Merge branch 'develop' into bugfix/workfiles-tool-shows-users-for-artists

This commit is contained in:
Jakub Trllo 2024-06-14 10:29:11 +02:00 committed by GitHub
commit 577a6873fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 84 additions and 37 deletions

View file

@ -14,9 +14,10 @@ from ayon_core.lib import (
convert_ffprobe_fps_value,
)
FFMPEG_EXE_COMMAND = subprocess.list2cmdline(get_ffmpeg_tool_args("ffmpeg"))
FFMPEG = (
'{}%(input_args)s -i "%(input)s" %(filters)s %(args)s%(output)s'
).format(subprocess.list2cmdline(get_ffmpeg_tool_args("ffmpeg")))
).format(FFMPEG_EXE_COMMAND)
DRAWTEXT = (
"drawtext@'%(label)s'=fontfile='%(font)s':text=\\'%(text)s\\':"
@ -482,10 +483,19 @@ class ModifiedBurnins(ffmpeg_burnins.Burnins):
)
print("Launching command: {}".format(command))
use_shell = True
try:
test_proc = subprocess.Popen(
f"{FFMPEG_EXE_COMMAND} --help", shell=True
)
test_proc.wait()
except BaseException:
use_shell = False
kwargs = {
"stdout": subprocess.PIPE,
"stderr": subprocess.PIPE,
"shell": True,
"shell": use_shell,
}
proc = subprocess.Popen(command, **kwargs)

View file

@ -834,12 +834,13 @@ class AbstractWorkfilesFrontend(AbstractWorkfilesCommon):
pass
@abstractmethod
def get_workarea_file_items(self, folder_id, task_id):
def get_workarea_file_items(self, folder_id, task_name, sender=None):
"""Get workarea file items.
Args:
folder_id (str): Folder id.
task_id (str): Task id.
task_name (str): Task name.
sender (Optional[str]): Who requested workarea file items.
Returns:
list[FileItem]: List of workarea file items.
@ -905,12 +906,12 @@ class AbstractWorkfilesFrontend(AbstractWorkfilesCommon):
pass
@abstractmethod
def get_workfile_info(self, folder_id, task_id, filepath):
def get_workfile_info(self, folder_id, task_name, filepath):
"""Workfile info from database.
Args:
folder_id (str): Folder id.
task_id (str): Task id.
task_name (str): Task id.
filepath (str): Workfile path.
Returns:
@ -921,7 +922,7 @@ class AbstractWorkfilesFrontend(AbstractWorkfilesCommon):
pass
@abstractmethod
def save_workfile_info(self, folder_id, task_id, filepath, note):
def save_workfile_info(self, folder_id, task_name, filepath, note):
"""Save workfile info to database.
At this moment the only information which can be saved about
@ -932,7 +933,7 @@ class AbstractWorkfilesFrontend(AbstractWorkfilesCommon):
Args:
folder_id (str): Folder id.
task_id (str): Task id.
task_name (str): Task id.
filepath (str): Workfile path.
note (Union[str, None]): Note.
"""

View file

@ -411,9 +411,11 @@ class BaseWorkfileController(
return self._workfiles_model.get_workarea_dir_by_context(
folder_id, task_id)
def get_workarea_file_items(self, folder_id, task_id):
def get_workarea_file_items(self, folder_id, task_name, sender=None):
task_id = self._get_task_id(folder_id, task_name)
return self._workfiles_model.get_workarea_file_items(
folder_id, task_id)
folder_id, task_id, task_name
)
def get_workarea_save_as_data(self, folder_id, task_id):
return self._workfiles_model.get_workarea_save_as_data(
@ -448,12 +450,14 @@ class BaseWorkfileController(
return self._workfiles_model.get_published_file_items(
folder_id, task_name)
def get_workfile_info(self, folder_id, task_id, filepath):
def get_workfile_info(self, folder_id, task_name, filepath):
task_id = self._get_task_id(folder_id, task_name)
return self._workfiles_model.get_workfile_info(
folder_id, task_id, filepath
)
def save_workfile_info(self, folder_id, task_id, filepath, note):
def save_workfile_info(self, folder_id, task_name, filepath, note):
task_id = self._get_task_id(folder_id, task_name)
self._workfiles_model.save_workfile_info(
folder_id, task_id, filepath, note
)
@ -628,6 +632,17 @@ class BaseWorkfileController(
def _emit_event(self, topic, data=None):
self.emit_event(topic, data, "controller")
def _get_task_id(self, folder_id, task_name, sender=None):
task_item = self._hierarchy_model.get_task_item_by_name(
self.get_current_project_name(),
folder_id,
task_name,
sender
)
if not task_item:
return None
return task_item.id
# Expected selection
# - expected selection is used to restore selection after refresh
# or when current context should be used
@ -723,7 +738,7 @@ class BaseWorkfileController(
self._host_save_workfile(dst_filepath)
# Make sure workfile info exists
self.save_workfile_info(folder_id, task_id, dst_filepath, None)
self.save_workfile_info(folder_id, task_name, dst_filepath, None)
# Create extra folders
create_workdir_extra_folders(

View file

@ -1,6 +1,7 @@
import os
import re
import copy
import uuid
import arrow
import ayon_api
@ -173,7 +174,7 @@ class WorkareaModel:
folder_mapping[task_id] = workdir
return workdir
def get_file_items(self, folder_id, task_id):
def get_file_items(self, folder_id, task_id, task_name):
items = []
if not folder_id or not task_id:
return items
@ -192,7 +193,7 @@ class WorkareaModel:
continue
workfile_info = self._controller.get_workfile_info(
folder_id, task_id, filepath
folder_id, task_name, filepath
)
modified = os.path.getmtime(filepath)
items.append(FileItem(
@ -587,6 +588,7 @@ class WorkfileEntitiesModel:
username = self._get_current_username()
workfile_info = {
"id": uuid.uuid4().hex,
"path": rootless_path,
"taskId": task_id,
"attrib": {
@ -770,19 +772,21 @@ class WorkfilesModel:
return self._workarea_model.get_workarea_dir_by_context(
folder_id, task_id)
def get_workarea_file_items(self, folder_id, task_id):
def get_workarea_file_items(self, folder_id, task_id, task_name):
"""Workfile items for passed context from workarea.
Args:
folder_id (Union[str, None]): Folder id.
task_id (Union[str, None]): Task id.
task_name (Union[str, None]): Task name.
Returns:
list[FileItem]: List of file items matching workarea of passed
context.
"""
return self._workarea_model.get_file_items(folder_id, task_id)
return self._workarea_model.get_file_items(
folder_id, task_id, task_name
)
def get_workarea_save_as_data(self, folder_id, task_id):
return self._workarea_model.get_workarea_save_as_data(

View file

@ -66,7 +66,7 @@ class WorkAreaFilesModel(QtGui.QStandardItemModel):
self._empty_item_used = False
self._published_mode = False
self._selected_folder_id = None
self._selected_task_id = None
self._selected_task_name = None
self._add_missing_context_item()
@ -153,7 +153,7 @@ class WorkAreaFilesModel(QtGui.QStandardItemModel):
def _on_task_changed(self, event):
self._selected_folder_id = event["folder_id"]
self._selected_task_id = event["task_id"]
self._selected_task_name = event["task_name"]
if not self._published_mode:
self._fill_items()
@ -179,13 +179,13 @@ class WorkAreaFilesModel(QtGui.QStandardItemModel):
def _fill_items_impl(self):
folder_id = self._selected_folder_id
task_id = self._selected_task_id
if not folder_id or not task_id:
task_name = self._selected_task_name
if not folder_id or not task_name:
self._add_missing_context_item()
return
file_items = self._controller.get_workarea_file_items(
folder_id, task_id
folder_id, task_name
)
root_item = self.invisibleRootItem()
if not file_items:

View file

@ -75,7 +75,7 @@ class SidePanelWidget(QtWidgets.QWidget):
self._btn_note_save = btn_note_save
self._folder_id = None
self._task_id = None
self._task_name = None
self._filepath = None
self._orig_note = ""
self._controller = controller
@ -93,10 +93,10 @@ class SidePanelWidget(QtWidgets.QWidget):
def _on_selection_change(self, event):
folder_id = event["folder_id"]
task_id = event["task_id"]
task_name = event["task_name"]
filepath = event["path"]
self._set_context(folder_id, task_id, filepath)
self._set_context(folder_id, task_name, filepath)
def _on_note_change(self):
text = self._note_input.toPlainText()
@ -106,19 +106,19 @@ class SidePanelWidget(QtWidgets.QWidget):
note = self._note_input.toPlainText()
self._controller.save_workfile_info(
self._folder_id,
self._task_id,
self._task_name,
self._filepath,
note
)
self._orig_note = note
self._btn_note_save.setEnabled(False)
def _set_context(self, folder_id, task_id, filepath):
def _set_context(self, folder_id, task_name, filepath):
workfile_info = None
# Check if folder, task and file are selected
if bool(folder_id) and bool(task_id) and bool(filepath):
if bool(folder_id) and bool(task_name) and bool(filepath):
workfile_info = self._controller.get_workfile_info(
folder_id, task_id, filepath
folder_id, task_name, filepath
)
enabled = workfile_info is not None
@ -127,7 +127,7 @@ class SidePanelWidget(QtWidgets.QWidget):
self._btn_note_save.setEnabled(enabled)
self._folder_id = folder_id
self._task_id = task_id
self._task_name = task_name
self._filepath = filepath
# Disable inputs and remove texts if any required arguments are

View file

@ -272,10 +272,8 @@ def reset_frame_range(fps: bool = True):
scene frame rate in frames-per-second.
"""
if fps:
task_entity = get_current_task_entity()
task_attributes = task_entity["attrib"]
fps_number = float(task_attributes["fps"])
rt.frameRate = fps_number
rt.frameRate = float(get_fps_for_current_context())
frame_range = get_frame_range()
set_timeline(
@ -284,6 +282,22 @@ def reset_frame_range(fps: bool = True):
frame_range["frameStartHandle"], frame_range["frameEndHandle"])
def get_fps_for_current_context():
"""Get fps that should be set for current context.
Todos:
- Skip project value.
- Merge logic with 'get_frame_range' and 'reset_scene_resolution' ->
all the values in the functions can be collected at one place as
they have same requirements.
Returns:
Union[int, float]: FPS value.
"""
task_entity = get_current_task_entity(fields={"attrib"})
return task_entity["attrib"]["fps"]
def reset_unit_scale():
"""Apply the unit scale setting to 3dsMax
"""
@ -358,7 +372,7 @@ def is_headless():
def set_timeline(frameStart, frameEnd):
"""Set frame range for timeline editor in Max
"""
rt.animationRange = rt.interval(frameStart, frameEnd)
rt.animationRange = rt.interval(int(frameStart), int(frameEnd))
return rt.animationRange

View file

@ -7,7 +7,7 @@ Because of limited api, alembics can be only loaded, but not easily updated.
import os
from ayon_core.pipeline import load, get_representation_path
from ayon_max.api import lib, maintained_selection
from ayon_max.api.lib import unique_namespace
from ayon_max.api.lib import unique_namespace, reset_frame_range
from ayon_max.api.pipeline import (
containerise,
get_previous_loaded_object,
@ -38,6 +38,9 @@ class AbcLoader(load.LoaderPlugin):
}
rt.AlembicImport.ImportToRoot = False
# TODO: it will be removed after the improvement
# on the post-system setup
reset_frame_range()
rt.importFile(file_path, rt.name("noPrompt"), using=rt.AlembicImport)
abc_after = {