diff --git a/pype/api.py b/pype/api.py
index 5775bb3ce4..44a31f2626 100644
--- a/pype/api.py
+++ b/pype/api.py
@@ -12,6 +12,8 @@ from pypeapp.lib.mongo import (
get_default_components
)
+from . import resources
+
from .plugin import (
Extractor,
@@ -54,6 +56,8 @@ __all__ = [
"compose_url",
"get_default_components",
+ # Resources
+ "resources",
# plugin classes
"Extractor",
# ordering
diff --git a/pype/modules/ftrack/ftrack_server/lib.py b/pype/modules/ftrack/ftrack_server/lib.py
index 327fab817d..8377187ebe 100644
--- a/pype/modules/ftrack/ftrack_server/lib.py
+++ b/pype/modules/ftrack/ftrack_server/lib.py
@@ -51,9 +51,10 @@ def get_ftrack_event_mongo_info():
if not _used_ftrack_url or components["database"] is None:
components["database"] = database_name
- components["collection"] = collection_name
- uri = compose_url(components)
+ components.pop("collection", None)
+
+ uri = compose_url(**components)
return uri, components["port"], database_name, collection_name
diff --git a/pype/modules/ftrack/tray/login_tools.py b/pype/modules/ftrack/tray/login_tools.py
index b259f2d2ed..02982294f2 100644
--- a/pype/modules/ftrack/tray/login_tools.py
+++ b/pype/modules/ftrack/tray/login_tools.py
@@ -1,16 +1,16 @@
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib import parse
-import os
import webbrowser
import functools
-import pype
-import inspect
from Qt import QtCore
+from pype.api import resources
class LoginServerHandler(BaseHTTPRequestHandler):
'''Login server handler.'''
+ message_filepath = resources.get_resource("ftrack", "sign_in_message.html")
+
def __init__(self, login_callback, *args, **kw):
'''Initialise handler.'''
self.login_callback = login_callback
@@ -28,23 +28,21 @@ class LoginServerHandler(BaseHTTPRequestHandler):
login_credentials = parse.parse_qs(query)
api_user = login_credentials['api_user'][0]
api_key = login_credentials['api_key'][0]
- # get path to resources
- path_items = os.path.dirname(
- inspect.getfile(pype)
- ).split(os.path.sep)
- del path_items[-1]
- path_items.extend(['res', 'ftrack', 'sign_in_message.html'])
- message_filepath = os.path.sep.join(path_items)
- message_file = open(message_filepath, 'r')
- sign_in_message = message_file.read()
- message_file.close()
+
+ with open(self.message_filepath, "r") as message_file:
+ sign_in_message = message_file.read()
+
# formatting html code for python
- replacement = [('{', '{{'), ('}', '}}'), ('{{}}', '{}')]
- for r in (replacement):
- sign_in_message = sign_in_message.replace(*r)
+ replacements = (
+ ("{", "{{"),
+ ("}", "}}"),
+ ("{{}}", "{}")
+ )
+ for replacement in (replacements):
+ sign_in_message = sign_in_message.replace(*replacement)
message = sign_in_message.format(api_user)
else:
- message = '
Failed to sign in
'
+ message = "Failed to sign in
"
self.send_response(200)
self.end_headers()
@@ -74,7 +72,6 @@ class LoginServerThread(QtCore.QThread):
def run(self):
'''Listen for events.'''
- # self._server = BaseHTTPServer.HTTPServer(
self._server = HTTPServer(
('localhost', 0),
functools.partial(
diff --git a/pype/modules/rest_api/rest_api.py b/pype/modules/rest_api/rest_api.py
index 81763e8b9f..cc98b56a3b 100644
--- a/pype/modules/rest_api/rest_api.py
+++ b/pype/modules/rest_api/rest_api.py
@@ -96,7 +96,11 @@ class RestApiServer:
port = self.find_port()
self.rest_api_thread = RestApiThread(self, port)
- statics_dir = os.path.sep.join([os.environ["PYPE_MODULE_ROOT"], "res"])
+ statics_dir = os.path.join(
+ os.environ["PYPE_MODULE_ROOT"],
+ "pype",
+ "resources"
+ )
self.register_statics("/res", statics_dir)
os.environ["PYPE_STATICS_SERVER"] = "{}/res".format(
os.environ["PYPE_REST_API_URL"]
diff --git a/pype/plugins/blender/create/create_camera.py b/pype/plugins/blender/create/create_camera.py
new file mode 100644
index 0000000000..5817985053
--- /dev/null
+++ b/pype/plugins/blender/create/create_camera.py
@@ -0,0 +1,32 @@
+"""Create a camera asset."""
+
+import bpy
+
+from avalon import api
+from avalon.blender import Creator, lib
+import pype.hosts.blender.plugin
+
+
+class CreateCamera(Creator):
+ """Polygonal static geometry"""
+
+ name = "cameraMain"
+ label = "Camera"
+ family = "camera"
+ icon = "video-camera"
+
+ def process(self):
+
+ asset = self.data["asset"]
+ subset = self.data["subset"]
+ name = pype.hosts.blender.plugin.asset_name(asset, subset)
+ collection = bpy.data.collections.new(name=name)
+ bpy.context.scene.collection.children.link(collection)
+ self.data['task'] = api.Session.get('AVALON_TASK')
+ lib.imprint(collection, self.data)
+
+ if (self.options or {}).get("useSelection"):
+ for obj in lib.get_selection():
+ collection.objects.link(obj)
+
+ return collection
diff --git a/pype/plugins/blender/load/load_camera.py b/pype/plugins/blender/load/load_camera.py
new file mode 100644
index 0000000000..7fd8f94b4e
--- /dev/null
+++ b/pype/plugins/blender/load/load_camera.py
@@ -0,0 +1,239 @@
+"""Load a camera asset in Blender."""
+
+import logging
+from pathlib import Path
+from pprint import pformat
+from typing import Dict, List, Optional
+
+from avalon import api, blender
+import bpy
+import pype.hosts.blender.plugin
+
+logger = logging.getLogger("pype").getChild("blender").getChild("load_camera")
+
+
+class BlendCameraLoader(pype.hosts.blender.plugin.AssetLoader):
+ """Load a camera from a .blend file.
+
+ Warning:
+ Loading the same asset more then once is not properly supported at the
+ moment.
+ """
+
+ families = ["camera"]
+ representations = ["blend"]
+
+ label = "Link Camera"
+ icon = "code-fork"
+ color = "orange"
+
+ def _remove(self, objects, lib_container):
+
+ for obj in objects:
+ bpy.data.cameras.remove(obj.data)
+
+ bpy.data.collections.remove(bpy.data.collections[lib_container])
+
+ def _process(self, libpath, lib_container, container_name, actions):
+
+ relative = bpy.context.preferences.filepaths.use_relative_paths
+ with bpy.data.libraries.load(
+ libpath, link=True, relative=relative
+ ) as (_, data_to):
+ data_to.collections = [lib_container]
+
+ scene = bpy.context.scene
+
+ scene.collection.children.link(bpy.data.collections[lib_container])
+
+ camera_container = scene.collection.children[lib_container].make_local()
+
+ objects_list = []
+
+ for obj in camera_container.objects:
+ obj = obj.make_local()
+ obj.data.make_local()
+
+ if not obj.get(blender.pipeline.AVALON_PROPERTY):
+ obj[blender.pipeline.AVALON_PROPERTY] = dict()
+
+ avalon_info = obj[blender.pipeline.AVALON_PROPERTY]
+ avalon_info.update({"container_name": container_name})
+
+ if actions[0] is not None:
+ if obj.animation_data is None:
+ obj.animation_data_create()
+ obj.animation_data.action = actions[0]
+
+ if actions[1] is not None:
+ if obj.data.animation_data is None:
+ obj.data.animation_data_create()
+ obj.data.animation_data.action = actions[1]
+
+ objects_list.append(obj)
+
+ camera_container.pop(blender.pipeline.AVALON_PROPERTY)
+
+ bpy.ops.object.select_all(action='DESELECT')
+
+ return objects_list
+
+ def process_asset(
+ self, context: dict, name: str, namespace: Optional[str] = None,
+ options: Optional[Dict] = None
+ ) -> Optional[List]:
+ """
+ Arguments:
+ name: Use pre-defined name
+ namespace: Use pre-defined namespace
+ context: Full parenthood of representation to load
+ options: Additional settings dictionary
+ """
+
+ libpath = self.fname
+ asset = context["asset"]["name"]
+ subset = context["subset"]["name"]
+ lib_container = pype.hosts.blender.plugin.asset_name(asset, subset)
+ container_name = pype.hosts.blender.plugin.asset_name(
+ asset, subset, namespace
+ )
+
+ container = bpy.data.collections.new(lib_container)
+ container.name = container_name
+ blender.pipeline.containerise_existing(
+ container,
+ name,
+ namespace,
+ context,
+ self.__class__.__name__,
+ )
+
+ container_metadata = container.get(
+ blender.pipeline.AVALON_PROPERTY)
+
+ container_metadata["libpath"] = libpath
+ container_metadata["lib_container"] = lib_container
+
+ objects_list = self._process(
+ libpath, lib_container, container_name, (None, None))
+
+ # Save the list of objects in the metadata container
+ container_metadata["objects"] = objects_list
+
+ nodes = list(container.objects)
+ nodes.append(container)
+ self[:] = nodes
+ return nodes
+
+ def update(self, container: Dict, representation: Dict):
+ """Update the loaded asset.
+
+ This will remove all objects of the current collection, load the new
+ ones and add them to the collection.
+ If the objects of the collection are used in another collection they
+ will not be removed, only unlinked. Normally this should not be the
+ case though.
+
+ Warning:
+ No nested collections are supported at the moment!
+ """
+
+ collection = bpy.data.collections.get(
+ container["objectName"]
+ )
+
+ libpath = Path(api.get_representation_path(representation))
+ extension = libpath.suffix.lower()
+
+ logger.info(
+ "Container: %s\nRepresentation: %s",
+ pformat(container, indent=2),
+ pformat(representation, indent=2),
+ )
+
+ assert collection, (
+ f"The asset is not loaded: {container['objectName']}"
+ )
+ assert not (collection.children), (
+ "Nested collections are not supported."
+ )
+ assert libpath, (
+ "No existing library file found for {container['objectName']}"
+ )
+ assert libpath.is_file(), (
+ f"The file doesn't exist: {libpath}"
+ )
+ assert extension in pype.hosts.blender.plugin.VALID_EXTENSIONS, (
+ f"Unsupported file: {libpath}"
+ )
+
+ collection_metadata = collection.get(
+ blender.pipeline.AVALON_PROPERTY)
+ collection_libpath = collection_metadata["libpath"]
+ objects = collection_metadata["objects"]
+ lib_container = collection_metadata["lib_container"]
+
+ normalized_collection_libpath = (
+ str(Path(bpy.path.abspath(collection_libpath)).resolve())
+ )
+ normalized_libpath = (
+ str(Path(bpy.path.abspath(str(libpath))).resolve())
+ )
+ logger.debug(
+ "normalized_collection_libpath:\n %s\nnormalized_libpath:\n %s",
+ normalized_collection_libpath,
+ normalized_libpath,
+ )
+ if normalized_collection_libpath == normalized_libpath:
+ logger.info("Library already loaded, not updating...")
+ return
+
+ camera = objects[0]
+
+ actions = (camera.animation_data.action, camera.data.animation_data.action)
+
+ self._remove(objects, lib_container)
+
+ objects_list = self._process(
+ str(libpath), lib_container, collection.name, actions)
+
+ # Save the list of objects in the metadata container
+ collection_metadata["objects"] = objects_list
+ collection_metadata["libpath"] = str(libpath)
+ collection_metadata["representation"] = str(representation["_id"])
+
+ bpy.ops.object.select_all(action='DESELECT')
+
+ def remove(self, container: Dict) -> bool:
+ """Remove an existing container from a Blender scene.
+
+ Arguments:
+ container (avalon-core:container-1.0): Container to remove,
+ from `host.ls()`.
+
+ Returns:
+ bool: Whether the container was deleted.
+
+ Warning:
+ No nested collections are supported at the moment!
+ """
+
+ collection = bpy.data.collections.get(
+ container["objectName"]
+ )
+ if not collection:
+ return False
+ assert not (collection.children), (
+ "Nested collections are not supported."
+ )
+
+ collection_metadata = collection.get(
+ blender.pipeline.AVALON_PROPERTY)
+ objects = collection_metadata["objects"]
+ lib_container = collection_metadata["lib_container"]
+
+ self._remove(objects, lib_container)
+
+ bpy.data.collections.remove(collection)
+
+ return True
diff --git a/pype/plugins/blender/publish/extract_blend.py b/pype/plugins/blender/publish/extract_blend.py
index 0924763f12..a5e76dcf4e 100644
--- a/pype/plugins/blender/publish/extract_blend.py
+++ b/pype/plugins/blender/publish/extract_blend.py
@@ -9,7 +9,7 @@ class ExtractBlend(pype.api.Extractor):
label = "Extract Blend"
hosts = ["blender"]
- families = ["animation", "model", "rig", "action", "layout"]
+ families = ["model", "camera", "rig", "action", "layout", "animation"]
optional = True
def process(self, instance):
diff --git a/res/app_icons/Aport.png b/pype/resources/app_icons/Aport.png
similarity index 100%
rename from res/app_icons/Aport.png
rename to pype/resources/app_icons/Aport.png
diff --git a/res/app_icons/blender.png b/pype/resources/app_icons/blender.png
similarity index 100%
rename from res/app_icons/blender.png
rename to pype/resources/app_icons/blender.png
diff --git a/res/app_icons/celaction_local.png b/pype/resources/app_icons/celaction_local.png
similarity index 100%
rename from res/app_icons/celaction_local.png
rename to pype/resources/app_icons/celaction_local.png
diff --git a/res/app_icons/celaction_remotel.png b/pype/resources/app_icons/celaction_remotel.png
similarity index 100%
rename from res/app_icons/celaction_remotel.png
rename to pype/resources/app_icons/celaction_remotel.png
diff --git a/res/app_icons/clockify-white.png b/pype/resources/app_icons/clockify-white.png
similarity index 100%
rename from res/app_icons/clockify-white.png
rename to pype/resources/app_icons/clockify-white.png
diff --git a/res/app_icons/clockify.png b/pype/resources/app_icons/clockify.png
similarity index 100%
rename from res/app_icons/clockify.png
rename to pype/resources/app_icons/clockify.png
diff --git a/res/app_icons/djvView.png b/pype/resources/app_icons/djvView.png
similarity index 100%
rename from res/app_icons/djvView.png
rename to pype/resources/app_icons/djvView.png
diff --git a/res/app_icons/harmony.png b/pype/resources/app_icons/harmony.png
similarity index 100%
rename from res/app_icons/harmony.png
rename to pype/resources/app_icons/harmony.png
diff --git a/res/app_icons/houdini.png b/pype/resources/app_icons/houdini.png
similarity index 100%
rename from res/app_icons/houdini.png
rename to pype/resources/app_icons/houdini.png
diff --git a/res/app_icons/maya.png b/pype/resources/app_icons/maya.png
similarity index 100%
rename from res/app_icons/maya.png
rename to pype/resources/app_icons/maya.png
diff --git a/res/app_icons/nuke.png b/pype/resources/app_icons/nuke.png
similarity index 100%
rename from res/app_icons/nuke.png
rename to pype/resources/app_icons/nuke.png
diff --git a/res/app_icons/nukex.png b/pype/resources/app_icons/nukex.png
similarity index 100%
rename from res/app_icons/nukex.png
rename to pype/resources/app_icons/nukex.png
diff --git a/res/app_icons/photoshop.png b/pype/resources/app_icons/photoshop.png
similarity index 100%
rename from res/app_icons/photoshop.png
rename to pype/resources/app_icons/photoshop.png
diff --git a/res/app_icons/premiere.png b/pype/resources/app_icons/premiere.png
similarity index 100%
rename from res/app_icons/premiere.png
rename to pype/resources/app_icons/premiere.png
diff --git a/res/app_icons/python.png b/pype/resources/app_icons/python.png
similarity index 100%
rename from res/app_icons/python.png
rename to pype/resources/app_icons/python.png
diff --git a/res/app_icons/resolve.png b/pype/resources/app_icons/resolve.png
similarity index 100%
rename from res/app_icons/resolve.png
rename to pype/resources/app_icons/resolve.png
diff --git a/res/app_icons/storyboardpro.png b/pype/resources/app_icons/storyboardpro.png
similarity index 100%
rename from res/app_icons/storyboardpro.png
rename to pype/resources/app_icons/storyboardpro.png
diff --git a/res/app_icons/ue4.png b/pype/resources/app_icons/ue4.png
similarity index 100%
rename from res/app_icons/ue4.png
rename to pype/resources/app_icons/ue4.png
diff --git a/res/ftrack/action_icons/ActionAskWhereIRun.svg b/pype/resources/ftrack/action_icons/ActionAskWhereIRun.svg
similarity index 100%
rename from res/ftrack/action_icons/ActionAskWhereIRun.svg
rename to pype/resources/ftrack/action_icons/ActionAskWhereIRun.svg
diff --git a/res/ftrack/action_icons/AssetsRemover.svg b/pype/resources/ftrack/action_icons/AssetsRemover.svg
similarity index 100%
rename from res/ftrack/action_icons/AssetsRemover.svg
rename to pype/resources/ftrack/action_icons/AssetsRemover.svg
diff --git a/res/ftrack/action_icons/ComponentOpen.svg b/pype/resources/ftrack/action_icons/ComponentOpen.svg
similarity index 100%
rename from res/ftrack/action_icons/ComponentOpen.svg
rename to pype/resources/ftrack/action_icons/ComponentOpen.svg
diff --git a/res/ftrack/action_icons/CreateFolders.svg b/pype/resources/ftrack/action_icons/CreateFolders.svg
similarity index 100%
rename from res/ftrack/action_icons/CreateFolders.svg
rename to pype/resources/ftrack/action_icons/CreateFolders.svg
diff --git a/res/ftrack/action_icons/CreateProjectFolders.svg b/pype/resources/ftrack/action_icons/CreateProjectFolders.svg
similarity index 100%
rename from res/ftrack/action_icons/CreateProjectFolders.svg
rename to pype/resources/ftrack/action_icons/CreateProjectFolders.svg
diff --git a/res/ftrack/action_icons/DeleteAsset.svg b/pype/resources/ftrack/action_icons/DeleteAsset.svg
similarity index 100%
rename from res/ftrack/action_icons/DeleteAsset.svg
rename to pype/resources/ftrack/action_icons/DeleteAsset.svg
diff --git a/res/ftrack/action_icons/Delivery.svg b/pype/resources/ftrack/action_icons/Delivery.svg
similarity index 100%
rename from res/ftrack/action_icons/Delivery.svg
rename to pype/resources/ftrack/action_icons/Delivery.svg
diff --git a/res/ftrack/action_icons/MultipleNotes.svg b/pype/resources/ftrack/action_icons/MultipleNotes.svg
similarity index 100%
rename from res/ftrack/action_icons/MultipleNotes.svg
rename to pype/resources/ftrack/action_icons/MultipleNotes.svg
diff --git a/res/ftrack/action_icons/PrepareProject.svg b/pype/resources/ftrack/action_icons/PrepareProject.svg
similarity index 100%
rename from res/ftrack/action_icons/PrepareProject.svg
rename to pype/resources/ftrack/action_icons/PrepareProject.svg
diff --git a/res/ftrack/action_icons/PypeAdmin.svg b/pype/resources/ftrack/action_icons/PypeAdmin.svg
similarity index 100%
rename from res/ftrack/action_icons/PypeAdmin.svg
rename to pype/resources/ftrack/action_icons/PypeAdmin.svg
diff --git a/res/ftrack/action_icons/PypeDoctor.svg b/pype/resources/ftrack/action_icons/PypeDoctor.svg
similarity index 100%
rename from res/ftrack/action_icons/PypeDoctor.svg
rename to pype/resources/ftrack/action_icons/PypeDoctor.svg
diff --git a/res/ftrack/action_icons/PypeUpdate.svg b/pype/resources/ftrack/action_icons/PypeUpdate.svg
similarity index 100%
rename from res/ftrack/action_icons/PypeUpdate.svg
rename to pype/resources/ftrack/action_icons/PypeUpdate.svg
diff --git a/res/ftrack/action_icons/RV.png b/pype/resources/ftrack/action_icons/RV.png
similarity index 100%
rename from res/ftrack/action_icons/RV.png
rename to pype/resources/ftrack/action_icons/RV.png
diff --git a/res/ftrack/action_icons/SeedProject.svg b/pype/resources/ftrack/action_icons/SeedProject.svg
similarity index 100%
rename from res/ftrack/action_icons/SeedProject.svg
rename to pype/resources/ftrack/action_icons/SeedProject.svg
diff --git a/res/ftrack/action_icons/SyncHierarchicalAttrs.svg b/pype/resources/ftrack/action_icons/SyncHierarchicalAttrs.svg
similarity index 100%
rename from res/ftrack/action_icons/SyncHierarchicalAttrs.svg
rename to pype/resources/ftrack/action_icons/SyncHierarchicalAttrs.svg
diff --git a/res/ftrack/action_icons/SyncToAvalon.svg b/pype/resources/ftrack/action_icons/SyncToAvalon.svg
similarity index 100%
rename from res/ftrack/action_icons/SyncToAvalon.svg
rename to pype/resources/ftrack/action_icons/SyncToAvalon.svg
diff --git a/res/ftrack/action_icons/TestAction.svg b/pype/resources/ftrack/action_icons/TestAction.svg
similarity index 100%
rename from res/ftrack/action_icons/TestAction.svg
rename to pype/resources/ftrack/action_icons/TestAction.svg
diff --git a/res/ftrack/action_icons/Thumbnail.svg b/pype/resources/ftrack/action_icons/Thumbnail.svg
similarity index 100%
rename from res/ftrack/action_icons/Thumbnail.svg
rename to pype/resources/ftrack/action_icons/Thumbnail.svg
diff --git a/res/ftrack/sign_in_message.html b/pype/resources/ftrack/sign_in_message.html
similarity index 100%
rename from res/ftrack/sign_in_message.html
rename to pype/resources/ftrack/sign_in_message.html
diff --git a/pype/tools/tray/modules_imports.json b/pype/tools/tray/modules_imports.json
new file mode 100644
index 0000000000..e9526dcddb
--- /dev/null
+++ b/pype/tools/tray/modules_imports.json
@@ -0,0 +1,58 @@
+[
+ {
+ "title": "User settings",
+ "type": "module",
+ "import_path": "pype.modules.user",
+ "fromlist": ["pype", "modules"]
+ }, {
+ "title": "Ftrack",
+ "type": "module",
+ "import_path": "pype.modules.ftrack.tray",
+ "fromlist": ["pype", "modules", "ftrack"]
+ }, {
+ "title": "Muster",
+ "type": "module",
+ "import_path": "pype.modules.muster",
+ "fromlist": ["pype", "modules"]
+ }, {
+ "title": "Avalon",
+ "type": "module",
+ "import_path": "pype.modules.avalon_apps",
+ "fromlist": ["pype", "modules"]
+ }, {
+ "title": "Clockify",
+ "type": "module",
+ "import_path": "pype.modules.clockify",
+ "fromlist": ["pype", "modules"]
+ }, {
+ "title": "Standalone Publish",
+ "type": "module",
+ "import_path": "pype.modules.standalonepublish",
+ "fromlist": ["pype", "modules"]
+ }, {
+ "title": "Logging",
+ "type": "module",
+ "import_path": "pype.modules.logging.tray",
+ "fromlist": ["pype", "modules", "logging"]
+ }, {
+ "title": "Idle Manager",
+ "type": "module",
+ "import_path": "pype.modules.idle_manager",
+ "fromlist": ["pype","modules"]
+ }, {
+ "title": "Timers Manager",
+ "type": "module",
+ "import_path": "pype.modules.timers_manager",
+ "fromlist": ["pype","modules"]
+ }, {
+ "title": "Rest Api",
+ "type": "module",
+ "import_path": "pype.modules.rest_api",
+ "fromlist": ["pype","modules"]
+ }, {
+ "title": "Adobe Communicator",
+ "type": "module",
+ "import_path": "pype.modules.adobe_communicator",
+ "fromlist": ["pype", "modules"]
+ }
+]
diff --git a/pype/tools/tray/pype_tray.py b/pype/tools/tray/pype_tray.py
index 5b7188495f..468a02c62e 100644
--- a/pype/tools/tray/pype_tray.py
+++ b/pype/tools/tray/pype_tray.py
@@ -12,28 +12,34 @@ class TrayManager:
Load submenus, actions, separators and modules into tray's context.
"""
- modules = {}
- services = {}
- services_submenu = None
-
- errors = []
- items = (
- config.get_presets(first_run=True)
- .get('tray', {})
- .get('menu_items', [])
- )
- available_sourcetypes = ['python', 'file']
+ available_sourcetypes = ["python", "file"]
def __init__(self, tray_widget, main_window):
self.tray_widget = tray_widget
self.main_window = main_window
+
self.log = Logger().get_logger(self.__class__.__name__)
- self.icon_run = QtGui.QIcon(get_resource('circle_green.png'))
- self.icon_stay = QtGui.QIcon(get_resource('circle_orange.png'))
- self.icon_failed = QtGui.QIcon(get_resource('circle_red.png'))
+ self.modules = {}
+ self.services = {}
+ self.services_submenu = None
- self.services_thread = None
+ self.errors = []
+
+ CURRENT_DIR = os.path.dirname(__file__)
+ self.modules_imports = config.load_json(
+ os.path.join(CURRENT_DIR, "modules_imports.json")
+ )
+ presets = config.get_presets(first_run=True)
+ try:
+ self.modules_usage = presets["tray"]["menu_items"]["item_usage"]
+ except Exception:
+ self.modules_usage = {}
+ self.log.critical("Couldn't find modules usage data.")
+
+ self.icon_run = QtGui.QIcon(get_resource("circle_green.png"))
+ self.icon_stay = QtGui.QIcon(get_resource("circle_orange.png"))
+ self.icon_failed = QtGui.QIcon(get_resource("circle_red.png"))
def process_presets(self):
"""Add modules to tray by presets.
@@ -46,21 +52,10 @@ class TrayManager:
"item_usage": {
"Statics Server": false
}
- }, {
- "item_import": [{
- "title": "Ftrack",
- "type": "module",
- "import_path": "pype.ftrack.tray",
- "fromlist": ["pype", "ftrack"]
- }, {
- "title": "Statics Server",
- "type": "module",
- "import_path": "pype.services.statics_server",
- "fromlist": ["pype","services"]
- }]
}
In this case `Statics Server` won't be used.
"""
+
# Backwards compatible presets loading
if isinstance(self.items, list):
items = self.items