Merge pull request #2024 from pypeclub/feature/timers_manager_wihtout_interface

TimersManager: Removed interface of timers manager
This commit is contained in:
Jakub Trllo 2021-09-20 17:22:21 +02:00 committed by GitHub
commit 54a273e07f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 218 additions and 94 deletions

View file

@ -11,8 +11,7 @@ from openpype.modules import OpenPypeModule
from openpype_interfaces import (
ITrayModule,
IPluginPaths,
IFtrackEventHandlerPaths,
ITimersManager
IFtrackEventHandlerPaths
)
@ -20,8 +19,7 @@ class ClockifyModule(
OpenPypeModule,
ITrayModule,
IPluginPaths,
IFtrackEventHandlerPaths,
ITimersManager
IFtrackEventHandlerPaths
):
name = "clockify"
@ -39,6 +37,11 @@ class ClockifyModule(
self.clockapi = ClockifyAPI(master_parent=self)
# TimersManager attributes
# - set `timers_manager_connector` only in `tray_init`
self.timers_manager_connector = None
self._timers_manager_module = None
def get_global_environments(self):
return {
"CLOCKIFY_WORKSPACE": self.workspace_name
@ -61,6 +64,9 @@ class ClockifyModule(
self.bool_timer_run = False
self.bool_api_key_set = self.clockapi.set_api()
# Define itself as TimersManager connector
self.timers_manager_connector = self
def tray_start(self):
if self.bool_api_key_set is False:
self.show_settings()
@ -162,10 +168,6 @@ class ClockifyModule(
self.set_menu_visibility()
time.sleep(5)
def stop_timer(self):
"""Implementation of ITimersManager."""
self.clockapi.finish_time_entry()
def signed_in(self):
if not self.timer_manager:
return
@ -176,8 +178,60 @@ class ClockifyModule(
if self.timer_manager.is_running:
self.start_timer_manager(self.timer_manager.last_task)
def on_message_widget_close(self):
self.message_widget = None
# Definition of Tray menu
def tray_menu(self, parent_menu):
# Menu for Tray App
from Qt import QtWidgets
menu = QtWidgets.QMenu("Clockify", parent_menu)
menu.setProperty("submenu", "on")
# Actions
action_show_settings = QtWidgets.QAction("Settings", menu)
action_stop_timer = QtWidgets.QAction("Stop timer", menu)
menu.addAction(action_show_settings)
menu.addAction(action_stop_timer)
action_show_settings.triggered.connect(self.show_settings)
action_stop_timer.triggered.connect(self.stop_timer)
self.action_stop_timer = action_stop_timer
self.set_menu_visibility()
parent_menu.addMenu(menu)
def show_settings(self):
self.widget_settings.input_api_key.setText(self.clockapi.get_api_key())
self.widget_settings.show()
def set_menu_visibility(self):
self.action_stop_timer.setVisible(self.bool_timer_run)
# --- TimersManager connection methods ---
def register_timers_manager(self, timer_manager_module):
"""Store TimersManager for future use."""
self._timers_manager_module = timer_manager_module
def timer_started(self, data):
"""Tell TimersManager that timer started."""
if self._timers_manager_module is not None:
self._timers_manager_module.timer_started(self._module.id, data)
def timer_stopped(self):
"""Tell TimersManager that timer stopped."""
if self._timers_manager_module is not None:
self._timers_manager_module.timer_stopped(self._module.id)
def stop_timer(self):
"""Called from TimersManager to stop timer."""
self.clockapi.finish_time_entry()
def start_timer(self, input_data):
"""Implementation of ITimersManager."""
"""Called from TimersManager to start timer."""
# If not api key is not entered then skip
if not self.clockapi.get_api_key():
return
@ -234,36 +288,3 @@ class ClockifyModule(
self.clockapi.start_time_entry(
description, project_id, tag_ids=tag_ids
)
def on_message_widget_close(self):
self.message_widget = None
# Definition of Tray menu
def tray_menu(self, parent_menu):
# Menu for Tray App
from Qt import QtWidgets
menu = QtWidgets.QMenu("Clockify", parent_menu)
menu.setProperty("submenu", "on")
# Actions
action_show_settings = QtWidgets.QAction("Settings", menu)
action_stop_timer = QtWidgets.QAction("Stop timer", menu)
menu.addAction(action_show_settings)
menu.addAction(action_stop_timer)
action_show_settings.triggered.connect(self.show_settings)
action_stop_timer.triggered.connect(self.stop_timer)
self.action_stop_timer = action_stop_timer
self.set_menu_visibility()
parent_menu.addMenu(menu)
def show_settings(self):
self.widget_settings.input_api_key.setText(self.clockapi.get_api_key())
self.widget_settings.show()
def set_menu_visibility(self):
self.action_stop_timer.setVisible(self.bool_timer_run)

View file

@ -7,7 +7,6 @@ from openpype.modules import OpenPypeModule
from openpype_interfaces import (
ITrayModule,
IPluginPaths,
ITimersManager,
ILaunchHookPaths,
ISettingsChangeListener,
IFtrackEventHandlerPaths
@ -21,7 +20,6 @@ class FtrackModule(
OpenPypeModule,
ITrayModule,
IPluginPaths,
ITimersManager,
ILaunchHookPaths,
ISettingsChangeListener
):
@ -61,6 +59,10 @@ class FtrackModule(
self.user_event_handlers_paths = user_event_handlers_paths
self.tray_module = None
# TimersManager connection
self.timers_manager_connector = None
self._timers_manager_module = None
def get_global_environments(self):
"""Ftrack's global environments."""
return {
@ -102,16 +104,6 @@ class FtrackModule(
elif key == "user":
self.user_event_handlers_paths.extend(value)
def start_timer(self, data):
"""Implementation of ITimersManager interface."""
if self.tray_module:
self.tray_module.start_timer_manager(data)
def stop_timer(self):
"""Implementation of ITimersManager interface."""
if self.tray_module:
self.tray_module.stop_timer_manager()
def on_system_settings_save(
self, old_value, new_value, changes, new_value_metadata
):
@ -343,7 +335,10 @@ class FtrackModule(
def tray_init(self):
from .tray import FtrackTrayWrapper
self.tray_module = FtrackTrayWrapper(self)
# Module is it's own connector to TimersManager
self.timers_manager_connector = self
def tray_menu(self, parent_menu):
return self.tray_module.tray_menu(parent_menu)
@ -357,3 +352,23 @@ class FtrackModule(
def set_credentials_to_env(self, username, api_key):
os.environ["FTRACK_API_USER"] = username or ""
os.environ["FTRACK_API_KEY"] = api_key or ""
# --- TimersManager connection methods ---
def start_timer(self, data):
if self.tray_module:
self.tray_module.start_timer_manager(data)
def stop_timer(self):
if self.tray_module:
self.tray_module.stop_timer_manager()
def register_timers_manager(self, timer_manager_module):
self._timers_manager_module = timer_manager_module
def timer_started(self, data):
if self._timers_manager_module is not None:
self._timers_manager_module.timer_started(self.id, data)
def timer_stopped(self):
if self._timers_manager_module is not None:
self._timers_manager_module.timer_stopped(self.id)

View file

@ -1,26 +0,0 @@
from abc import abstractmethod
from openpype.modules import OpenPypeInterface
class ITimersManager(OpenPypeInterface):
timer_manager_module = None
@abstractmethod
def stop_timer(self):
pass
@abstractmethod
def start_timer(self, data):
pass
def timer_started(self, data):
if not self.timer_manager_module:
return
self.timer_manager_module.timer_started(self.id, data)
def timer_stopped(self):
if not self.timer_manager_module:
return
self.timer_manager_module.timer_stopped(self.id)

View file

@ -9,20 +9,90 @@ from openpype_interfaces import (
from avalon.api import AvalonMongoDB
class ExampleTimersManagerConnector:
"""Timers manager can handle timers of multiple modules/addons.
Module must have object under `timers_manager_connector` attribute with
few methods. This is example class of the object that could be stored under
module.
Required methods are 'stop_timer' and 'start_timer'.
# TODO pass asset document instead of `hierarchy`
Example of `data` that are passed during changing timer:
```
data = {
"project_name": project_name,
"task_name": task_name,
"task_type": task_type,
"hierarchy": hierarchy
}
```
"""
# Not needed at all
def __init__(self, module):
# Store timer manager module to be able call it's methods when needed
self._timers_manager_module = None
# Store module which want to use timers manager to have access
self._module = module
# Required
def stop_timer(self):
"""Called by timers manager when module should stop timer."""
self._module.stop_timer()
# Required
def start_timer(self, data):
"""Method called by timers manager when should start timer."""
self._module.start_timer(data)
# Optional
def register_timers_manager(self, timer_manager_module):
"""Method called by timers manager where it's object is passed.
This is moment when timers manager module can be store to be able
call it's callbacks (e.g. timer started).
"""
self._timers_manager_module = timer_manager_module
# Custom implementation
def timer_started(self, data):
"""This is example of possibility to trigger callbacks on manager."""
if self._timers_manager_module is not None:
self._timers_manager_module.timer_started(self._module.id, data)
# Custom implementation
def timer_stopped(self):
if self._timers_manager_module is not None:
self._timers_manager_module.timer_stopped(self._module.id)
class TimersManager(OpenPypeModule, ITrayService, IIdleManager):
""" Handles about Timers.
Should be able to start/stop all timers at once.
If IdleManager is imported then is able to handle about stop timers
when user idles for a long time (set in presets).
To be able use this advantage module has to have attribute with name
`timers_manager_connector` which has two methods 'stop_timer'
and 'start_timer'. Optionally may have `register_timers_manager` where
object of TimersManager module is passed to be able call it's callbacks.
See `ExampleTimersManagerConnector`.
"""
name = "timers_manager"
label = "Timers Service"
_required_methods = (
"stop_timer",
"start_timer"
)
def initialize(self, modules_settings):
timers_settings = modules_settings[self.name]
self.enabled = timers_settings["enabled"]
auto_stop = timers_settings["auto_stop"]
# When timer will stop if idle manager is running (minutes)
full_time = int(timers_settings["full_time"] * 60)
@ -41,7 +111,8 @@ class TimersManager(OpenPypeModule, ITrayService, IIdleManager):
self.widget_user_idle = None
self.signal_handler = None
self.modules = []
self._connectors_by_module_id = {}
self._modules_by_id = {}
def tray_init(self):
from .widget_user_idle import WidgetUserIdle, SignalHandler
@ -96,17 +167,35 @@ class TimersManager(OpenPypeModule, ITrayService, IIdleManager):
self.timer_started(None, data)
def timer_started(self, source_id, data):
for module in self.modules:
if module.id != source_id:
module.start_timer(data)
for module_id, connector in self._connectors_by_module_id.items():
if module_id == source_id:
continue
try:
connector.start_timer(data)
except Exception:
self.log.info(
"Failed to start timer on connector {}".format(
str(connector)
)
)
self.last_task = data
self.is_running = True
def timer_stopped(self, source_id):
for module in self.modules:
if module.id != source_id:
module.stop_timer()
for module_id, connector in self._connectors_by_module_id.items():
if module_id == source_id:
continue
try:
connector.stop_timer()
except Exception:
self.log.info(
"Failed to stop timer on connector {}".format(
str(connector)
)
)
def restart_timers(self):
if self.last_task is not None:
@ -120,15 +209,40 @@ class TimersManager(OpenPypeModule, ITrayService, IIdleManager):
self.widget_user_idle.refresh_context()
self.is_running = False
for module in self.modules:
module.stop_timer()
self.timer_stopper(None)
def connect_with_modules(self, enabled_modules):
for module in enabled_modules:
if not isinstance(module, ITimersManager):
connector = getattr(module, "timers_manager_connector", None)
if connector is None:
continue
module.timer_manager_module = self
self.modules.append(module)
missing_methods = set()
for method_name in self._required_methods:
if not hasattr(connector, method_name):
missing_methods.add(method_name)
if missing_methods:
joined = ", ".join(
['"{}"'.format(name for name in missing_methods)]
)
self.log.info((
"Module \"{}\" has missing required methods {}."
).format(module.name, joined))
continue
self._connectors_by_module_id[module.id] = connector
self._modules_by_id[module.id] = module
# Optional method
if hasattr(connector, "register_timers_manager"):
try:
connector.register_timers_manager(self)
except Exception:
self.log.info((
"Failed to register timers manager"
" for connector of module \"{}\"."
).format(module.name))
def callbacks_by_idle_time(self):
"""Implementation of IIdleManager interface."""