mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
[Automated] Merged develop into main
This commit is contained in:
commit
c4eecfa88c
89 changed files with 541 additions and 263 deletions
|
|
@ -6,6 +6,8 @@ class AddLastWorkfileToLaunchArgs(PreLaunchHook):
|
|||
"""Add last workfile path to launch arguments.
|
||||
|
||||
This is not possible to do for all applications the same way.
|
||||
Checks 'start_last_workfile', if set to False, it will not open last
|
||||
workfile. This property is set explicitly in Launcher.
|
||||
"""
|
||||
|
||||
# Execute after workfile template copy
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ class GlobalHostDataHook(PreLaunchHook):
|
|||
|
||||
"env": self.launch_context.env,
|
||||
|
||||
"start_last_workfile": self.data.get("start_last_workfile"),
|
||||
"last_workfile_path": self.data.get("last_workfile_path"),
|
||||
|
||||
"log": self.log
|
||||
|
|
|
|||
|
|
@ -40,7 +40,10 @@ class NonPythonHostHook(PreLaunchHook):
|
|||
)
|
||||
# Add workfile path if exists
|
||||
workfile_path = self.data["last_workfile_path"]
|
||||
if os.path.exists(workfile_path):
|
||||
if (
|
||||
self.data.get("start_last_workfile")
|
||||
and workfile_path
|
||||
and os.path.exists(workfile_path)):
|
||||
new_launch_args.append(workfile_path)
|
||||
|
||||
# Append as whole list as these areguments should not be separated
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class ExtractSubsetResources(openpype.api.Extractor):
|
|||
staging_dir = self.staging_dir(instance)
|
||||
|
||||
# add default preset type for thumbnail and reviewable video
|
||||
# update them with settings and overide in case the same
|
||||
# update them with settings and override in case the same
|
||||
# are found in there
|
||||
export_presets = deepcopy(self.default_presets)
|
||||
export_presets.update(self.export_presets_mapping)
|
||||
|
|
|
|||
|
|
@ -218,12 +218,10 @@ def on_task_changed(*args):
|
|||
)
|
||||
|
||||
|
||||
def before_workfile_save(workfile_path):
|
||||
if not workfile_path:
|
||||
return
|
||||
|
||||
workdir = os.path.dirname(workfile_path)
|
||||
copy_workspace_mel(workdir)
|
||||
def before_workfile_save(event):
|
||||
workdir_path = event.workdir_path
|
||||
if workdir_path:
|
||||
copy_workspace_mel(workdir_path)
|
||||
|
||||
|
||||
class MayaDirmap(HostDirmap):
|
||||
|
|
|
|||
|
|
@ -1490,6 +1490,7 @@ def _prepare_last_workfile(data, workdir):
|
|||
import avalon.api
|
||||
|
||||
log = data["log"]
|
||||
|
||||
_workdir_data = data.get("workdir_data")
|
||||
if not _workdir_data:
|
||||
log.info(
|
||||
|
|
@ -1503,9 +1504,15 @@ def _prepare_last_workfile(data, workdir):
|
|||
project_name = data["project_name"]
|
||||
task_name = data["task_name"]
|
||||
task_type = data["task_type"]
|
||||
start_last_workfile = should_start_last_workfile(
|
||||
project_name, app.host_name, task_name, task_type
|
||||
)
|
||||
|
||||
start_last_workfile = data.get("start_last_workfile")
|
||||
if start_last_workfile is None:
|
||||
start_last_workfile = should_start_last_workfile(
|
||||
project_name, app.host_name, task_name, task_type
|
||||
)
|
||||
else:
|
||||
log.info("Opening of last workfile was disabled by user")
|
||||
|
||||
data["start_last_workfile"] = start_last_workfile
|
||||
|
||||
workfile_startup = should_workfile_tool_start(
|
||||
|
|
|
|||
|
|
@ -34,11 +34,17 @@ def get_vendor_bin_path(bin_app):
|
|||
def get_oiio_tools_path(tool="oiiotool"):
|
||||
"""Path to vendorized OpenImageIO tool executables.
|
||||
|
||||
On Window it adds .exe extension if missing from tool argument.
|
||||
|
||||
Args:
|
||||
tool (string): Tool name (oiiotool, maketx, ...).
|
||||
Default is "oiiotool".
|
||||
"""
|
||||
oiio_dir = get_vendor_bin_path("oiio")
|
||||
if platform.system().lower() == "windows" and not tool.lower().endswith(
|
||||
".exe"
|
||||
):
|
||||
tool = "{}.exe".format(tool)
|
||||
return os.path.join(oiio_dir, tool)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ class ProcessEventHub(SocketBaseEventHub):
|
|||
sys.exit(0)
|
||||
|
||||
def wait(self, duration=None):
|
||||
"""Overriden wait
|
||||
"""Overridden wait
|
||||
Event are loaded from Mongo DB when queue is empty. Handled event is
|
||||
set as processed in Mongo DB.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ class DropboxHandler(AbstractProvider):
|
|||
"key": "acting_as_member",
|
||||
"label": "Acting As Member"
|
||||
},
|
||||
# roots could be overriden only on Project level, User cannot
|
||||
# roots could be overridden only on Project level, User cannot
|
||||
{
|
||||
"key": "root",
|
||||
"label": "Roots",
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ class GDriveHandler(AbstractProvider):
|
|||
# {platform} tells that value is multiplatform and only specific OS
|
||||
# should be returned
|
||||
editable = [
|
||||
# credentials could be overriden on Project or User level
|
||||
# credentials could be overridden on Project or User level
|
||||
{
|
||||
"type": "path",
|
||||
"key": "credentials_url",
|
||||
|
|
@ -127,7 +127,7 @@ class GDriveHandler(AbstractProvider):
|
|||
"multiplatform": True,
|
||||
"placeholder": "Credentials url"
|
||||
},
|
||||
# roots could be overriden only on Project leve, User cannot
|
||||
# roots could be overridden only on Project level, User cannot
|
||||
{
|
||||
"key": "root",
|
||||
"label": "Roots",
|
||||
|
|
@ -414,7 +414,7 @@ class GDriveHandler(AbstractProvider):
|
|||
def delete_folder(self, path, force=False):
|
||||
"""
|
||||
Deletes folder on GDrive. Checks if folder contains any files or
|
||||
subfolders. In that case raises error, could be overriden by
|
||||
subfolders. In that case raises error, could be overridden by
|
||||
'force' argument.
|
||||
In that case deletes folder on 'path' and all its children.
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class SFTPHandler(AbstractProvider):
|
|||
# {platform} tells that value is multiplatform and only specific OS
|
||||
# should be returned
|
||||
editable = [
|
||||
# credentials could be overriden on Project or User level
|
||||
# credentials could be overridden on Project or User level
|
||||
{
|
||||
'key': "sftp_host",
|
||||
'label': "SFTP host name",
|
||||
|
|
@ -129,7 +129,7 @@ class SFTPHandler(AbstractProvider):
|
|||
'label': "SFTP user ssh key password",
|
||||
'type': 'text'
|
||||
},
|
||||
# roots could be overriden only on Project leve, User cannot
|
||||
# roots could be overridden only on Project level, User cannot
|
||||
{
|
||||
"key": "root",
|
||||
"label": "Roots",
|
||||
|
|
|
|||
|
|
@ -1073,7 +1073,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule):
|
|||
"""
|
||||
Returns settings for 'studio' and user's local site
|
||||
|
||||
Returns base values from setting, not overriden by Local Settings,
|
||||
Returns base values from setting, not overridden by Local Settings,
|
||||
eg. value used to push TO LS not to get actual value for syncing.
|
||||
"""
|
||||
if not project_name:
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ class ITrayAction(ITrayModule):
|
|||
Add action to tray menu which will trigger `on_action_trigger`.
|
||||
It is expected to be used for showing tools.
|
||||
|
||||
Methods `tray_start`, `tray_exit` and `connect_with_modules` are overriden
|
||||
Methods `tray_start`, `tray_exit` and `connect_with_modules` are overridden
|
||||
as it's not expected that action will use them. But it is possible if
|
||||
necessary.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class WorkerRpc(JsonRpc):
|
|||
self._job_queue.remove_worker(worker)
|
||||
|
||||
async def handle_websocket_request(self, http_request):
|
||||
"""Overide this method to catch CLOSING messages."""
|
||||
"""Override this method to catch CLOSING messages."""
|
||||
http_request.msg_id = 0
|
||||
http_request.pending = {}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
from .events import (
|
||||
BaseEvent,
|
||||
BeforeWorkfileSave
|
||||
)
|
||||
|
||||
from .attribute_definitions import (
|
||||
AbtractAttrDef,
|
||||
UnknownDef,
|
||||
|
|
@ -9,6 +14,9 @@ from .attribute_definitions import (
|
|||
|
||||
|
||||
__all__ = (
|
||||
"BaseEvent",
|
||||
"BeforeWorkfileSave",
|
||||
|
||||
"AbtractAttrDef",
|
||||
"UnknownDef",
|
||||
"NumberDef",
|
||||
|
|
|
|||
51
openpype/pipeline/lib/events.py
Normal file
51
openpype/pipeline/lib/events.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
"""Events holding data about specific event."""
|
||||
|
||||
|
||||
# Inherit from 'object' for Python 2 hosts
|
||||
class BaseEvent(object):
|
||||
"""Base event object.
|
||||
|
||||
Can be used to anything because data are not much specific. Only required
|
||||
argument is topic which defines why event is happening and may be used for
|
||||
filtering.
|
||||
|
||||
Arg:
|
||||
topic (str): Identifier of event.
|
||||
data (Any): Data specific for event. Dictionary is recommended.
|
||||
"""
|
||||
_data = {}
|
||||
|
||||
def __init__(self, topic, data=None):
|
||||
self._topic = topic
|
||||
if data is None:
|
||||
data = {}
|
||||
self._data = data
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self._data
|
||||
|
||||
@property
|
||||
def topic(self):
|
||||
return self._topic
|
||||
|
||||
@classmethod
|
||||
def emit(cls, *args, **kwargs):
|
||||
"""Create object of event and emit.
|
||||
|
||||
Args:
|
||||
Same args as '__init__' expects which may be class specific.
|
||||
"""
|
||||
from avalon import pipeline
|
||||
|
||||
obj = cls(*args, **kwargs)
|
||||
pipeline.emit(obj.topic, [obj])
|
||||
return obj
|
||||
|
||||
|
||||
class BeforeWorkfileSave(BaseEvent):
|
||||
"""Before workfile changes event data."""
|
||||
def __init__(self, filename, workdir):
|
||||
super(BeforeWorkfileSave, self).__init__("before.workfile.save")
|
||||
self.filename = filename
|
||||
self.workdir_path = workdir
|
||||
|
|
@ -31,7 +31,7 @@ class DiscoverResult:
|
|||
def publish_plugins_discover(paths=None):
|
||||
"""Find and return available pyblish plug-ins
|
||||
|
||||
Overriden function from `pyblish` module to be able collect crashed files
|
||||
Overridden function from `pyblish` module to be able collect crashed files
|
||||
and reason of their crash.
|
||||
|
||||
Arguments:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ class CollectSceneVersion(pyblish.api.ContextPlugin):
|
|||
|
||||
order = pyblish.api.CollectorOrder
|
||||
label = 'Collect Scene Version'
|
||||
# configurable in Settings
|
||||
hosts = [
|
||||
"aftereffects",
|
||||
"blender",
|
||||
|
|
@ -26,7 +27,19 @@ class CollectSceneVersion(pyblish.api.ContextPlugin):
|
|||
"tvpaint"
|
||||
]
|
||||
|
||||
# in some cases of headless publishing (for example webpublisher using PS)
|
||||
# you want to ignore version from name and let integrate use next version
|
||||
skip_hosts_headless_publish = []
|
||||
|
||||
def process(self, context):
|
||||
# tests should be close to regular publish as possible
|
||||
if (
|
||||
os.environ.get("HEADLESS_PUBLISH")
|
||||
and not os.environ.get("IS_TEST")
|
||||
and context.data["hostName"] in self.skip_hosts_headless_publish):
|
||||
self.log.debug("Skipping for headless publishing")
|
||||
return
|
||||
|
||||
assert context.data.get('currentFile'), "Cannot get current file"
|
||||
filename = os.path.basename(context.data.get('currentFile'))
|
||||
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ class ModifiedBurnins(ffmpeg_burnins.Burnins):
|
|||
- required IF start frame is not set when using frames or timecode burnins
|
||||
|
||||
On initializing class can be set General options through "options_init" arg.
|
||||
General can be overriden when adding burnin
|
||||
General can be overridden when adding burnin
|
||||
|
||||
'''
|
||||
TOP_CENTERED = ffmpeg_burnins.TOP_CENTERED
|
||||
|
|
@ -549,7 +549,7 @@ def burnins_from_data(
|
|||
codec_data (list): All codec related arguments in list.
|
||||
options (dict): Options for burnins.
|
||||
burnin_values (dict): Contain positioned values.
|
||||
overwrite (bool): Output will be overriden if already exists,
|
||||
overwrite (bool): Output will be overwritten if already exists,
|
||||
True by default.
|
||||
|
||||
Presets must be set separately. Should be dict with 2 keys:
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ import re
|
|||
|
||||
|
||||
# Metadata keys for work with studio and project overrides
|
||||
M_OVERRIDEN_KEY = "__overriden_keys__"
|
||||
M_OVERRIDDEN_KEY = "__overriden_keys__"
|
||||
# Metadata key for storing information about environments
|
||||
M_ENVIRONMENT_KEY = "__environment_keys__"
|
||||
# Metadata key for storing dynamic created labels
|
||||
M_DYNAMIC_KEY_LABEL = "__dynamic_keys_labels__"
|
||||
|
||||
METADATA_KEYS = (
|
||||
M_OVERRIDEN_KEY,
|
||||
M_OVERRIDDEN_KEY,
|
||||
M_ENVIRONMENT_KEY,
|
||||
M_DYNAMIC_KEY_LABEL
|
||||
)
|
||||
|
|
@ -32,7 +32,7 @@ KEY_REGEX = re.compile(r"^[{}]+$".format(KEY_ALLOWED_SYMBOLS))
|
|||
|
||||
|
||||
__all__ = (
|
||||
"M_OVERRIDEN_KEY",
|
||||
"M_OVERRIDDEN_KEY",
|
||||
"M_ENVIRONMENT_KEY",
|
||||
"M_DYNAMIC_KEY_LABEL",
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,24 @@
|
|||
"CollectAnatomyInstanceData": {
|
||||
"follow_workfile_version": false
|
||||
},
|
||||
"CollectSceneVersion": {
|
||||
"hosts": [
|
||||
"aftereffects",
|
||||
"blender",
|
||||
"celaction",
|
||||
"fusion",
|
||||
"harmony",
|
||||
"hiero",
|
||||
"houdini",
|
||||
"maya",
|
||||
"nuke",
|
||||
"photoshop",
|
||||
"resolve",
|
||||
"tvpaint"
|
||||
],
|
||||
"skip_hosts_headless_publish": [
|
||||
]
|
||||
},
|
||||
"ValidateEditorialAssetName": {
|
||||
"enabled": true,
|
||||
"optional": false
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
{
|
||||
"color_code": [],
|
||||
"layer_name_regex": [],
|
||||
"family": "",
|
||||
"family": "image",
|
||||
"subset_template_name": ""
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -752,7 +752,7 @@ class BaseItemEntity(BaseEntity):
|
|||
|
||||
@abstractmethod
|
||||
def _add_to_project_override(self, on_change_trigger):
|
||||
"""Item's implementation to set values as overriden for project.
|
||||
"""Item's implementation to set values as overridden for project.
|
||||
|
||||
Mark item and all it's children to be stored as project overrides.
|
||||
"""
|
||||
|
|
@ -794,7 +794,7 @@ class BaseItemEntity(BaseEntity):
|
|||
"""Item's implementation to remove project overrides.
|
||||
|
||||
Mark item as does not have project overrides. Must not change
|
||||
`was_overriden` attribute value.
|
||||
`was_overridden` attribute value.
|
||||
|
||||
Args:
|
||||
on_change_trigger (list): Callbacks of `on_change` should be stored
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from .lib import (
|
|||
)
|
||||
from openpype.settings.constants import (
|
||||
METADATA_KEYS,
|
||||
M_OVERRIDEN_KEY,
|
||||
M_OVERRIDDEN_KEY,
|
||||
KEY_REGEX
|
||||
)
|
||||
from . import (
|
||||
|
|
@ -119,7 +119,7 @@ class DictConditionalEntity(ItemEntity):
|
|||
|
||||
# `current_metadata` are still when schema is loaded
|
||||
# - only metadata stored with dict item are gorup overrides in
|
||||
# M_OVERRIDEN_KEY
|
||||
# M_OVERRIDDEN_KEY
|
||||
self._current_metadata = {}
|
||||
self._metadata_are_modified = False
|
||||
|
||||
|
|
@ -377,9 +377,9 @@ class DictConditionalEntity(ItemEntity):
|
|||
):
|
||||
continue
|
||||
|
||||
if M_OVERRIDEN_KEY not in current_metadata:
|
||||
current_metadata[M_OVERRIDEN_KEY] = []
|
||||
current_metadata[M_OVERRIDEN_KEY].append(key)
|
||||
if M_OVERRIDDEN_KEY not in current_metadata:
|
||||
current_metadata[M_OVERRIDDEN_KEY] = []
|
||||
current_metadata[M_OVERRIDDEN_KEY].append(key)
|
||||
|
||||
# Define if current metadata are avaialble for current override state
|
||||
metadata = NOT_SET
|
||||
|
|
@ -535,7 +535,7 @@ class DictConditionalEntity(ItemEntity):
|
|||
|
||||
enum_value = value.get(self.enum_key)
|
||||
|
||||
old_metadata = metadata.get(M_OVERRIDEN_KEY)
|
||||
old_metadata = metadata.get(M_OVERRIDDEN_KEY)
|
||||
if old_metadata:
|
||||
old_metadata_set = set(old_metadata)
|
||||
new_metadata = []
|
||||
|
|
@ -547,7 +547,7 @@ class DictConditionalEntity(ItemEntity):
|
|||
|
||||
for key in old_metadata_set:
|
||||
new_metadata.append(key)
|
||||
metadata[M_OVERRIDEN_KEY] = new_metadata
|
||||
metadata[M_OVERRIDDEN_KEY] = new_metadata
|
||||
|
||||
return value, metadata
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from .lib import (
|
|||
)
|
||||
from openpype.settings.constants import (
|
||||
METADATA_KEYS,
|
||||
M_OVERRIDEN_KEY,
|
||||
M_OVERRIDDEN_KEY,
|
||||
KEY_REGEX
|
||||
)
|
||||
from . import (
|
||||
|
|
@ -183,7 +183,7 @@ class DictImmutableKeysEntity(ItemEntity):
|
|||
|
||||
# `current_metadata` are still when schema is loaded
|
||||
# - only metadata stored with dict item are gorup overrides in
|
||||
# M_OVERRIDEN_KEY
|
||||
# M_OVERRIDDEN_KEY
|
||||
self._current_metadata = {}
|
||||
self._metadata_are_modified = False
|
||||
|
||||
|
|
@ -257,9 +257,9 @@ class DictImmutableKeysEntity(ItemEntity):
|
|||
):
|
||||
continue
|
||||
|
||||
if M_OVERRIDEN_KEY not in current_metadata:
|
||||
current_metadata[M_OVERRIDEN_KEY] = []
|
||||
current_metadata[M_OVERRIDEN_KEY].append(key)
|
||||
if M_OVERRIDDEN_KEY not in current_metadata:
|
||||
current_metadata[M_OVERRIDDEN_KEY] = []
|
||||
current_metadata[M_OVERRIDDEN_KEY].append(key)
|
||||
|
||||
# Define if current metadata are avaialble for current override state
|
||||
metadata = NOT_SET
|
||||
|
|
@ -399,7 +399,7 @@ class DictImmutableKeysEntity(ItemEntity):
|
|||
if key in value:
|
||||
metadata[key] = value.pop(key)
|
||||
|
||||
old_metadata = metadata.get(M_OVERRIDEN_KEY)
|
||||
old_metadata = metadata.get(M_OVERRIDDEN_KEY)
|
||||
if old_metadata:
|
||||
old_metadata_set = set(old_metadata)
|
||||
new_metadata = []
|
||||
|
|
@ -410,7 +410,7 @@ class DictImmutableKeysEntity(ItemEntity):
|
|||
|
||||
for key in old_metadata_set:
|
||||
new_metadata.append(key)
|
||||
metadata[M_OVERRIDEN_KEY] = new_metadata
|
||||
metadata[M_OVERRIDDEN_KEY] = new_metadata
|
||||
|
||||
return value, metadata
|
||||
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ class DictMutableKeysEntity(EndpointEntity):
|
|||
self.required_keys = self.schema_data.get("required_keys") or []
|
||||
self.collapsible_key = self.schema_data.get("collapsible_key") or False
|
||||
# GUI attributes
|
||||
self.hightlight_content = (
|
||||
self.highlight_content = (
|
||||
self.schema_data.get("highlight_content") or False
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -121,6 +121,20 @@ class EnumEntity(BaseEnumEntity):
|
|||
)
|
||||
super(EnumEntity, self).schema_validations()
|
||||
|
||||
def set_override_state(self, *args, **kwargs):
|
||||
super(EnumEntity, self).set_override_state(*args, **kwargs)
|
||||
|
||||
# Make sure current value is valid
|
||||
if self.multiselection:
|
||||
new_value = []
|
||||
for key in self._current_value:
|
||||
if key in self.valid_keys:
|
||||
new_value.append(key)
|
||||
self._current_value = new_value
|
||||
|
||||
elif self._current_value not in self.valid_keys:
|
||||
self._current_value = self.value_on_not_set
|
||||
|
||||
|
||||
class HostsEnumEntity(BaseEnumEntity):
|
||||
"""Enumeration of host names.
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class OverrideState:
|
|||
- DEFAULTS - Entity cares only about default values. It is not
|
||||
possible to set higher state if any entity does not have filled
|
||||
default value.
|
||||
- STUDIO - First layer of overrides. Hold only studio overriden values
|
||||
- STUDIO - First layer of overrides. Hold only studio overridden values
|
||||
that are applied on top of defaults.
|
||||
- PROJECT - Second layer of overrides. Hold only project overrides that are
|
||||
applied on top of defaults and studio overrides.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
- `"is_file"` - this key is for storing openpype defaults in `openpype` repo
|
||||
- reasons of existence: developing new schemas does not require to create defaults manually
|
||||
- key is validated, must be once in hierarchy else it won't be possible to store openpype defaults
|
||||
- `"is_group"` - define that all values under key in hierarchy will be overriden if any value is modified, this information is also stored to overrides
|
||||
- `"is_group"` - define that all values under key in hierarchy will be overridden if any value is modified, this information is also stored to overrides
|
||||
- this keys is not allowed for all inputs as they may have not reason for that
|
||||
- key is validated, can be only once in hierarchy but is not required
|
||||
- currently there are `system settings` and `project settings`
|
||||
|
|
@ -767,7 +767,7 @@ Anatomy represents data stored on project document.
|
|||
|
||||
### anatomy
|
||||
- entity works similarly to `dict`
|
||||
- anatomy has always all keys overriden with overrides
|
||||
- anatomy has always all keys overridden with overrides
|
||||
- overrides are not applied as all anatomy data must be available from project document
|
||||
- all children must be groups
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,27 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
"key": "CollectSceneVersion",
|
||||
"label": "Collect Version from Workfile",
|
||||
"is_group": true,
|
||||
"children": [
|
||||
{
|
||||
"key": "hosts",
|
||||
"label": "Host names",
|
||||
"type": "hosts-enum",
|
||||
"multiselection": true
|
||||
},
|
||||
{
|
||||
"key": "skip_hosts_headless_publish",
|
||||
"label": "Skip for host if headless publish",
|
||||
"type": "hosts-enum",
|
||||
"multiselection": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dict",
|
||||
"collapsible": true,
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@
|
|||
},
|
||||
{
|
||||
"type": "dict-conditional",
|
||||
"key": "overriden_value",
|
||||
"label": "Overriden value",
|
||||
"enum_key": "overriden",
|
||||
"key": "overridden_value",
|
||||
"label": "Overridden value",
|
||||
"enum_key": "overridden",
|
||||
"enum_is_horizontal": true,
|
||||
"enum_children": [
|
||||
{
|
||||
"key": "overriden",
|
||||
"key": "overridden",
|
||||
"label": "Override value",
|
||||
"children": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from .constants import (
|
|||
PROJECT_SETTINGS_KEY,
|
||||
PROJECT_ANATOMY_KEY,
|
||||
LOCAL_SETTING_KEY,
|
||||
M_OVERRIDEN_KEY
|
||||
M_OVERRIDDEN_KEY
|
||||
)
|
||||
from .lib import load_json_file
|
||||
|
||||
|
|
@ -254,12 +254,12 @@ class MongoSettingsHandler(SettingsHandler):
|
|||
continue
|
||||
# Pop key from values
|
||||
output[key] = general_data.pop(key)
|
||||
# Pop key from overriden metadata
|
||||
# Pop key from overridden metadata
|
||||
if (
|
||||
M_OVERRIDEN_KEY in general_data
|
||||
and key in general_data[M_OVERRIDEN_KEY]
|
||||
M_OVERRIDDEN_KEY in general_data
|
||||
and key in general_data[M_OVERRIDDEN_KEY]
|
||||
):
|
||||
general_data[M_OVERRIDEN_KEY].remove(key)
|
||||
general_data[M_OVERRIDDEN_KEY].remove(key)
|
||||
return output
|
||||
|
||||
def _apply_global_settings(
|
||||
|
|
@ -319,17 +319,17 @@ class MongoSettingsHandler(SettingsHandler):
|
|||
system_general = {}
|
||||
system_settings_data["general"] = system_general
|
||||
|
||||
overriden_keys = system_general.get(M_OVERRIDEN_KEY) or []
|
||||
overridden_keys = system_general.get(M_OVERRIDDEN_KEY) or []
|
||||
for key in self.global_general_keys:
|
||||
if key not in globals_data:
|
||||
continue
|
||||
|
||||
system_general[key] = globals_data[key]
|
||||
if key not in overriden_keys:
|
||||
overriden_keys.append(key)
|
||||
if key not in overridden_keys:
|
||||
overridden_keys.append(key)
|
||||
|
||||
if overriden_keys:
|
||||
system_general[M_OVERRIDEN_KEY] = overriden_keys
|
||||
if overridden_keys:
|
||||
system_general[M_OVERRIDDEN_KEY] = overridden_keys
|
||||
|
||||
return system_settings_document
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from .exceptions import (
|
|||
SaveWarningExc
|
||||
)
|
||||
from .constants import (
|
||||
M_OVERRIDEN_KEY,
|
||||
M_OVERRIDDEN_KEY,
|
||||
M_ENVIRONMENT_KEY,
|
||||
|
||||
METADATA_KEYS,
|
||||
|
|
@ -546,13 +546,13 @@ def subkey_merge(_dict, value, keys):
|
|||
def merge_overrides(source_dict, override_dict):
|
||||
"""Merge data from override_dict to source_dict."""
|
||||
|
||||
if M_OVERRIDEN_KEY in override_dict:
|
||||
overriden_keys = set(override_dict.pop(M_OVERRIDEN_KEY))
|
||||
if M_OVERRIDDEN_KEY in override_dict:
|
||||
overridden_keys = set(override_dict.pop(M_OVERRIDDEN_KEY))
|
||||
else:
|
||||
overriden_keys = set()
|
||||
overridden_keys = set()
|
||||
|
||||
for key, value in override_dict.items():
|
||||
if (key in overriden_keys or key not in source_dict):
|
||||
if (key in overridden_keys or key not in source_dict):
|
||||
source_dict[key] = value
|
||||
|
||||
elif isinstance(value, dict) and isinstance(source_dict[key], dict):
|
||||
|
|
@ -574,7 +574,7 @@ def apply_local_settings_on_system_settings(system_settings, local_settings):
|
|||
"""Apply local settings on studio system settings.
|
||||
|
||||
ATM local settings can modify only application executables. Executable
|
||||
values are not overriden but prepended.
|
||||
values are not overridden but prepended.
|
||||
"""
|
||||
if not local_settings or "applications" not in local_settings:
|
||||
return
|
||||
|
|
@ -914,7 +914,7 @@ def get_environments():
|
|||
"""Calculated environment based on defaults and system settings.
|
||||
|
||||
Any default environment also found in the system settings will be fully
|
||||
overriden by the one from the system settings.
|
||||
overridden by the one from the system settings.
|
||||
|
||||
Returns:
|
||||
dict: Output should be ready for `acre` module.
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@
|
|||
"breadcrumbs-btn-bg": "rgba(127, 127, 127, 60)",
|
||||
"breadcrumbs-btn-bg-hover": "rgba(127, 127, 127, 90)",
|
||||
|
||||
"content-hightlighted": "rgba(19, 26, 32, 15)",
|
||||
"content-highlighted": "rgba(19, 26, 32, 15)",
|
||||
"focus-border": "#839caf",
|
||||
"image-btn": "#bfccd6",
|
||||
"image-btn-hover": "#189aea",
|
||||
|
|
|
|||
|
|
@ -1093,16 +1093,16 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
|
|||
#ExpandLabel[state="modified"]:hover, #SettingsLabel[state="modified"]:hover {
|
||||
color: {color:settings:modified-light};
|
||||
}
|
||||
#ExpandLabel[state="overriden-modified"], #SettingsLabel[state="overriden-modified"] {
|
||||
#ExpandLabel[state="overridden-modified"], #SettingsLabel[state="overridden-modified"] {
|
||||
color: {color:settings:modified-mid};
|
||||
}
|
||||
#ExpandLabel[state="overriden-modified"]:hover, #SettingsLabel[state="overriden-modified"]:hover {
|
||||
#ExpandLabel[state="overridden-modified"]:hover, #SettingsLabel[state="overridden-modified"]:hover {
|
||||
color: {color:settings:modified-light};
|
||||
}
|
||||
#ExpandLabel[state="overriden"], #SettingsLabel[state="overriden"] {
|
||||
#ExpandLabel[state="overridden"], #SettingsLabel[state="overridden"] {
|
||||
color: {color:settings:project-mid};
|
||||
}
|
||||
#ExpandLabel[state="overriden"]:hover, #SettingsLabel[state="overriden"]:hover {
|
||||
#ExpandLabel[state="overridden"]:hover, #SettingsLabel[state="overridden"]:hover {
|
||||
color: {color:settings:project-light};
|
||||
}
|
||||
#ExpandLabel[state="invalid"], #SettingsLabel[state="invalid"] {
|
||||
|
|
@ -1116,10 +1116,10 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
|
|||
#SettingsMainWidget QWidget[input-state="modified"] {
|
||||
border-color: {color:settings:modified-mid};
|
||||
}
|
||||
#SettingsMainWidget QWidget[input-state="overriden-modified"] {
|
||||
#SettingsMainWidget QWidget[input-state="overridden-modified"] {
|
||||
border-color: {color:settings:modified-mid};
|
||||
}
|
||||
#SettingsMainWidget QWidget[input-state="overriden"] {
|
||||
#SettingsMainWidget QWidget[input-state="overridden"] {
|
||||
border-color: {color:settings:project-mid};
|
||||
}
|
||||
#SettingsMainWidget QWidget[input-state="invalid"] {
|
||||
|
|
@ -1145,8 +1145,8 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
|
|||
#ContentWidget {
|
||||
background-color: transparent;
|
||||
}
|
||||
#ContentWidget[content_state="hightlighted"] {
|
||||
background-color: {color:settings:content-hightlighted};
|
||||
#ContentWidget[content_state="highlighted"] {
|
||||
background-color: {color:settings:content-highlighted};
|
||||
}
|
||||
|
||||
#SideLineWidget {
|
||||
|
|
@ -1172,11 +1172,11 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
|
|||
#SideLineWidget[state="child-invalid"] {border-color: {color:settings:invalid-dark};}
|
||||
#SideLineWidget[state="child-invalid"]:hover {border-color: {color:settings:invalid-light};}
|
||||
|
||||
#SideLineWidget[state="child-overriden"] {border-color: {color:settings:project-dark};}
|
||||
#SideLineWidget[state="child-overriden"]:hover {border-color: {color:settings:project-mid};}
|
||||
#SideLineWidget[state="child-overridden"] {border-color: {color:settings:project-dark};}
|
||||
#SideLineWidget[state="child-overridden"]:hover {border-color: {color:settings:project-mid};}
|
||||
|
||||
#SideLineWidget[state="child-overriden-modified"] {border-color: {color:settings:modified-dark};}
|
||||
#SideLineWidget[state="child-overriden-modified"]:hover {border-color: {color:settings:modified-mid};}
|
||||
#SideLineWidget[state="child-overridden-modified"] {border-color: {color:settings:modified-dark};}
|
||||
#SideLineWidget[state="child-overridden-modified"]:hover {border-color: {color:settings:modified-mid};}
|
||||
|
||||
#DictAsWidgetBody {
|
||||
background: transparent;
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ def test_avalon_plugin_presets(monkeypatch, printer):
|
|||
assert MyTestCreator in plugins
|
||||
for p in plugins:
|
||||
if p.__name__ == "MyTestCreator":
|
||||
printer("Test if we have overriden existing property")
|
||||
printer("Test if we have overridden existing property")
|
||||
assert p.my_test_property == "B"
|
||||
printer("Test if we have overriden superclass property")
|
||||
printer("Test if we have overridden superclass property")
|
||||
assert p.active is False
|
||||
printer("Test if we have added new property")
|
||||
assert p.new_property == "new"
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ class Window(QtWidgets.QDialog):
|
|||
btn_layout = QtWidgets.QHBoxLayout(btns_widget)
|
||||
btn_create_asset = QtWidgets.QPushButton("Create asset")
|
||||
btn_create_asset.setToolTip(
|
||||
"Creates all neccessary components for asset"
|
||||
"Creates all necessary components for asset"
|
||||
)
|
||||
checkbox_app = None
|
||||
if self.context is not None:
|
||||
|
|
@ -231,7 +231,7 @@ class Window(QtWidgets.QDialog):
|
|||
test_name = name.replace(' ', '')
|
||||
error_message = None
|
||||
message = QtWidgets.QMessageBox(self)
|
||||
message.setWindowTitle("Some errors has occured")
|
||||
message.setWindowTitle("Some errors have occurred")
|
||||
message.setIcon(QtWidgets.QMessageBox.Critical)
|
||||
# TODO: show error messages on any error
|
||||
if self.valid_parent is not True and test_name == '':
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ def preserve_expanded_rows(tree_view,
|
|||
|
||||
This function is created to maintain the expand vs collapse status of
|
||||
the model items. When refresh is triggered the items which are expanded
|
||||
will stay expanded and vise versa.
|
||||
will stay expanded and vice versa.
|
||||
|
||||
Arguments:
|
||||
tree_view (QWidgets.QTreeView): the tree view which is
|
||||
|
|
@ -94,7 +94,7 @@ def preserve_selection(tree_view,
|
|||
|
||||
This function is created to maintain the selection status of
|
||||
the model items. When refresh is triggered the items which are expanded
|
||||
will stay expanded and vise versa.
|
||||
will stay expanded and vice versa.
|
||||
|
||||
tree_view (QWidgets.QTreeView): the tree view nested in the application
|
||||
column (int): the column to retrieve the data from
|
||||
|
|
@ -179,7 +179,7 @@ class AssetModel(TreeModel):
|
|||
"""
|
||||
if silos:
|
||||
# WARNING: Silo item "_id" is set to silo value
|
||||
# mainly because GUI issue with perserve selection and expanded row
|
||||
# mainly because GUI issue with preserve selection and expanded row
|
||||
# and because of easier hierarchy parenting (in "assets")
|
||||
for silo in silos:
|
||||
item = Item({
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class ContextDialog(QtWidgets.QDialog):
|
|||
# UI initialization
|
||||
main_splitter = QtWidgets.QSplitter(self)
|
||||
|
||||
# Left side widget containt project combobox and asset widget
|
||||
# Left side widget contains project combobox and asset widget
|
||||
left_side_widget = QtWidgets.QWidget(main_splitter)
|
||||
|
||||
project_combobox = QtWidgets.QComboBox(left_side_widget)
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ class CreatorWindow(QtWidgets.QDialog):
|
|||
|
||||
Override keyPressEvent to do nothing so that Maya's panels won't
|
||||
take focus when pressing "SHIFT" whilst mouse is over viewport or
|
||||
outliner. This way users don't accidently perform Maya commands
|
||||
outliner. This way users don't accidentally perform Maya commands
|
||||
whilst trying to name an instance.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class ExperimentalToolsDialog(QtWidgets.QDialog):
|
|||
|
||||
# Is dialog first shown
|
||||
self._first_show = True
|
||||
# Trigger refresh when window get's activity
|
||||
# Trigger refresh when window gets activity
|
||||
self._refresh_on_active = True
|
||||
# Is window active
|
||||
self._window_is_active = False
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class ExperimentalTool:
|
|||
self._enabled = enabled
|
||||
|
||||
def execute(self):
|
||||
"""Trigger registerd callback."""
|
||||
"""Trigger registered callback."""
|
||||
self.callback()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ class ApplicationAction(api.Action):
|
|||
icon = None
|
||||
color = None
|
||||
order = 0
|
||||
data = {}
|
||||
|
||||
_log = None
|
||||
required_session_keys = (
|
||||
|
|
@ -103,7 +104,8 @@ class ApplicationAction(api.Action):
|
|||
self.application.launch(
|
||||
project_name=project_name,
|
||||
asset_name=asset_name,
|
||||
task_name=task_name
|
||||
task_name=task_name,
|
||||
**self.data
|
||||
)
|
||||
|
||||
except ApplictionExecutableNotFound as exc:
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ VARIANT_GROUP_ROLE = QtCore.Qt.UserRole + 2
|
|||
ACTION_ID_ROLE = QtCore.Qt.UserRole + 3
|
||||
ANIMATION_START_ROLE = QtCore.Qt.UserRole + 4
|
||||
ANIMATION_STATE_ROLE = QtCore.Qt.UserRole + 5
|
||||
FORCE_NOT_OPEN_WORKFILE_ROLE = QtCore.Qt.UserRole + 6
|
||||
ACTION_TOOLTIP_ROLE = QtCore.Qt.UserRole + 7
|
||||
|
||||
# Animation length in seconds
|
||||
ANIMATION_LEN = 7
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import time
|
|||
from Qt import QtCore, QtWidgets, QtGui
|
||||
from .constants import (
|
||||
ANIMATION_START_ROLE,
|
||||
ANIMATION_STATE_ROLE
|
||||
ANIMATION_STATE_ROLE,
|
||||
FORCE_NOT_OPEN_WORKFILE_ROLE
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -69,6 +70,16 @@ class ActionDelegate(QtWidgets.QStyledItemDelegate):
|
|||
self._draw_animation(painter, option, index)
|
||||
|
||||
super(ActionDelegate, self).paint(painter, option, index)
|
||||
|
||||
if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE):
|
||||
rect = QtCore.QRectF(option.rect.x(), option.rect.height(),
|
||||
5, 5)
|
||||
painter.setPen(QtCore.Qt.transparent)
|
||||
painter.setBrush(QtGui.QColor(200, 0, 0))
|
||||
painter.drawEllipse(rect)
|
||||
|
||||
painter.setBrush(self.extender_bg_brush)
|
||||
|
||||
is_group = False
|
||||
for group_role in self.group_roles:
|
||||
is_group = index.data(group_role)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class ProjectHandler(QtCore.QObject):
|
|||
Helps to organize two separate widgets handling current project selection.
|
||||
|
||||
It is easier to trigger project change callbacks from one place than from
|
||||
multiple differect places without proper handling or sequence changes.
|
||||
multiple different places without proper handling or sequence changes.
|
||||
|
||||
Args:
|
||||
dbcon(AvalonMongoDB): Mongo connection with Session.
|
||||
|
|
@ -42,7 +42,7 @@ class ProjectHandler(QtCore.QObject):
|
|||
# that may require reshing of projects
|
||||
refresh_interval = 10000
|
||||
|
||||
# Signal emmited when project has changed
|
||||
# Signal emitted when project has changed
|
||||
project_changed = QtCore.Signal(str)
|
||||
projects_refreshed = QtCore.Signal()
|
||||
timer_timeout = QtCore.Signal()
|
||||
|
|
|
|||
|
|
@ -2,19 +2,21 @@ import uuid
|
|||
import copy
|
||||
import logging
|
||||
import collections
|
||||
import appdirs
|
||||
|
||||
from . import lib
|
||||
from .constants import (
|
||||
ACTION_ROLE,
|
||||
GROUP_ROLE,
|
||||
VARIANT_GROUP_ROLE,
|
||||
ACTION_ID_ROLE
|
||||
ACTION_ID_ROLE,
|
||||
FORCE_NOT_OPEN_WORKFILE_ROLE
|
||||
)
|
||||
from .actions import ApplicationAction
|
||||
from Qt import QtCore, QtGui
|
||||
from avalon.vendor import qtawesome
|
||||
from avalon import style, api
|
||||
from openpype.lib import ApplicationManager
|
||||
from openpype.lib import ApplicationManager, JSONSettingRegistry
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -30,6 +32,13 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
# Cache of available actions
|
||||
self._registered_actions = list()
|
||||
self.items_by_id = {}
|
||||
path = appdirs.user_data_dir("openpype", "pypeclub")
|
||||
self.launcher_registry = JSONSettingRegistry("launcher", path)
|
||||
|
||||
try:
|
||||
_ = self.launcher_registry.get_item("force_not_open_workfile")
|
||||
except ValueError:
|
||||
self.launcher_registry.set_item("force_not_open_workfile", [])
|
||||
|
||||
def discover(self):
|
||||
"""Set up Actions cache. Run this for each new project."""
|
||||
|
|
@ -75,7 +84,8 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
"group": None,
|
||||
"icon": app.icon,
|
||||
"color": getattr(app, "color", None),
|
||||
"order": getattr(app, "order", None) or 0
|
||||
"order": getattr(app, "order", None) or 0,
|
||||
"data": {}
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -102,7 +112,7 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
# Groups
|
||||
group_name = getattr(action, "group", None)
|
||||
|
||||
# Lable variants
|
||||
# Label variants
|
||||
label = getattr(action, "label", None)
|
||||
label_variant = getattr(action, "label_variant", None)
|
||||
if label_variant and not label:
|
||||
|
|
@ -179,11 +189,17 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
|
||||
self.beginResetModel()
|
||||
|
||||
stored = self.launcher_registry.get_item("force_not_open_workfile")
|
||||
items = []
|
||||
for order in sorted(items_by_order.keys()):
|
||||
for item in items_by_order[order]:
|
||||
item_id = str(uuid.uuid4())
|
||||
item.setData(item_id, ACTION_ID_ROLE)
|
||||
|
||||
if self.is_force_not_open_workfile(item,
|
||||
stored):
|
||||
self.change_action_item(item, True)
|
||||
|
||||
self.items_by_id[item_id] = item
|
||||
items.append(item)
|
||||
|
||||
|
|
@ -222,6 +238,90 @@ class ActionModel(QtGui.QStandardItemModel):
|
|||
key=lambda action: (action.order, action.name)
|
||||
)
|
||||
|
||||
def update_force_not_open_workfile_settings(self, is_checked, action_id):
|
||||
"""Store/remove config for forcing to skip opening last workfile.
|
||||
|
||||
Args:
|
||||
is_checked (bool): True to add, False to remove
|
||||
action_id (str)
|
||||
"""
|
||||
action_item = self.items_by_id.get(action_id)
|
||||
if not action_item:
|
||||
return
|
||||
|
||||
action = action_item.data(ACTION_ROLE)
|
||||
actual_data = self._prepare_compare_data(action)
|
||||
|
||||
stored = self.launcher_registry.get_item("force_not_open_workfile")
|
||||
if is_checked:
|
||||
stored.append(actual_data)
|
||||
else:
|
||||
final_values = []
|
||||
for config in stored:
|
||||
if config != actual_data:
|
||||
final_values.append(config)
|
||||
stored = final_values
|
||||
|
||||
self.launcher_registry.set_item("force_not_open_workfile", stored)
|
||||
self.launcher_registry._get_item.cache_clear()
|
||||
self.change_action_item(action_item, is_checked)
|
||||
|
||||
def change_action_item(self, item, checked):
|
||||
"""Modifies tooltip and sets if opening of last workfile forbidden"""
|
||||
tooltip = item.data(QtCore.Qt.ToolTipRole)
|
||||
if checked:
|
||||
tooltip += " (Not opening last workfile)"
|
||||
|
||||
item.setData(tooltip, QtCore.Qt.ToolTipRole)
|
||||
item.setData(checked, FORCE_NOT_OPEN_WORKFILE_ROLE)
|
||||
|
||||
def is_application_action(self, action):
|
||||
"""Checks if item is of a ApplicationAction type
|
||||
|
||||
Args:
|
||||
action (action)
|
||||
"""
|
||||
if isinstance(action, list) and action:
|
||||
action = action[0]
|
||||
|
||||
return ApplicationAction in action.__bases__
|
||||
|
||||
def is_force_not_open_workfile(self, item, stored):
|
||||
"""Checks if application for task is marked to not open workfile
|
||||
|
||||
There might be specific tasks where is unwanted to open workfile right
|
||||
always (broken file, low performance). This allows artist to mark to
|
||||
skip opening for combination (project, asset, task_name, app)
|
||||
|
||||
Args:
|
||||
item (QStandardItem)
|
||||
stored (list) of dict
|
||||
"""
|
||||
action = item.data(ACTION_ROLE)
|
||||
if not self.is_application_action(action):
|
||||
return False
|
||||
|
||||
actual_data = self._prepare_compare_data(action)
|
||||
for config in stored:
|
||||
if config == actual_data:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _prepare_compare_data(self, action):
|
||||
if isinstance(action, list) and action:
|
||||
action = action[0]
|
||||
|
||||
compare_data = {}
|
||||
if action:
|
||||
compare_data = {
|
||||
"app_label": action.label.lower(),
|
||||
"project_name": self.dbcon.Session["AVALON_PROJECT"],
|
||||
"asset": self.dbcon.Session["AVALON_ASSET"],
|
||||
"task_name": self.dbcon.Session["AVALON_TASK"]
|
||||
}
|
||||
return compare_data
|
||||
|
||||
|
||||
class ProjectModel(QtGui.QStandardItemModel):
|
||||
"""List of projects"""
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ from .constants import (
|
|||
ACTION_ID_ROLE,
|
||||
ANIMATION_START_ROLE,
|
||||
ANIMATION_STATE_ROLE,
|
||||
ANIMATION_LEN
|
||||
ANIMATION_LEN,
|
||||
FORCE_NOT_OPEN_WORKFILE_ROLE
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -96,6 +97,7 @@ class ActionBar(QtWidgets.QWidget):
|
|||
view.setViewMode(QtWidgets.QListView.IconMode)
|
||||
view.setResizeMode(QtWidgets.QListView.Adjust)
|
||||
view.setSelectionMode(QtWidgets.QListView.NoSelection)
|
||||
view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
|
||||
view.setEditTriggers(QtWidgets.QListView.NoEditTriggers)
|
||||
view.setWrapping(True)
|
||||
view.setGridSize(QtCore.QSize(70, 75))
|
||||
|
|
@ -135,8 +137,16 @@ class ActionBar(QtWidgets.QWidget):
|
|||
|
||||
project_handler.projects_refreshed.connect(self._on_projects_refresh)
|
||||
view.clicked.connect(self.on_clicked)
|
||||
view.customContextMenuRequested.connect(self.on_context_menu)
|
||||
|
||||
self._context_menu = None
|
||||
self._discover_on_menu = False
|
||||
|
||||
def discover_actions(self):
|
||||
if self._context_menu is not None:
|
||||
self._discover_on_menu = True
|
||||
return
|
||||
|
||||
if self._animation_timer.isActive():
|
||||
self._animation_timer.stop()
|
||||
self.model.discover()
|
||||
|
|
@ -171,7 +181,7 @@ class ActionBar(QtWidgets.QWidget):
|
|||
self.update()
|
||||
|
||||
def _start_animation(self, index):
|
||||
# Offset refresh timout
|
||||
# Offset refresh timeout
|
||||
self.project_handler.start_timer()
|
||||
action_id = index.data(ACTION_ID_ROLE)
|
||||
item = self.model.items_by_id.get(action_id)
|
||||
|
|
@ -181,6 +191,46 @@ class ActionBar(QtWidgets.QWidget):
|
|||
self._animated_items.add(action_id)
|
||||
self._animation_timer.start()
|
||||
|
||||
def on_context_menu(self, point):
|
||||
"""Creates menu to force skip opening last workfile."""
|
||||
index = self.view.indexAt(point)
|
||||
if not index.isValid():
|
||||
return
|
||||
|
||||
action_item = index.data(ACTION_ROLE)
|
||||
if not self.model.is_application_action(action_item):
|
||||
return
|
||||
|
||||
menu = QtWidgets.QMenu(self.view)
|
||||
checkbox = QtWidgets.QCheckBox("Skip opening last workfile.",
|
||||
menu)
|
||||
if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE):
|
||||
checkbox.setChecked(True)
|
||||
|
||||
action_id = index.data(ACTION_ID_ROLE)
|
||||
checkbox.stateChanged.connect(
|
||||
lambda: self.on_checkbox_changed(checkbox.isChecked(),
|
||||
action_id))
|
||||
action = QtWidgets.QWidgetAction(menu)
|
||||
action.setDefaultWidget(checkbox)
|
||||
|
||||
menu.addAction(action)
|
||||
|
||||
self._context_menu = menu
|
||||
global_point = self.mapToGlobal(point)
|
||||
menu.exec_(global_point)
|
||||
self._context_menu = None
|
||||
if self._discover_on_menu:
|
||||
self._discover_on_menu = False
|
||||
self.discover_actions()
|
||||
|
||||
def on_checkbox_changed(self, is_checked, action_id):
|
||||
self.model.update_force_not_open_workfile_settings(is_checked,
|
||||
action_id)
|
||||
self.view.update()
|
||||
if self._context_menu is not None:
|
||||
self._context_menu.close()
|
||||
|
||||
def on_clicked(self, index):
|
||||
if not index or not index.isValid():
|
||||
return
|
||||
|
|
@ -189,11 +239,15 @@ class ActionBar(QtWidgets.QWidget):
|
|||
is_variant_group = index.data(VARIANT_GROUP_ROLE)
|
||||
if not is_group and not is_variant_group:
|
||||
action = index.data(ACTION_ROLE)
|
||||
if index.data(FORCE_NOT_OPEN_WORKFILE_ROLE):
|
||||
action.data["start_last_workfile"] = False
|
||||
else:
|
||||
action.data.pop("start_last_workfile", None)
|
||||
self._start_animation(index)
|
||||
self.action_clicked.emit(action)
|
||||
return
|
||||
|
||||
# Offset refresh timout
|
||||
# Offset refresh timeout
|
||||
self.project_handler.start_timer()
|
||||
|
||||
actions = index.data(ACTION_ROLE)
|
||||
|
|
@ -212,7 +266,7 @@ class ActionBar(QtWidgets.QWidget):
|
|||
by_variant_label = collections.defaultdict(list)
|
||||
orders = []
|
||||
for action in actions:
|
||||
# Lable variants
|
||||
# Label variants
|
||||
label = getattr(action, "label", None)
|
||||
label_variant = getattr(action, "label_variant", None)
|
||||
if label_variant and not label:
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ module.window = None
|
|||
|
||||
# Register callback on task change
|
||||
# - callback can't be defined in Window as it is weak reference callback
|
||||
# so `WeakSet` will remove it immidiatelly
|
||||
# so `WeakSet` will remove it immediately
|
||||
def on_context_task_change(*args, **kwargs):
|
||||
if module.window:
|
||||
module.window.on_context_task_change(*args, **kwargs)
|
||||
|
|
@ -455,7 +455,7 @@ class LoaderWindow(QtWidgets.QDialog):
|
|||
shift_pressed = QtCore.Qt.ShiftModifier & modifiers
|
||||
|
||||
if shift_pressed:
|
||||
print("Force quitted..")
|
||||
print("Force quit..")
|
||||
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||||
|
||||
print("Good bye")
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ def get_options(action, loader, parent, repre_contexts):
|
|||
|
||||
Args:
|
||||
action (OptionalAction) - action in menu
|
||||
loader (cls of api.Loader) - not initilized yet
|
||||
loader (cls of api.Loader) - not initialized yet
|
||||
parent (Qt element to parent dialog to)
|
||||
repre_contexts (list) of dict with full info about selected repres
|
||||
Returns:
|
||||
|
|
|
|||
|
|
@ -233,8 +233,8 @@ class LookOutliner(QtWidgets.QWidget):
|
|||
list: list of dictionaries
|
||||
"""
|
||||
|
||||
datas = [i.data(TreeModel.ItemRole) for i in self.view.get_indices()]
|
||||
return [d for d in datas if d is not None]
|
||||
items = [i.data(TreeModel.ItemRole) for i in self.view.get_indices()]
|
||||
return [item for item in items if item is not None]
|
||||
|
||||
def right_mouse_menu(self, pos):
|
||||
"""Build RMB menu for look view"""
|
||||
|
|
|
|||
|
|
@ -124,12 +124,12 @@ class HierarchyModel(QtCore.QAbstractItemModel):
|
|||
Main part of ProjectManager.
|
||||
|
||||
Model should be able to load existing entities, create new, handle their
|
||||
validations like name duplication and validate if is possible to save it's
|
||||
validations like name duplication and validate if is possible to save its
|
||||
data.
|
||||
|
||||
Args:
|
||||
dbcon (AvalonMongoDB): Connection to MongoDB with set AVALON_PROJECT in
|
||||
it's Session to current project.
|
||||
its Session to current project.
|
||||
"""
|
||||
|
||||
# Definition of all possible columns with their labels in default order
|
||||
|
|
@ -799,7 +799,7 @@ class HierarchyModel(QtCore.QAbstractItemModel):
|
|||
for row in range(parent_item.rowCount()):
|
||||
child_item = parent_item.child(row)
|
||||
child_id = child_item.id
|
||||
# Not sure if this can happend
|
||||
# Not sure if this can happen
|
||||
# TODO validate this line it seems dangerous as start/end
|
||||
# row is not changed
|
||||
if child_id not in children:
|
||||
|
|
@ -1902,7 +1902,7 @@ class AssetItem(BaseItem):
|
|||
return self._data["name"]
|
||||
|
||||
def child_parents(self):
|
||||
"""Chilren AssetItem can use this method to get it's parent names.
|
||||
"""Children AssetItem can use this method to get it's parent names.
|
||||
|
||||
This is used for `data.parents` key on document.
|
||||
"""
|
||||
|
|
@ -2006,7 +2006,7 @@ class AssetItem(BaseItem):
|
|||
@classmethod
|
||||
def data_from_doc(cls, asset_doc):
|
||||
"""Convert asset document from Mongo to item data."""
|
||||
# Minimum required data for cases that it is new AssetItem withoud doc
|
||||
# Minimum required data for cases that it is new AssetItem without doc
|
||||
data = {
|
||||
"name": None,
|
||||
"type": "asset"
|
||||
|
|
@ -2253,7 +2253,7 @@ class TaskItem(BaseItem):
|
|||
"""Item representing Task item on Asset document.
|
||||
|
||||
Always should be AssetItem children and never should have any other
|
||||
childrens.
|
||||
children.
|
||||
|
||||
It's name value should be validated with it's parent which only knows if
|
||||
has same name as other sibling under same parent.
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
|||
elif event.type() == QtCore.QEvent.KeyPress:
|
||||
# TODO: handle QtCore.Qt.Key_Enter, Key_Return?
|
||||
if event.key() == QtCore.Qt.Key_Space:
|
||||
# toogle the current items check state
|
||||
# toggle the current items check state
|
||||
if (
|
||||
index_flags & QtCore.Qt.ItemIsUserCheckable
|
||||
and index_flags & QtCore.Qt.ItemIsTristate
|
||||
|
|
|
|||
|
|
@ -555,7 +555,7 @@ class PublisherController:
|
|||
self.create_context.reset_avalon_context()
|
||||
|
||||
self._reset_plugins()
|
||||
# Publish part must be resetted after plugins
|
||||
# Publish part must be reset after plugins
|
||||
self._reset_publish()
|
||||
self._reset_instances()
|
||||
|
||||
|
|
@ -690,7 +690,7 @@ class PublisherController:
|
|||
|
||||
def remove_instances(self, instances):
|
||||
""""""
|
||||
# QUESTION Expect that instaces are really removed? In that case save
|
||||
# QUESTION Expect that instances are really removed? In that case save
|
||||
# reset is not required and save changes too.
|
||||
self.save_changes()
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class _HBottomLineWidget(QtWidgets.QWidget):
|
|||
Corners may have curve set by radius (`set_radius`). Radius should expect
|
||||
height of widget.
|
||||
|
||||
Bottom line is drawed at the bottom of widget. If radius is 0 then height
|
||||
Bottom line is drawn at the bottom of widget. If radius is 0 then height
|
||||
of widget should be 1px.
|
||||
|
||||
It is expected that parent widget will set height and radius.
|
||||
|
|
@ -94,7 +94,7 @@ class _HTopCornerLineWidget(QtWidgets.QWidget):
|
|||
or
|
||||
```┌───────```
|
||||
|
||||
Horizontal line is drawed in the middle of widget.
|
||||
Horizontal line is drawn in the middle of widget.
|
||||
|
||||
Widget represents left or right corner. Corner may have curve set by
|
||||
radius (`set_radius`). Radius should expect height of widget (maximum half
|
||||
|
|
@ -225,7 +225,7 @@ class BorderedLabelWidget(QtWidgets.QFrame):
|
|||
self._radius = radius
|
||||
|
||||
side_width = 1 + radius
|
||||
# Dont't use fixed width/height as that would set also set
|
||||
# Don't use fixed width/height as that would set also set
|
||||
# the other size (When fixed width is set then is also set
|
||||
# fixed height).
|
||||
self._left_w.setMinimumWidth(side_width)
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ class InstanceCardView(AbstractInstanceView):
|
|||
|
||||
def sizeHint(self):
|
||||
"""Modify sizeHint based on visibility of scroll bars."""
|
||||
# Calculate width hint by content widget and verticall scroll bar
|
||||
# Calculate width hint by content widget and vertical scroll bar
|
||||
scroll_bar = self._scroll_area.verticalScrollBar()
|
||||
width = (
|
||||
self._content_widget.sizeHint().width()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ attribute on instance (Group defined by creator).
|
|||
Each item can be enabled/disabled with their checkbox, whole group
|
||||
can be enabled/disabled with checkbox on group or
|
||||
selection can be enabled disabled using checkbox or keyboard key presses:
|
||||
- Space - change state of selection to oposite
|
||||
- Space - change state of selection to opposite
|
||||
- Enter - enable selection
|
||||
- Backspace - disable selection
|
||||
|
||||
|
|
@ -589,7 +589,7 @@ class InstanceListView(AbstractInstanceView):
|
|||
# - create new instance, update existing and remove not existing
|
||||
for group_name, group_item in self._group_items.items():
|
||||
# Instance items to remove
|
||||
# - will contain all exising instance ids at the start
|
||||
# - will contain all existing instance ids at the start
|
||||
# - instance ids may be removed when existing instances are checked
|
||||
to_remove = set()
|
||||
# Mapping of existing instances under group item
|
||||
|
|
@ -659,7 +659,7 @@ class InstanceListView(AbstractInstanceView):
|
|||
for instance_id in to_remove:
|
||||
idx_to_remove.append(existing_mapping[instance_id])
|
||||
|
||||
# Remove them in reverse order to prevend row index changes
|
||||
# Remove them in reverse order to prevent row index changes
|
||||
for idx in reversed(sorted(idx_to_remove)):
|
||||
group_item.removeRows(idx, 1)
|
||||
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ class VerticallScrollArea(QtWidgets.QScrollArea):
|
|||
The biggest difference is that the scroll area has scroll bar on left side
|
||||
and resize of content will also resize scrollarea itself.
|
||||
|
||||
Resize if deffered by 100ms because at the moment of resize are not yet
|
||||
Resize if deferred by 100ms because at the moment of resize are not yet
|
||||
propagated sizes and visibility of scroll bars.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -749,7 +749,7 @@ class TasksCombobox(QtWidgets.QComboBox):
|
|||
self.value_changed.emit()
|
||||
|
||||
def set_text(self, text):
|
||||
"""Set context shown in combobox without chaning selected items."""
|
||||
"""Set context shown in combobox without changing selected items."""
|
||||
if text == self._text:
|
||||
return
|
||||
|
||||
|
|
@ -1000,7 +1000,7 @@ class VariantInputWidget(PlaceholderLineEdit):
|
|||
self.value_changed.emit()
|
||||
|
||||
def reset_to_origin(self):
|
||||
"""Set origin value of selected instnaces."""
|
||||
"""Set origin value of selected instances."""
|
||||
self.set_value(self._origin_value)
|
||||
|
||||
def get_value(self):
|
||||
|
|
@ -1105,7 +1105,7 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
|
|||
|
||||
Subset name is or may be affected on context. Gives abiity to modify
|
||||
context and subset name of instance. This change is not autopromoted but
|
||||
must be submited.
|
||||
must be submitted.
|
||||
|
||||
Warning: Until artist hit `Submit` changes must not be propagated to
|
||||
instance data.
|
||||
|
|
@ -1179,7 +1179,7 @@ class GlobalAttrsWidget(QtWidgets.QWidget):
|
|||
self.cancel_btn = cancel_btn
|
||||
|
||||
def _on_submit(self):
|
||||
"""Commit changes for selected instnaces."""
|
||||
"""Commit changes for selected instances."""
|
||||
variant_value = None
|
||||
asset_name = None
|
||||
task_name = None
|
||||
|
|
@ -1363,7 +1363,7 @@ class CreatorAttrsWidget(QtWidgets.QWidget):
|
|||
self._attr_def_id_to_instances = {}
|
||||
self._attr_def_id_to_attr_def = {}
|
||||
|
||||
# To store content of scroll area to prevend garbage collection
|
||||
# To store content of scroll area to prevent garbage collection
|
||||
self._content_widget = None
|
||||
|
||||
def set_instances_valid(self, valid):
|
||||
|
|
@ -1375,7 +1375,7 @@ class CreatorAttrsWidget(QtWidgets.QWidget):
|
|||
self._content_widget.setEnabled(valid)
|
||||
|
||||
def set_current_instances(self, instances):
|
||||
"""Set current instances for which are attribute definitons shown."""
|
||||
"""Set current instances for which are attribute definitions shown."""
|
||||
prev_content_widget = self._scroll_area.widget()
|
||||
if prev_content_widget:
|
||||
self._scroll_area.takeWidget()
|
||||
|
|
@ -1461,7 +1461,7 @@ class PublishPluginAttrsWidget(QtWidgets.QWidget):
|
|||
self._attr_def_id_to_attr_def = {}
|
||||
self._attr_def_id_to_plugin_name = {}
|
||||
|
||||
# Store content of scroll area to prevend garbage collection
|
||||
# Store content of scroll area to prevent garbage collection
|
||||
self._content_widget = None
|
||||
|
||||
def set_instances_valid(self, valid):
|
||||
|
|
@ -1473,7 +1473,7 @@ class PublishPluginAttrsWidget(QtWidgets.QWidget):
|
|||
self._content_widget.setEnabled(valid)
|
||||
|
||||
def set_current_instances(self, instances, context_selected):
|
||||
"""Set current instances for which are attribute definitons shown."""
|
||||
"""Set current instances for which are attribute definitions shown."""
|
||||
prev_content_widget = self._scroll_area.widget()
|
||||
if prev_content_widget:
|
||||
self._scroll_area.takeWidget()
|
||||
|
|
|
|||
|
|
@ -106,14 +106,14 @@ class Controller(QtCore.QObject):
|
|||
# ??? Emitted for each process
|
||||
was_processed = QtCore.Signal(dict)
|
||||
|
||||
# Emmited when reset
|
||||
# Emitted when reset
|
||||
# - all data are reset (plugins, processing, pari yielder, etc.)
|
||||
was_reset = QtCore.Signal()
|
||||
|
||||
# Emmited when previous group changed
|
||||
# Emitted when previous group changed
|
||||
passed_group = QtCore.Signal(object)
|
||||
|
||||
# Emmited when want to change state of instances
|
||||
# Emitted when want to change state of instances
|
||||
switch_toggleability = QtCore.Signal(bool)
|
||||
|
||||
# On action finished
|
||||
|
|
@ -322,7 +322,7 @@ class Controller(QtCore.QObject):
|
|||
try:
|
||||
result = pyblish.plugin.process(plugin, self.context, instance)
|
||||
# Make note of the order at which the
|
||||
# potential error error occured.
|
||||
# potential error error occurred.
|
||||
if result["error"] is not None:
|
||||
self.processing["ordersWithError"].add(plugin.order)
|
||||
|
||||
|
|
@ -564,7 +564,7 @@ class Controller(QtCore.QObject):
|
|||
case must be taken to ensure there are no memory leaks.
|
||||
Explicitly deleting objects shines a light on where objects
|
||||
may still be referenced in the form of an error. No errors
|
||||
means this was uneccesary, but that's ok.
|
||||
means this was unnecessary, but that's ok.
|
||||
"""
|
||||
|
||||
for instance in self.context:
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ class OrderGroups:
|
|||
def sort_groups(_groups_dict):
|
||||
sorted_dict = collections.OrderedDict()
|
||||
|
||||
# make sure wont affect any dictionary as pointer
|
||||
# make sure won't affect any dictionary as pointer
|
||||
groups_dict = copy.deepcopy(_groups_dict)
|
||||
last_order = None
|
||||
if None in groups_dict:
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ class SwitchAssetDialog(QtWidgets.QDialog):
|
|||
|
||||
repre_docs = io.find(
|
||||
{
|
||||
"type": "rerpesentation",
|
||||
"type": "representation",
|
||||
"parent": subset_doc["_id"],
|
||||
"name": {"$in": list(repre_names)}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class SceneInventoryWindow(QtWidgets.QDialog):
|
|||
|
||||
Override keyPressEvent to do nothing so that Maya's panels won't
|
||||
take focus when pressing "SHIFT" whilst mouse is over viewport or
|
||||
outliner. This way users don't accidently perform Maya commands
|
||||
outliner. This way users don't accidentally perform Maya commands
|
||||
whilst trying to name an instance.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ LABEL_REMOVE_PROJECT = "Remove from project"
|
|||
LABEL_ADD_PROJECT = "Add to project"
|
||||
LABEL_DISCARD_CHANGES = "Discard changes"
|
||||
|
||||
# Local setting contants
|
||||
# Local setting constants
|
||||
# TODO move to settings constants
|
||||
LOCAL_GENERAL_KEY = "general"
|
||||
LOCAL_PROJECTS_KEY = "projects"
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ class DynamicInputItem(QtCore.QObject):
|
|||
return "studio"
|
||||
else:
|
||||
if current_value:
|
||||
return "overriden"
|
||||
return "overridden"
|
||||
|
||||
if self.value_item.default_value:
|
||||
return "studio"
|
||||
|
|
@ -512,7 +512,7 @@ class _SiteCombobox(QtWidgets.QWidget):
|
|||
return "studio"
|
||||
else:
|
||||
if current_value:
|
||||
return "overriden"
|
||||
return "overridden"
|
||||
|
||||
studio_value = self._get_local_settings_item(DEFAULT_PROJECT_KEY)
|
||||
if studio_value:
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ class LocalSettingsWindow(QtWidgets.QWidget):
|
|||
# Do not create local settings widget in init phase as it's using
|
||||
# settings objects that must be OK to be able create this widget
|
||||
# - we want to show dialog if anything goes wrong
|
||||
# - without reseting nothing is shown
|
||||
# - without resetting nothing is shown
|
||||
self._settings_widget = None
|
||||
self._scroll_widget = scroll_widget
|
||||
self.reset_btn = reset_btn
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
- `"is_file"` - this key is for storing openpype defaults in `openpype` repo
|
||||
- reasons of existence: developing new schemas does not require to create defaults manually
|
||||
- key is validated, must be once in hierarchy else it won't be possible to store openpype defaults
|
||||
- `"is_group"` - define that all values under key in hierarchy will be overriden if any value is modified, this information is also stored to overrides
|
||||
- `"is_group"` - define that all values under key in hierarchy will be overridden if any value is modified, this information is also stored to overrides
|
||||
- this keys is not allowed for all inputs as they may have not reason for that
|
||||
- key is validated, can be only once in hierarchy but is not required
|
||||
- currently there are `system configurations` and `project configurations`
|
||||
|
|
@ -199,7 +199,7 @@
|
|||
- number input, can be used for both integer and float
|
||||
- key `"decimal"` defines how many decimal places will be used, 0 is for integer input (Default: `0`)
|
||||
- key `"minimum"` as minimum allowed number to enter (Default: `-99999`)
|
||||
- key `"maxium"` as maximum allowed number to enter (Default: `99999`)
|
||||
- key `"maximum"` as maximum allowed number to enter (Default: `99999`)
|
||||
```
|
||||
{
|
||||
"type": "number",
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class BaseWidget(QtWidgets.QWidget):
|
|||
if is_modified:
|
||||
return "modified"
|
||||
if has_project_override:
|
||||
return "overriden"
|
||||
return "overridden"
|
||||
if has_studio_override:
|
||||
return "studio"
|
||||
return ""
|
||||
|
|
@ -168,7 +168,7 @@ class BaseWidget(QtWidgets.QWidget):
|
|||
with self.category_widget.working_state_context():
|
||||
self.entity.add_to_project_override
|
||||
|
||||
action = QtWidgets.QAction("Add to project project override")
|
||||
action = QtWidgets.QAction("Add to project override")
|
||||
actions_mapping[action] = add_to_project_override
|
||||
menu.addAction(action)
|
||||
|
||||
|
|
@ -289,7 +289,7 @@ class BaseWidget(QtWidgets.QWidget):
|
|||
action = QtWidgets.QAction("Paste", menu)
|
||||
output.append((action, paste_value))
|
||||
|
||||
# Paste value to matchin entity
|
||||
# Paste value to matching entity
|
||||
def paste_value_to_path():
|
||||
with self.category_widget.working_state_context():
|
||||
_set_entity_value(matching_entity, value)
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ class DictConditionalWidget(BaseWidget):
|
|||
content_widget.setObjectName("ContentWidget")
|
||||
|
||||
if self.entity.highlight_content:
|
||||
content_state = "hightlighted"
|
||||
content_state = "highlighted"
|
||||
bottom_margin = 5
|
||||
else:
|
||||
content_state = ""
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ class ModifiableDictItem(QtWidgets.QWidget):
|
|||
if self.entity.has_unsaved_changes:
|
||||
return "modified"
|
||||
if self.entity.has_project_override:
|
||||
return "overriden"
|
||||
return "overridden"
|
||||
if self.entity.has_studio_override:
|
||||
return "studio"
|
||||
return ""
|
||||
|
|
@ -600,8 +600,8 @@ class DictMutableKeysWidget(BaseWidget):
|
|||
self.input_fields = []
|
||||
self.required_inputs_by_key = {}
|
||||
|
||||
if self.entity.hightlight_content:
|
||||
content_state = "hightlighted"
|
||||
if self.entity.highlight_content:
|
||||
content_state = "highlighted"
|
||||
bottom_margin = 5
|
||||
else:
|
||||
content_state = ""
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ class DictImmutableKeysWidget(BaseWidget):
|
|||
content_widget.setObjectName("ContentWidget")
|
||||
|
||||
if self.entity.highlight_content:
|
||||
content_state = "hightlighted"
|
||||
content_state = "highlighted"
|
||||
bottom_margin = 5
|
||||
else:
|
||||
content_state = ""
|
||||
|
|
@ -477,7 +477,7 @@ class OpenPypeVersionText(TextWidget):
|
|||
self.entity.set(value)
|
||||
self.update_style()
|
||||
else:
|
||||
# Manually trigger hierachical style update
|
||||
# Manually trigger hierarchical style update
|
||||
self.ignore_input_changes.set_ignore(True)
|
||||
self.ignore_input_changes.set_ignore(False)
|
||||
|
||||
|
|
@ -675,7 +675,7 @@ class RawJsonWidget(InputWidget):
|
|||
self.entity.set(self.input_field.json_value())
|
||||
self.update_style()
|
||||
else:
|
||||
# Manually trigger hierachical style update
|
||||
# Manually trigger hierarchical style update
|
||||
self.ignore_input_changes.set_ignore(True)
|
||||
self.ignore_input_changes.set_ignore(False)
|
||||
|
||||
|
|
@ -792,7 +792,7 @@ class PathWidget(BaseWidget):
|
|||
self.input_field.hierarchical_style_update()
|
||||
|
||||
def _on_entity_change(self):
|
||||
# No need to do anything. Styles will be updated from top hierachy.
|
||||
# No need to do anything. Styles will be updated from top hierarchy.
|
||||
pass
|
||||
|
||||
def update_style(self):
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ VALUE_CHANGE_OFFSET_MS = 300
|
|||
|
||||
|
||||
def create_deffered_value_change_timer(callback):
|
||||
"""Deffer value change callback.
|
||||
"""Defer value change callback.
|
||||
|
||||
UI won't trigger all callbacks on each value change but after predefined
|
||||
time. Timer is reset on each start so callback is triggered after user
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class ListStrictWidget(BaseWidget):
|
|||
break
|
||||
|
||||
self._any_children_has_label = any_children_has_label
|
||||
# Change column stretch factor for verticall alignment
|
||||
# Change column stretch factor for vertical alignment
|
||||
if not self.entity.is_horizontal:
|
||||
col_index = 2 if any_children_has_label else 1
|
||||
content_layout.setColumnStretch(col_index, 1)
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ class MultiSelectionComboBox(QtWidgets.QComboBox):
|
|||
elif event.type() == QtCore.QEvent.KeyPress:
|
||||
# TODO: handle QtCore.Qt.Key_Enter, Key_Return?
|
||||
if event.key() == QtCore.Qt.Key_Space:
|
||||
# toogle the current items check state
|
||||
# toggle the current items check state
|
||||
if (
|
||||
index_flags & QtCore.Qt.ItemIsUserCheckable
|
||||
and index_flags & QtCore.Qt.ItemIsTristate
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ class MainWidget(QtWidgets.QWidget):
|
|||
def _on_restart_required(self):
|
||||
# Don't show dialog if there are not registered slots for
|
||||
# `trigger_restart` signal.
|
||||
# - For example when settings are runnin as standalone tool
|
||||
# - For example when settings are running as standalone tool
|
||||
# - PySide2 and PyQt5 compatible way how to find out
|
||||
method_index = self.metaObject().indexOfMethod("trigger_restart()")
|
||||
method = self.metaObject().method(method_index)
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ class Window(QtWidgets.QDialog):
|
|||
return self._db
|
||||
|
||||
def on_start(self):
|
||||
''' Things must be done when initilized.
|
||||
''' Things must be done when initialized.
|
||||
'''
|
||||
# Refresh asset input in Family widget
|
||||
self.on_asset_changed()
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ class AssetModel(TreeModel):
|
|||
"""
|
||||
if silos:
|
||||
# WARNING: Silo item "_id" is set to silo value
|
||||
# mainly because GUI issue with perserve selection and expanded row
|
||||
# mainly because GUI issue with preserve selection and expanded row
|
||||
# and because of easier hierarchy parenting (in "assets")
|
||||
for silo in silos:
|
||||
node = Node({
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ def preserve_expanded_rows(tree_view,
|
|||
|
||||
This function is created to maintain the expand vs collapse status of
|
||||
the model items. When refresh is triggered the items which are expanded
|
||||
will stay expanded and vise versa.
|
||||
will stay expanded and vice versa.
|
||||
|
||||
Arguments:
|
||||
tree_view (QWidgets.QTreeView): the tree view which is
|
||||
|
|
@ -68,7 +68,7 @@ def preserve_selection(tree_view,
|
|||
|
||||
This function is created to maintain the selection status of
|
||||
the model items. When refresh is triggered the items which are expanded
|
||||
will stay expanded and vise versa.
|
||||
will stay expanded and vice versa.
|
||||
|
||||
tree_view (QWidgets.QTreeView): the tree view nested in the application
|
||||
column (int): the column to retrieve the data from
|
||||
|
|
@ -390,7 +390,7 @@ class AssetWidget(QtWidgets.QWidget):
|
|||
assets, (tuple, list)
|
||||
), "Assets must be list or tuple"
|
||||
|
||||
# convert to list - tuple cant be modified
|
||||
# convert to list - tuple can't be modified
|
||||
assets = list(assets)
|
||||
|
||||
# Clear selection
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class DropDataFrame(QtWidgets.QFrame):
|
|||
return paths
|
||||
|
||||
def _add_item(self, data, actions=[]):
|
||||
# Assign to self so garbage collector wont remove the component
|
||||
# Assign to self so garbage collector won't remove the component
|
||||
# during initialization
|
||||
new_component = ComponentItem(self.components_list, self)
|
||||
new_component.set_context(data)
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ class FamilyWidget(QtWidgets.QWidget):
|
|||
|
||||
Override keyPressEvent to do nothing so that Maya's panels won't
|
||||
take focus when pressing "SHIFT" whilst mouse is over viewport or
|
||||
outliner. This way users don't accidently perform Maya commands
|
||||
outliner. This way users don't accidentally perform Maya commands
|
||||
whilst trying to name an instance.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -433,7 +433,7 @@ class PypeInfoSubWidget(QtWidgets.QWidget):
|
|||
pype_info.pop("version_type", self.not_applicable)
|
||||
)
|
||||
pype_info["version_value"] = version_value
|
||||
# Prepare lable mapping
|
||||
# Prepare label mapping
|
||||
key_label_mapping = {
|
||||
"version_value": "Running version:",
|
||||
"build_verison": "Build version:",
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ class TrayManager:
|
|||
|
||||
@property
|
||||
def doubleclick_callback(self):
|
||||
"""Doubleclick callback for Tray icon."""
|
||||
"""Double-click callback for Tray icon."""
|
||||
callback_name = self.modules_manager.doubleclick_callback
|
||||
return self.modules_manager.doubleclick_callbacks.get(callback_name)
|
||||
|
||||
|
|
@ -398,7 +398,7 @@ class TrayManager:
|
|||
title = "Settings miss default values"
|
||||
msg = (
|
||||
"Your OpenPype will not work as expected! \n"
|
||||
"Some default values in settigs are missing. \n\n"
|
||||
"Some default values in settings are missing. \n\n"
|
||||
"Please contact OpenPype team."
|
||||
)
|
||||
msg_box = QtWidgets.QMessageBox(
|
||||
|
|
@ -430,7 +430,7 @@ class TrayManager:
|
|||
message (str): Content of message.
|
||||
icon (QSystemTrayIcon.MessageIcon): Message's icon. Default is
|
||||
Information icon, may differ by Qt version.
|
||||
msecs (int): Duration of message visibility in miliseconds.
|
||||
msecs (int): Duration of message visibility in milliseconds.
|
||||
Default is 10000 msecs, may differ by Qt version.
|
||||
"""
|
||||
args = [title, message]
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ class ConsoleTrayApp:
|
|||
def _multiple_replace(text, adict):
|
||||
"""Replace multiple tokens defined in dict.
|
||||
|
||||
Find and replace all occurances of strings defined in dict is
|
||||
Find and replace all occurrences of strings defined in dict is
|
||||
supplied string.
|
||||
|
||||
Args:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"""Single access point to all tools usable in hosts.
|
||||
|
||||
It is possible to create `HostToolsHelper` in host implementaion or
|
||||
It is possible to create `HostToolsHelper` in host implementation or
|
||||
use singleton approach with global functions (using helper anyway).
|
||||
"""
|
||||
|
||||
|
|
@ -223,7 +223,7 @@ class HostToolsHelper:
|
|||
"""Dialog of experimental tools.
|
||||
|
||||
For some hosts it is not easy to modify menu of tools. For
|
||||
those cases was addded experimental tools dialog which is Qt based
|
||||
those cases was added experimental tools dialog which is Qt based
|
||||
and can dynamically filled by experimental tools so
|
||||
host need only single "Experimental tools" button to see them.
|
||||
|
||||
|
|
@ -347,7 +347,7 @@ class _SingletonPoint:
|
|||
return cls.helper.get_tool_by_name(tool_name, parent, *args, **kwargs)
|
||||
|
||||
|
||||
# Function callbacks using singleton acces point
|
||||
# Function callbacks using singleton access point
|
||||
def get_tool_by_name(tool_name, parent=None, *args, **kwargs):
|
||||
return _SingletonPoint.get_tool_by_name(tool_name, parent, *args, **kwargs)
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ def preserve_expanded_rows(tree_view, column=0, role=None):
|
|||
|
||||
This function is created to maintain the expand vs collapse status of
|
||||
the model items. When refresh is triggered the items which are expanded
|
||||
will stay expanded and vise versa.
|
||||
will stay expanded and vice versa.
|
||||
|
||||
Arguments:
|
||||
tree_view (QWidgets.QTreeView): the tree view which is
|
||||
|
|
@ -176,7 +176,7 @@ def preserve_selection(tree_view, column=0, role=None, current_index=True):
|
|||
|
||||
This function is created to maintain the selection status of
|
||||
the model items. When refresh is triggered the items which are expanded
|
||||
will stay expanded and vise versa.
|
||||
will stay expanded and vice versa.
|
||||
|
||||
tree_view (QWidgets.QTreeView): the tree view nested in the application
|
||||
column (int): the column to retrieve the data from
|
||||
|
|
@ -372,7 +372,7 @@ class GroupsConfig:
|
|||
group_configs = []
|
||||
project_name = self.dbcon.Session.get("AVALON_PROJECT")
|
||||
if project_name:
|
||||
# Get pre-defined group name and apperance from project config
|
||||
# Get pre-defined group name and appearance from project config
|
||||
project_doc = self.dbcon.find_one(
|
||||
{"type": "project"},
|
||||
projection={"config.groups": True}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ class OptionalMenu(QtWidgets.QMenu):
|
|||
"""A subclass of `QtWidgets.QMenu` to work with `OptionalAction`
|
||||
|
||||
This menu has reimplemented `mouseReleaseEvent`, `mouseMoveEvent` and
|
||||
`leaveEvent` to provide better action hightlighting and triggering for
|
||||
`leaveEvent` to provide better action highlighting and triggering for
|
||||
actions that were instances of `QtWidgets.QWidgetAction`.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ from Qt import QtWidgets, QtCore
|
|||
from avalon import io, api, pipeline
|
||||
|
||||
from openpype import style
|
||||
from openpype.pipeline.lib import BeforeWorkfileSave
|
||||
from openpype.tools.utils.lib import (
|
||||
qt_app_context
|
||||
)
|
||||
|
|
@ -162,7 +163,7 @@ class NameWindow(QtWidgets.QDialog):
|
|||
|
||||
# Build inputs
|
||||
inputs_layout = QtWidgets.QFormLayout(inputs_widget)
|
||||
# Add version only if template contain version key
|
||||
# Add version only if template contains version key
|
||||
# - since the version can be padded with "{version:0>4}" we only search
|
||||
# for "{version".
|
||||
if "{version" in self.template:
|
||||
|
|
@ -170,7 +171,7 @@ class NameWindow(QtWidgets.QDialog):
|
|||
else:
|
||||
version_widget.setVisible(False)
|
||||
|
||||
# Add subversion only if template containt `{comment}`
|
||||
# Add subversion only if template contains `{comment}`
|
||||
if "{comment}" in self.template:
|
||||
inputs_layout.addRow("Subversion:", subversion_input)
|
||||
else:
|
||||
|
|
@ -183,7 +184,7 @@ class NameWindow(QtWidgets.QDialog):
|
|||
main_layout.addWidget(inputs_widget)
|
||||
main_layout.addWidget(btns_widget)
|
||||
|
||||
# Singal callback registration
|
||||
# Signal callback registration
|
||||
version_input.valueChanged.connect(self.on_version_spinbox_changed)
|
||||
last_version_check.stateChanged.connect(
|
||||
self.on_version_checkbox_changed
|
||||
|
|
@ -367,7 +368,8 @@ class FilesWidget(QtWidgets.QWidget):
|
|||
self.template_key = "work"
|
||||
|
||||
# This is not root but workfile directory
|
||||
self.root = None
|
||||
self._workfiles_root = None
|
||||
self._workdir_path = None
|
||||
self.host = api.registered_host()
|
||||
|
||||
# Whether to automatically select the latest modified
|
||||
|
|
@ -465,8 +467,9 @@ class FilesWidget(QtWidgets.QWidget):
|
|||
# This way we can browse it even before we enter it.
|
||||
if self._asset_id and self._task_name and self._task_type:
|
||||
session = self._get_session()
|
||||
self.root = self.host.work_root(session)
|
||||
self.files_model.set_root(self.root)
|
||||
self._workdir_path = session["AVALON_WORKDIR"]
|
||||
self._workfiles_root = self.host.work_root(session)
|
||||
self.files_model.set_root(self._workfiles_root)
|
||||
|
||||
else:
|
||||
self.files_model.set_root(None)
|
||||
|
|
@ -590,7 +593,7 @@ class FilesWidget(QtWidgets.QWidget):
|
|||
|
||||
window = NameWindow(
|
||||
parent=self,
|
||||
root=self.root,
|
||||
root=self._workfiles_root,
|
||||
anatomy=self.anatomy,
|
||||
template_key=self.template_key,
|
||||
session=session
|
||||
|
|
@ -605,7 +608,7 @@ class FilesWidget(QtWidgets.QWidget):
|
|||
return
|
||||
|
||||
src = self._get_selected_filepath()
|
||||
dst = os.path.join(self.root, work_file)
|
||||
dst = os.path.join(self._workfiles_root, work_file)
|
||||
shutil.copy(src, dst)
|
||||
|
||||
self.workfile_created.emit(dst)
|
||||
|
|
@ -638,98 +641,59 @@ class FilesWidget(QtWidgets.QWidget):
|
|||
"filter": ext_filter
|
||||
}
|
||||
if Qt.__binding__ in ("PySide", "PySide2"):
|
||||
kwargs["dir"] = self.root
|
||||
kwargs["dir"] = self._workfiles_root
|
||||
else:
|
||||
kwargs["directory"] = self.root
|
||||
kwargs["directory"] = self._workfiles_root
|
||||
|
||||
work_file = QtWidgets.QFileDialog.getOpenFileName(**kwargs)[0]
|
||||
if work_file:
|
||||
self.open_file(work_file)
|
||||
|
||||
def on_save_as_pressed(self):
|
||||
work_file = self.get_filename()
|
||||
if not work_file:
|
||||
work_filename = self.get_filename()
|
||||
if not work_filename:
|
||||
return
|
||||
|
||||
# Initialize work directory if it has not been initialized before
|
||||
if not os.path.exists(self.root):
|
||||
log.debug("Initializing Work Directory: %s", self.root)
|
||||
self.initialize_work_directory()
|
||||
if not os.path.exists(self.root):
|
||||
# Failed to initialize Work Directory
|
||||
log.error(
|
||||
"Failed to initialize Work Directory: {}".format(self.root)
|
||||
)
|
||||
return
|
||||
|
||||
file_path = os.path.join(os.path.normpath(self.root), work_file)
|
||||
|
||||
pipeline.emit("before.workfile.save", [file_path])
|
||||
|
||||
self._enter_session() # Make sure we are in the right session
|
||||
self.host.save_file(file_path)
|
||||
# Trigger before save event
|
||||
BeforeWorkfileSave.emit(work_filename, self._workdir_path)
|
||||
|
||||
# Make sure workfiles root is updated
|
||||
# - this triggers 'workio.work_root(...)' which may change value of
|
||||
# '_workfiles_root'
|
||||
self.set_asset_task(
|
||||
self._asset_id, self._task_name, self._task_type
|
||||
)
|
||||
|
||||
# Create workfiles root folder
|
||||
if not os.path.exists(self._workfiles_root):
|
||||
log.debug("Initializing Work Directory: %s", self._workfiles_root)
|
||||
os.makedirs(self._workfiles_root)
|
||||
|
||||
# Update session if context has changed
|
||||
self._enter_session()
|
||||
# Prepare full path to workfile and save it
|
||||
filepath = os.path.join(
|
||||
os.path.normpath(self._workfiles_root), work_filename
|
||||
)
|
||||
self.host.save_file(filepath)
|
||||
# Create extra folders
|
||||
create_workdir_extra_folders(
|
||||
self.root,
|
||||
self._workdir_path,
|
||||
api.Session["AVALON_APP"],
|
||||
self._task_type,
|
||||
self._task_name,
|
||||
api.Session["AVALON_PROJECT"]
|
||||
)
|
||||
pipeline.emit("after.workfile.save", [file_path])
|
||||
|
||||
self.workfile_created.emit(file_path)
|
||||
# Trigger after save events
|
||||
pipeline.emit("after.workfile.save", [filepath])
|
||||
|
||||
self.workfile_created.emit(filepath)
|
||||
# Refresh files model
|
||||
self.refresh()
|
||||
|
||||
def on_file_select(self):
|
||||
self.file_selected.emit(self._get_selected_filepath())
|
||||
|
||||
def initialize_work_directory(self):
|
||||
"""Initialize Work Directory.
|
||||
|
||||
This is used when the Work Directory does not exist yet.
|
||||
|
||||
This finds the current AVALON_APP_NAME and tries to triggers its
|
||||
`.toml` initialization step. Note that this will only be valid
|
||||
whenever `AVALON_APP_NAME` is actually set in the current session.
|
||||
|
||||
"""
|
||||
|
||||
# Inputs (from the switched session and running app)
|
||||
session = api.Session.copy()
|
||||
changes = pipeline.compute_session_changes(
|
||||
session,
|
||||
asset=self._get_asset_doc(),
|
||||
task=self._task_name,
|
||||
template_key=self.template_key
|
||||
)
|
||||
session.update(changes)
|
||||
|
||||
# Prepare documents to get workdir data
|
||||
project_doc = io.find_one({"type": "project"})
|
||||
asset_doc = io.find_one(
|
||||
{
|
||||
"type": "asset",
|
||||
"name": session["AVALON_ASSET"]
|
||||
}
|
||||
)
|
||||
task_name = session["AVALON_TASK"]
|
||||
host_name = session["AVALON_APP"]
|
||||
|
||||
# Get workdir from collected documents
|
||||
workdir = get_workdir(project_doc, asset_doc, task_name, host_name)
|
||||
# Create workdir if does not exist yet
|
||||
if not os.path.exists(workdir):
|
||||
os.makedirs(workdir)
|
||||
|
||||
# Force a full to the asset as opposed to just self.refresh() so
|
||||
# that it will actually check again whether the Work directory exists
|
||||
self.set_asset_task(self._asset_id, self._task_name, self._task_type)
|
||||
|
||||
def refresh(self):
|
||||
"""Refresh listed files for current selection in the interface"""
|
||||
self.files_model.refresh()
|
||||
|
|
@ -833,7 +797,7 @@ class SidePanelWidget(QtWidgets.QWidget):
|
|||
self.note_input.setEnabled(enabled)
|
||||
self.btn_note_save.setEnabled(enabled)
|
||||
|
||||
# Make sure workfile doc is overriden
|
||||
# Make sure workfile doc is overridden
|
||||
self._workfile_doc = workfile_doc
|
||||
# Disable inputs and remove texts if any required arguments are missing
|
||||
if not enabled:
|
||||
|
|
@ -978,7 +942,7 @@ class Window(QtWidgets.QMainWindow):
|
|||
|
||||
Override keyPressEvent to do nothing so that Maya's panels won't
|
||||
take focus when pressing "SHIFT" whilst mouse is over viewport or
|
||||
outliner. This way users don't accidently perform Maya commands
|
||||
outliner. This way users don't accidentally perform Maya commands
|
||||
whilst trying to name an instance.
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ Contains end-to-end tests for automatic testing of OP.
|
|||
Should run headless publish on all hosts to check basic publish use cases automatically
|
||||
to limit regression issues.
|
||||
|
||||
Uses env var `HEADLESS_PUBLISH` (set in test data zip files) to differentiate between regular publish
|
||||
and "automated" one.
|
||||
|
||||
How to run
|
||||
----------
|
||||
- activate `{OPENPYPE_ROOT}/.venv`
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ Each published variant can come out of the software in multiple representations.
|
|||
|
||||
### Family
|
||||
|
||||
Each published [subset][3b89d8e0] can have exactly one family assigned to it. Family determines the type of data that the subset holds. Family doesn't dictate the file type, but can enforce certain technical specifications. For example OpenPype default configuration expects `model` family to only contain geometry without any shaders or joins when it is published.
|
||||
Each published [subset][3b89d8e0] can have exactly one family assigned to it. Family determines the type of data that the subset holds. Family doesn't dictate the file type, but can enforce certain technical specifications. For example OpenPype default configuration expects `model` family to only contain geometry without any shaders or joints when it is published.
|
||||
|
||||
|
||||
[3b89d8e0]: #subset "subset"
|
||||
|
|
@ -40,7 +40,7 @@ General term for Software or Application supported by OpenPype and Avalon. These
|
|||
|
||||
### Tool
|
||||
|
||||
Small piece of software usually dedicated to a particular purpose. Most of OpenPype and Avalon tools have GUI, but some are command line only
|
||||
Small piece of software usually dedicated to a particular purpose. Most of OpenPype and Avalon tools have GUI, but some are command line only.
|
||||
|
||||
|
||||
### Publish
|
||||
|
|
@ -50,4 +50,4 @@ Process of exporting data from your work scene to versioned, immutable file that
|
|||
### Load
|
||||
|
||||
Process of importing previously published subsets into your current scene, using any of the OpenPype tools.
|
||||
Loading asset using proper tools will ensure that all your scene content stays version controlled and updatable at a later point
|
||||
Loading asset using proper tools will ensure that all your scene content stays version controlled and updatable at a later point.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue