mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge branch 'develop' of https://github.com/ynput/ayon-core into chore/houdini_remove_unused_create_remote_publish
This commit is contained in:
commit
ea647c060b
9 changed files with 157 additions and 111 deletions
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
from .cache import CacheItem, NestedCacheItem
|
||||
from .projects import (
|
||||
StatusItem,
|
||||
StatusStates,
|
||||
ProjectItem,
|
||||
ProjectsModel,
|
||||
PROJECTS_MODEL_SENDER,
|
||||
|
|
@ -21,6 +23,8 @@ __all__ = (
|
|||
"CacheItem",
|
||||
"NestedCacheItem",
|
||||
|
||||
"StatusItem",
|
||||
"StatusStates",
|
||||
"ProjectItem",
|
||||
"ProjectsModel",
|
||||
"PROJECTS_MODEL_SENDER",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import contextlib
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict, Any
|
||||
|
||||
import ayon_api
|
||||
import six
|
||||
|
||||
from ayon_core.style import get_default_entity_icon_color
|
||||
from ayon_core.lib import CacheItem, NestedCacheItem
|
||||
|
|
@ -10,8 +10,14 @@ from ayon_core.lib import CacheItem, NestedCacheItem
|
|||
PROJECTS_MODEL_SENDER = "projects.model"
|
||||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class AbstractHierarchyController:
|
||||
class StatusStates:
|
||||
not_started = "not_started"
|
||||
in_progress = "in_progress"
|
||||
done = "done"
|
||||
blocked = "blocked"
|
||||
|
||||
|
||||
class AbstractHierarchyController(ABC):
|
||||
@abstractmethod
|
||||
def emit_event(self, topic, data, source):
|
||||
pass
|
||||
|
|
@ -25,18 +31,24 @@ class StatusItem:
|
|||
color (str): Status color in hex ("#434a56").
|
||||
short (str): Short status name ("NRD").
|
||||
icon (str): Icon name in MaterialIcons ("fiber_new").
|
||||
state (Literal["not_started", "in_progress", "done", "blocked"]):
|
||||
Status state.
|
||||
state (str): Status state.
|
||||
|
||||
"""
|
||||
def __init__(self, name, color, short, icon, state):
|
||||
self.name = name
|
||||
self.color = color
|
||||
self.short = short
|
||||
self.icon = icon
|
||||
self.state = state
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
color: str,
|
||||
short: str,
|
||||
icon: str,
|
||||
state: str
|
||||
):
|
||||
self.name: str = name
|
||||
self.color: str = color
|
||||
self.short: str = short
|
||||
self.icon: str = icon
|
||||
self.state: str = state
|
||||
|
||||
def to_data(self):
|
||||
def to_data(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"name": self.name,
|
||||
"color": self.color,
|
||||
|
|
|
|||
|
|
@ -217,7 +217,9 @@ class InventoryModel(QtGui.QStandardItemModel):
|
|||
version_label = format_version(version_item.version)
|
||||
is_hero = version_item.version < 0
|
||||
is_latest = version_item.is_latest
|
||||
if not is_latest:
|
||||
# TODO maybe use different colors for last approved and last
|
||||
# version? Or don't care about color at all?
|
||||
if not is_latest and not version_item.is_last_approved:
|
||||
version_color = self.OUTDATED_COLOR
|
||||
status_name = version_item.status
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ import collections
|
|||
|
||||
import ayon_api
|
||||
from ayon_api.graphql import GraphQlQuery
|
||||
|
||||
from ayon_core.host import ILoadHost
|
||||
from ayon_core.tools.common_models.projects import StatusStates
|
||||
|
||||
|
||||
# --- Implementation that should be in ayon-python-api ---
|
||||
|
|
@ -149,26 +151,35 @@ class RepresentationInfo:
|
|||
|
||||
|
||||
class VersionItem:
|
||||
def __init__(self, version_id, product_id, version, status, is_latest):
|
||||
self.version = version
|
||||
self.version_id = version_id
|
||||
self.product_id = product_id
|
||||
self.version = version
|
||||
self.status = status
|
||||
self.is_latest = is_latest
|
||||
def __init__(
|
||||
self,
|
||||
version_id: str,
|
||||
product_id: str,
|
||||
version: int,
|
||||
status: str,
|
||||
is_latest: bool,
|
||||
is_last_approved: bool,
|
||||
):
|
||||
self.version_id: str = version_id
|
||||
self.product_id: str = product_id
|
||||
self.version: int = version
|
||||
self.status: str = status
|
||||
self.is_latest: bool = is_latest
|
||||
self.is_last_approved: bool = is_last_approved
|
||||
|
||||
@property
|
||||
def is_hero(self):
|
||||
return self.version < 0
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, version_entity, is_latest):
|
||||
def from_entity(cls, version_entity, is_latest, is_last_approved):
|
||||
return cls(
|
||||
version_id=version_entity["id"],
|
||||
product_id=version_entity["productId"],
|
||||
version=version_entity["version"],
|
||||
status=version_entity["status"],
|
||||
is_latest=is_latest,
|
||||
is_last_approved=is_last_approved,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -275,6 +286,11 @@ class ContainersModel:
|
|||
if product_id not in self._version_items_by_product_id
|
||||
}
|
||||
if missing_ids:
|
||||
status_items_by_name = {
|
||||
status_item.name: status_item
|
||||
for status_item in self._controller.get_project_status_items()
|
||||
}
|
||||
|
||||
def version_sorted(entity):
|
||||
return entity["version"]
|
||||
|
||||
|
|
@ -300,9 +316,21 @@ class ContainersModel:
|
|||
version_entities_by_product_id.items()
|
||||
):
|
||||
last_version = abs(version_entities[-1]["version"])
|
||||
last_approved_id = None
|
||||
for version_entity in version_entities:
|
||||
status_item = status_items_by_name.get(
|
||||
version_entity["status"]
|
||||
)
|
||||
if status_item is None:
|
||||
continue
|
||||
if status_item.state == StatusStates.done:
|
||||
last_approved_id = version_entity["id"]
|
||||
|
||||
version_items_by_id = {
|
||||
entity["id"]: VersionItem.from_entity(
|
||||
entity, abs(entity["version"]) == last_version
|
||||
entity,
|
||||
abs(entity["version"]) == last_version,
|
||||
entity["id"] == last_approved_id
|
||||
)
|
||||
for entity in version_entities
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,19 +233,38 @@ class SceneInventoryView(QtWidgets.QTreeView):
|
|||
has_outdated = False
|
||||
has_loaded_hero_versions = False
|
||||
has_available_hero_version = False
|
||||
for version_items_by_id in version_items_by_product_id.values():
|
||||
has_outdated_approved = False
|
||||
last_version_by_product_id = {}
|
||||
for product_id, version_items_by_id in (
|
||||
version_items_by_product_id.items()
|
||||
):
|
||||
_has_outdated_approved = False
|
||||
_last_approved_version_item = None
|
||||
for version_item in version_items_by_id.values():
|
||||
if version_item.is_hero:
|
||||
has_available_hero_version = True
|
||||
|
||||
elif version_item.is_last_approved:
|
||||
_last_approved_version_item = version_item
|
||||
_has_outdated_approved = True
|
||||
|
||||
if version_item.version_id not in version_ids:
|
||||
continue
|
||||
|
||||
if version_item.is_hero:
|
||||
has_loaded_hero_versions = True
|
||||
|
||||
elif not version_item.is_latest:
|
||||
has_outdated = True
|
||||
|
||||
if (
|
||||
_has_outdated_approved
|
||||
and _last_approved_version_item is not None
|
||||
):
|
||||
last_version_by_product_id[product_id] = (
|
||||
_last_approved_version_item
|
||||
)
|
||||
has_outdated_approved = True
|
||||
|
||||
switch_to_versioned = None
|
||||
if has_loaded_hero_versions:
|
||||
update_icon = qtawesome.icon(
|
||||
|
|
@ -261,6 +280,42 @@ class SceneInventoryView(QtWidgets.QTreeView):
|
|||
lambda: self._on_switch_to_versioned(item_ids)
|
||||
)
|
||||
|
||||
update_to_last_approved_action = None
|
||||
approved_version_by_item_id = {}
|
||||
if has_outdated_approved:
|
||||
for container_item in container_items_by_id.values():
|
||||
repre_id = container_item.representation_id
|
||||
repre_info = repre_info_by_id.get(repre_id)
|
||||
if not repre_info or not repre_info.is_valid:
|
||||
continue
|
||||
version_item = last_version_by_product_id.get(
|
||||
repre_info.product_id
|
||||
)
|
||||
if (
|
||||
version_item is None
|
||||
or version_item.version_id == repre_info.version_id
|
||||
):
|
||||
continue
|
||||
approved_version_by_item_id[container_item.item_id] = (
|
||||
version_item.version
|
||||
)
|
||||
|
||||
if approved_version_by_item_id:
|
||||
update_icon = qtawesome.icon(
|
||||
"fa.angle-double-up",
|
||||
color="#00f0b4"
|
||||
)
|
||||
update_to_last_approved_action = QtWidgets.QAction(
|
||||
update_icon,
|
||||
"Update to last approved",
|
||||
menu
|
||||
)
|
||||
update_to_last_approved_action.triggered.connect(
|
||||
lambda: self._update_containers_to_approved_versions(
|
||||
approved_version_by_item_id
|
||||
)
|
||||
)
|
||||
|
||||
update_to_latest_action = None
|
||||
if has_outdated or has_loaded_hero_versions:
|
||||
update_icon = qtawesome.icon(
|
||||
|
|
@ -299,7 +354,9 @@ class SceneInventoryView(QtWidgets.QTreeView):
|
|||
# set version
|
||||
set_version_action = None
|
||||
if active_repre_id is not None:
|
||||
set_version_icon = qtawesome.icon("fa.hashtag", color=DEFAULT_COLOR)
|
||||
set_version_icon = qtawesome.icon(
|
||||
"fa.hashtag", color=DEFAULT_COLOR
|
||||
)
|
||||
set_version_action = QtWidgets.QAction(
|
||||
set_version_icon,
|
||||
"Set version",
|
||||
|
|
@ -323,6 +380,9 @@ class SceneInventoryView(QtWidgets.QTreeView):
|
|||
if switch_to_versioned:
|
||||
menu.addAction(switch_to_versioned)
|
||||
|
||||
if update_to_last_approved_action:
|
||||
menu.addAction(update_to_last_approved_action)
|
||||
|
||||
if update_to_latest_action:
|
||||
menu.addAction(update_to_latest_action)
|
||||
|
||||
|
|
@ -970,3 +1030,24 @@ class SceneInventoryView(QtWidgets.QTreeView):
|
|||
"""
|
||||
versions = [version for _ in range(len(item_ids))]
|
||||
self._update_containers(item_ids, versions)
|
||||
|
||||
def _update_containers_to_approved_versions(
|
||||
self, approved_version_by_item_id
|
||||
):
|
||||
"""Helper to update items to given version (or version per item)
|
||||
|
||||
If at least one item is specified this will always try to refresh
|
||||
the inventory even if errors occurred on any of the items.
|
||||
|
||||
Arguments:
|
||||
approved_version_by_item_id (Dict[str, int]): Version to set by
|
||||
item id.
|
||||
|
||||
"""
|
||||
versions = []
|
||||
item_ids = []
|
||||
for item_id, version in approved_version_by_item_id.items():
|
||||
item_ids.append(item_id)
|
||||
versions.append(version)
|
||||
|
||||
self._update_containers(item_ids, versions)
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@ from .pipeline import (
|
|||
containerise
|
||||
)
|
||||
|
||||
from .plugin import (
|
||||
Creator,
|
||||
)
|
||||
|
||||
from .lib import (
|
||||
lsattr,
|
||||
lsattrs,
|
||||
|
|
@ -23,8 +19,6 @@ __all__ = [
|
|||
"ls",
|
||||
"containerise",
|
||||
|
||||
"Creator",
|
||||
|
||||
# Utility functions
|
||||
"lsattr",
|
||||
"lsattrs",
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ import hou
|
|||
import pyblish.api
|
||||
from ayon_core.pipeline import (
|
||||
CreatorError,
|
||||
LegacyCreator,
|
||||
Creator as NewCreator,
|
||||
Creator,
|
||||
CreatedInstance,
|
||||
AYON_INSTANCE_ID,
|
||||
AVALON_INSTANCE_ID,
|
||||
|
|
@ -26,80 +25,6 @@ from .lib import imprint, read, lsattr, add_self_publish_button
|
|||
SETTINGS_CATEGORY = "houdini"
|
||||
|
||||
|
||||
class Creator(LegacyCreator):
|
||||
"""Creator plugin to create instances in Houdini
|
||||
|
||||
To support the wide range of node types for render output (Alembic, VDB,
|
||||
Mantra) the Creator needs a node type to create the correct instance
|
||||
|
||||
By default, if none is given, is `geometry`. An example of accepted node
|
||||
types: geometry, alembic, ifd (mantra)
|
||||
|
||||
Please check the Houdini documentation for more node types.
|
||||
|
||||
Tip: to find the exact node type to create press the `i` left of the node
|
||||
when hovering over a node. The information is visible under the name of
|
||||
the node.
|
||||
|
||||
Deprecated:
|
||||
This creator is deprecated and will be removed in future version.
|
||||
|
||||
"""
|
||||
defaults = ['Main']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Creator, self).__init__(*args, **kwargs)
|
||||
self.nodes = []
|
||||
|
||||
def process(self):
|
||||
"""This is the base functionality to create instances in Houdini
|
||||
|
||||
The selected nodes are stored in self to be used in an override method.
|
||||
This is currently necessary in order to support the multiple output
|
||||
types in Houdini which can only be rendered through their own node.
|
||||
|
||||
Default node type if none is given is `geometry`
|
||||
|
||||
It also makes it easier to apply custom settings per instance type
|
||||
|
||||
Example of override method for Alembic:
|
||||
|
||||
def process(self):
|
||||
instance = super(CreateEpicNode, self, process()
|
||||
# Set parameters for Alembic node
|
||||
instance.setParms(
|
||||
{"sop_path": "$HIP/%s.abc" % self.nodes[0]}
|
||||
)
|
||||
|
||||
Returns:
|
||||
hou.Node
|
||||
|
||||
"""
|
||||
try:
|
||||
if (self.options or {}).get("useSelection"):
|
||||
self.nodes = hou.selectedNodes()
|
||||
|
||||
# Get the node type and remove it from the data, not needed
|
||||
node_type = self.data.pop("node_type", None)
|
||||
if node_type is None:
|
||||
node_type = "geometry"
|
||||
|
||||
# Get out node
|
||||
out = hou.node("/out")
|
||||
instance = out.createNode(node_type, node_name=self.name)
|
||||
instance.moveToGoodPosition()
|
||||
|
||||
imprint(instance, self.data)
|
||||
|
||||
self._process(instance)
|
||||
|
||||
except hou.Error as er:
|
||||
six.reraise(
|
||||
CreatorError,
|
||||
CreatorError("Creator error: {}".format(er)),
|
||||
sys.exc_info()[2])
|
||||
|
||||
|
||||
class HoudiniCreatorBase(object):
|
||||
@staticmethod
|
||||
def cache_instance_data(shared_data):
|
||||
|
|
@ -175,7 +100,7 @@ class HoudiniCreatorBase(object):
|
|||
|
||||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class HoudiniCreator(NewCreator, HoudiniCreatorBase):
|
||||
class HoudiniCreator(Creator, HoudiniCreatorBase):
|
||||
"""Base class for most of the Houdini creator plugins."""
|
||||
selected_nodes = []
|
||||
settings_name = None
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Package declaring AYON addon 'houdini' version."""
|
||||
__version__ = "0.3.4"
|
||||
__version__ = "0.3.5"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
name = "houdini"
|
||||
title = "Houdini"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
|
||||
client_dir = "ayon_houdini"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue