Skip to content

action

ApplicationAction

Bases: LauncherAction

Action to launch an application.

Application action based on 'ApplicationManager' system.

Handling of applications in launcher is not ideal and should be completely redone from scratch. This is just a temporary solution to keep backwards compatibility with AYON launcher.

Todos

Move handling of errors to frontend.

Source code in client/ayon_applications/action.py
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
class ApplicationAction(LauncherAction):
    """Action to launch an application.

    Application action based on 'ApplicationManager' system.

    Handling of applications in launcher is not ideal and should be completely
    redone from scratch. This is just a temporary solution to keep backwards
    compatibility with AYON launcher.

    Todos:
        Move handling of errors to frontend.
    """

    # Application object
    application = None
    # Action attributes
    name = None
    label = None
    label_variant = None
    group = None
    icon = None
    color = None
    order = 0
    data = {}
    project_settings = {}
    project_entities = {}

    _log = None

    # --- For compatibility for combinations of new and old ayon-core ---
    project_settings_cache = NestedCacheItem(
        levels=1, default_factory=dict, lifetime=20
    )
    project_entities_cache = NestedCacheItem(
        levels=1, default_factory=dict, lifetime=20
    )

    @classmethod
    def _app_get_project_settings(cls, selection):
        project_name = selection.project_name
        if project_name in ApplicationAction.project_settings:
            return ApplicationAction.project_settings[project_name]

        if hasattr(selection, "get_project_settings"):
            return selection.get_project_settings()

        cache = ApplicationAction.project_settings_cache[project_name]
        if not cache.is_valid:
            if project_name:
                settings = get_project_settings(project_name)
            else:
                settings = get_studio_settings()
            cache.update_data(settings)
        return copy.deepcopy(cache.get_data())

    @property
    def log(self):
        if self._log is None:
            self._log = Logger.get_logger(self.__class__.__name__)
        return self._log

    def is_compatible(self, selection):
        if not selection.is_task_selected:
            return False

        project_settings = self._app_get_project_settings(selection)
        apps = get_applications_for_context(
            selection.project_name,
            selection.get_folder_entity(),
            selection.get_task_entity(),
            project_settings=project_settings,
            project_entity=selection.get_project_entity(),
        )
        if self.application.full_name not in apps:
            return False

        only_available = project_settings["applications"]["only_available"]
        if only_available and not self.application.find_executable():
            return False
        return True

    def _show_message_box(self, title, message, details=None):
        from qtpy import QtWidgets, QtGui
        from ayon_core import style

        dialog = QtWidgets.QMessageBox()
        icon = QtGui.QIcon(resources.get_ayon_icon_filepath())
        dialog.setWindowIcon(icon)
        dialog.setStyleSheet(style.load_stylesheet())
        dialog.setWindowTitle(title)
        dialog.setText(message)
        if details:
            dialog.setDetailedText(details)
        dialog.exec_()

    def process(self, selection, **kwargs):
        """Process the full Application action"""
        try:
            self.application.launch(
                project_name=selection.project_name,
                folder_path=selection.folder_path,
                task_name=selection.task_name,
                **self.data
            )

        except ApplicationExecutableNotFound as exc:
            details = exc.details
            msg = exc.msg
            log_msg = str(msg)
            if details:
                log_msg += "\n" + details
            self.log.warning(log_msg)
            self._show_message_box(
                "Application executable not found", msg, details
            )

        except ApplicationLaunchFailed as exc:
            msg = str(exc)
            self.log.warning(msg, exc_info=True)
            self._show_message_box("Application launch failed", msg)

process(selection, **kwargs)

Process the full Application action

Source code in client/ayon_applications/action.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
def process(self, selection, **kwargs):
    """Process the full Application action"""
    try:
        self.application.launch(
            project_name=selection.project_name,
            folder_path=selection.folder_path,
            task_name=selection.task_name,
            **self.data
        )

    except ApplicationExecutableNotFound as exc:
        details = exc.details
        msg = exc.msg
        log_msg = str(msg)
        if details:
            log_msg += "\n" + details
        self.log.warning(log_msg)
        self._show_message_box(
            "Application executable not found", msg, details
        )

    except ApplicationLaunchFailed as exc:
        msg = str(exc)
        self.log.warning(msg, exc_info=True)
        self._show_message_box("Application launch failed", msg)