Merge pull request #333 from pypeclub/feature/idle_manager_without_qt

Feature/idle manager without qt
This commit is contained in:
Milan Kolar 2020-07-08 09:08:38 +02:00 committed by GitHub
commit fe6ea0e1ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 94 additions and 101 deletions

View file

@ -1,26 +1,25 @@
import time
import collections
from Qt import QtCore
import threading
from pynput import mouse, keyboard
from pype.api import Logger
class IdleManager(QtCore.QThread):
class IdleManager(threading.Thread):
""" Measure user's idle time in seconds.
Idle time resets on keyboard/mouse input.
Is able to emit signals at specific time idle.
"""
time_signals = collections.defaultdict(list)
time_callbacks = collections.defaultdict(list)
idle_time = 0
signal_reset_timer = QtCore.Signal()
def __init__(self):
super(IdleManager, self).__init__()
self.log = Logger().get_logger(self.__class__.__name__)
self.signal_reset_timer.connect(self._reset_time)
self.qaction = None
self.failed_icon = None
self._is_running = False
self.threads = []
def set_qaction(self, qaction, failed_icon):
self.qaction = qaction
@ -32,18 +31,18 @@ class IdleManager(QtCore.QThread):
def tray_exit(self):
self.stop()
try:
self.time_signals = {}
self.time_callbacks = {}
except Exception:
pass
def add_time_signal(self, emit_time, signal):
""" If any module want to use IdleManager, need to use add_time_signal
:param emit_time: time when signal will be emitted
:type emit_time: int
:param signal: signal that will be emitted (without objects)
:type signal: QtCore.Signal
def add_time_callback(self, emit_time, callback):
"""If any module want to use IdleManager, need to use this method.
Args:
emit_time(int): Time when callback will be triggered.
callback(func): Callback that will be triggered.
"""
self.time_signals[emit_time].append(signal)
self.time_callbacks[emit_time].append(callback)
@property
def is_running(self):
@ -58,17 +57,26 @@ class IdleManager(QtCore.QThread):
def run(self):
self.log.info('IdleManager has started')
self._is_running = True
thread_mouse = MouseThread(self.signal_reset_timer)
thread_mouse = MouseThread(self._reset_time)
thread_mouse.start()
thread_keyboard = KeyboardThread(self.signal_reset_timer)
thread_keyboard = KeyboardThread(self._reset_time)
thread_keyboard.start()
try:
while self.is_running:
if self.idle_time in self.time_callbacks:
for callback in self.time_callbacks[self.idle_time]:
thread = threading.Thread(target=callback)
thread.start()
self.threads.append(thread)
for thread in tuple(self.threads):
if not thread.isAlive():
thread.join()
self.threads.remove(thread)
self.idle_time += 1
if self.idle_time in self.time_signals:
for signal in self.time_signals[self.idle_time]:
signal.emit()
time.sleep(1)
except Exception:
self.log.warning(
'Idle Manager service has failed', exc_info=True
@ -79,16 +87,14 @@ class IdleManager(QtCore.QThread):
# Threads don't have their attrs when Qt application already finished
try:
thread_mouse.signal_stop.emit()
thread_mouse.terminate()
thread_mouse.wait()
thread_mouse.stop()
thread_mouse.join()
except AttributeError:
pass
try:
thread_keyboard.signal_stop.emit()
thread_keyboard.terminate()
thread_keyboard.wait()
thread_keyboard.stop()
thread_keyboard.join()
except AttributeError:
pass
@ -96,49 +102,24 @@ class IdleManager(QtCore.QThread):
self.log.info('IdleManager has stopped')
class MouseThread(QtCore.QThread):
"""Listens user's mouse movement
"""
signal_stop = QtCore.Signal()
class MouseThread(mouse.Listener):
"""Listens user's mouse movement."""
def __init__(self, signal):
super(MouseThread, self).__init__()
self.signal_stop.connect(self.stop)
self.m_listener = None
self.signal_reset_timer = signal
def stop(self):
if self.m_listener is not None:
self.m_listener.stop()
def __init__(self, callback):
super(MouseThread, self).__init__(on_move=self.on_move)
self.callback = callback
def on_move(self, posx, posy):
self.signal_reset_timer.emit()
def run(self):
self.m_listener = mouse.Listener(on_move=self.on_move)
self.m_listener.start()
self.callback()
class KeyboardThread(QtCore.QThread):
"""Listens user's keyboard input
"""
signal_stop = QtCore.Signal()
class KeyboardThread(keyboard.Listener):
"""Listens user's keyboard input."""
def __init__(self, signal):
super(KeyboardThread, self).__init__()
self.signal_stop.connect(self.stop)
self.k_listener = None
def __init__(self, callback):
super(KeyboardThread, self).__init__(on_press=self.on_press)
self.signal_reset_timer = signal
def stop(self):
if self.k_listener is not None:
self.k_listener.stop()
self.callback = callback
def on_press(self, key):
self.signal_reset_timer.emit()
def run(self):
self.k_listener = keyboard.Listener(on_press=self.on_press)
self.k_listener.start()
self.callback()

View file

@ -1,5 +1,4 @@
from Qt import QtCore
from .widget_user_idle import WidgetUserIdle
from .widget_user_idle import WidgetUserIdle, SignalHandler
from pype.api import Logger, config
@ -31,7 +30,10 @@ class TimersManager(metaclass=Singleton):
self.log = Logger().get_logger(self.__class__.__name__)
self.tray_widget = tray_widget
self.main_widget = main_widget
self.widget_user_idle = WidgetUserIdle(self)
self.idle_man = None
self.signal_handler = None
self.widget_user_idle = WidgetUserIdle(self, tray_widget)
def set_signal_times(self):
try:
@ -114,49 +116,59 @@ class TimersManager(metaclass=Singleton):
:param modules: All imported modules from TrayManager
:type modules: dict
"""
self.s_handler = SignalHandler(self)
if 'IdleManager' in modules:
self.signal_handler = SignalHandler(self)
if self.set_signal_times() is True:
self.register_to_idle_manager(modules['IdleManager'])
def time_callback(self, int_def):
if not self.signal_handler:
return
if int_def == 0:
self.signal_handler.signal_show_message.emit()
elif int_def == 1:
self.signal_handler.signal_change_label.emit()
elif int_def == 2:
self.signal_handler.signal_stop_timers.emit()
def register_to_idle_manager(self, man_obj):
self.idle_man = man_obj
# Time when message is shown
self.idle_man.add_time_callback(
self.time_show_message,
lambda: self.time_callback(0)
)
# Times when idle is between show widget and stop timers
show_to_stop_range = range(
self.time_show_message-1, self.time_stop_timer
self.time_show_message - 1, self.time_stop_timer
)
for num in show_to_stop_range:
self.idle_man.add_time_signal(
num,
self.s_handler.signal_change_label
self.idle_man.add_time_callback(
num, lambda: self.time_callback(1)
)
# Times when widget is already shown and user restart idle
shown_and_moved_range = range(
self.time_stop_timer - self.time_show_message
)
for num in shown_and_moved_range:
self.idle_man.add_time_signal(
num,
self.s_handler.signal_change_label
self.idle_man.add_time_callback(
num, lambda: self.time_callback(1)
)
# Time when message is shown
self.idle_man.add_time_signal(
self.time_show_message,
self.s_handler.signal_show_message
)
# Time when timers are stopped
self.idle_man.add_time_signal(
self.idle_man.add_time_callback(
self.time_stop_timer,
self.s_handler.signal_stop_timers
lambda: self.time_callback(2)
)
def change_label(self):
if self.is_running is False:
return
if self.widget_user_idle.bool_is_showed is False:
return
if not hasattr(self, 'idle_man'):
if not self.idle_man or self.widget_user_idle.bool_is_showed is False:
return
if self.idle_man.idle_time > self.time_show_message:
@ -174,14 +186,3 @@ class TimersManager(metaclass=Singleton):
return
if self.widget_user_idle.bool_is_showed is False:
self.widget_user_idle.show()
class SignalHandler(QtCore.QObject):
signal_show_message = QtCore.Signal()
signal_change_label = QtCore.Signal()
signal_stop_timers = QtCore.Signal()
def __init__(self, cls):
super().__init__()
self.signal_show_message.connect(cls.show_message)
self.signal_change_label.connect(cls.change_label)
self.signal_stop_timers.connect(cls.stop_timers)

View file

@ -1,4 +1,3 @@
from pype.api import Logger
from avalon import style
from Qt import QtCore, QtGui, QtWidgets
@ -8,18 +7,18 @@ class WidgetUserIdle(QtWidgets.QWidget):
SIZE_W = 300
SIZE_H = 160
def __init__(self, parent):
def __init__(self, module, tray_widget):
super(WidgetUserIdle, self).__init__()
self.bool_is_showed = False
self.bool_not_stopped = True
self.parent_widget = parent
self.setWindowIcon(parent.tray_widget.icon)
self.module = module
self.setWindowIcon(tray_widget.icon)
self.setWindowFlags(
QtCore.Qt.WindowCloseButtonHint |
QtCore.Qt.WindowMinimizeButtonHint
QtCore.Qt.WindowCloseButtonHint
| QtCore.Qt.WindowMinimizeButtonHint
)
self._translate = QtCore.QCoreApplication.translate
@ -129,11 +128,11 @@ class WidgetUserIdle(QtWidgets.QWidget):
self.lbl_rest_time.setText(str_time)
def stop_timer(self):
self.parent_widget.stop_timers()
self.module.stop_timers()
self.close_widget()
def restart_timer(self):
self.parent_widget.restart_timers()
self.module.restart_timers()
self.close_widget()
def continue_timer(self):
@ -154,3 +153,15 @@ class WidgetUserIdle(QtWidgets.QWidget):
def showEvent(self, event):
self.bool_is_showed = True
class SignalHandler(QtCore.QObject):
signal_show_message = QtCore.Signal()
signal_change_label = QtCore.Signal()
signal_stop_timers = QtCore.Signal()
def __init__(self, cls):
super().__init__()
self.signal_show_message.connect(cls.show_message)
self.signal_change_label.connect(cls.change_label)
self.signal_stop_timers.connect(cls.stop_timers)