def __init__(self, parent=None): super(StopTimer, self).__init__() self.main_context = True self.parent = parent self.setWindowIcon(self.parent.parent.icon) self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint) self._translate = QtCore.QCoreApplication.translate self.font = QtGui.QFont() self.font.setFamily("DejaVu Sans Condensed") self.font.setPointSize(9) self.font.setBold(True) self.font.setWeight(50) self.font.setKerning(True) self.resize(self.SIZE_W, self.SIZE_H) self.setMinimumSize(QtCore.QSize(self.SIZE_W, self.SIZE_H)) self.setMaximumSize(QtCore.QSize(self.SIZE_W + 100, self.SIZE_H + 100)) self.setStyleSheet(style.load_stylesheet()) self.setLayout(self._main()) self.refresh_context() self.setWindowTitle('Pype - Stop Ftrack timer')
class LoginServerThread(QtCore.QThread): '''Login server thread.''' # Login signal. loginSignal = QtCore.Signal(object, object, object) def start(self, url): '''Start thread.''' self.url = url super(LoginServerThread, self).start() def _handle_login(self, api_user, api_key): '''Login to server with *api_user* and *api_key*.''' self.loginSignal.emit(self.url, api_user, api_key) def run(self): '''Listen for events.''' # self._server = BaseHTTPServer.HTTPServer( self._server = HTTPServer(('localhost', 0), functools.partial(LoginServerHandler, self._handle_login)) unformated_url = ('{0}/user/api_credentials?' 'redirect_url=http://localhost:{1}') webbrowser.open_new_tab( unformated_url.format(self.url, self._server.server_port)) self._server.handle_request()
def __init__(self, parent=None, is_event=False): super(Login_Dialog_ui, self).__init__() self.parent = parent self.is_event = is_event if hasattr(parent, 'icon'): self.setWindowIcon(self.parent.icon) elif hasattr(parent, 'parent') and hasattr(parent.parent, 'icon'): self.setWindowIcon(self.parent.parent.icon) else: pype_setup = os.getenv('PYPE_SETUP_ROOT') items = [pype_setup, "app", "resources", "icon.png"] fname = os.path.sep.join(items) icon = QtGui.QIcon(fname) self.setWindowIcon(icon) self.setWindowFlags( QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint ) self.loginSignal.connect(self.loginWithCredentials) self._translate = QtCore.QCoreApplication.translate self.font = QtGui.QFont() self.font.setFamily("DejaVu Sans Condensed") self.font.setPointSize(9) self.font.setBold(True) self.font.setWeight(50) self.font.setKerning(True) self.resize(self.SIZE_W, self.SIZE_H) self.setMinimumSize(QtCore.QSize(self.SIZE_W, self.SIZE_H)) self.setMaximumSize(QtCore.QSize(self.SIZE_W+100, self.SIZE_H+100)) self.setStyleSheet(style.load_stylesheet()) self.setLayout(self._main()) self.setWindowTitle('Pype - Ftrack Login')
class KeyboardThread(QtCore.QThread): signal_stop = QtCore.Signal() def __init__(self, parent): super(KeyboardThread, self).__init__() self.parent = parent self.signal_stop.connect(self.stop) self.k_listener = None def stop(self): if self.k_listener is not None: self.k_listener.stop() def on_press(self, key): self.parent.signal_reset_timer.emit() def run(self): self.k_listener = keyboard.Listener(on_press=self.on_press) self.k_listener.start()
class MouseThread(QtCore.QThread): signal_stop = QtCore.Signal() def __init__(self, parent): super(MouseThread, self).__init__() self.parent = parent self.signal_stop.connect(self.stop) self.m_listener = None def stop(self): if self.m_listener is not None: self.m_listener.stop() def on_move(self, posx, posy): self.parent.signal_reset_timer.emit() def run(self): self.m_listener = mouse.Listener(on_move=self.on_move) self.m_listener.start()
class Login_Dialog_ui(QtWidgets.QWidget): SIZE_W = 300 SIZE_H = 230 loginSignal = QtCore.Signal(object, object, object) _login_server_thread = None inputs = [] buttons = [] labels = [] def __init__(self, parent=None, is_event=False): super(Login_Dialog_ui, self).__init__() self.parent = parent self.is_event = is_event if hasattr(parent, 'icon'): self.setWindowIcon(self.parent.icon) elif hasattr(parent, 'parent') and hasattr(parent.parent, 'icon'): self.setWindowIcon(self.parent.parent.icon) else: pype_setup = os.getenv('PYPE_SETUP_ROOT') items = [pype_setup, "app", "resources", "icon.png"] fname = os.path.sep.join(items) icon = QtGui.QIcon(fname) self.setWindowIcon(icon) self.setWindowFlags( QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint ) self.loginSignal.connect(self.loginWithCredentials) self._translate = QtCore.QCoreApplication.translate self.font = QtGui.QFont() self.font.setFamily("DejaVu Sans Condensed") self.font.setPointSize(9) self.font.setBold(True) self.font.setWeight(50) self.font.setKerning(True) self.resize(self.SIZE_W, self.SIZE_H) self.setMinimumSize(QtCore.QSize(self.SIZE_W, self.SIZE_H)) self.setMaximumSize(QtCore.QSize(self.SIZE_W+100, self.SIZE_H+100)) self.setStyleSheet(style.load_stylesheet()) self.setLayout(self._main()) self.setWindowTitle('Pype - Ftrack Login') def _main(self): self.main = QtWidgets.QVBoxLayout() self.main.setObjectName("main") self.form = QtWidgets.QFormLayout() self.form.setContentsMargins(10, 15, 10, 5) self.form.setObjectName("form") self.ftsite_label = QtWidgets.QLabel("FTrack URL:") self.ftsite_label.setFont(self.font) self.ftsite_label.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.ftsite_label.setTextFormat(QtCore.Qt.RichText) self.ftsite_label.setObjectName("user_label") self.ftsite_input = QtWidgets.QLineEdit() self.ftsite_input.setEnabled(True) self.ftsite_input.setFrame(True) self.ftsite_input.setEnabled(False) self.ftsite_input.setReadOnly(True) self.ftsite_input.setObjectName("ftsite_input") self.user_label = QtWidgets.QLabel("Username:"******"user_label") self.user_input = QtWidgets.QLineEdit() self.user_input.setEnabled(True) self.user_input.setFrame(True) self.user_input.setObjectName("user_input") self.user_input.setPlaceholderText( self._translate("main", "user.name") ) self.user_input.textChanged.connect(self._user_changed) self.api_label = QtWidgets.QLabel("API Key:") self.api_label.setFont(self.font) self.api_label.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) self.api_label.setTextFormat(QtCore.Qt.RichText) self.api_label.setObjectName("api_label") self.api_input = QtWidgets.QLineEdit() self.api_input.setEnabled(True) self.api_input.setFrame(True) self.api_input.setObjectName("api_input") self.api_input.setPlaceholderText(self._translate( "main", "e.g. xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" )) self.api_input.textChanged.connect(self._api_changed) self.error_label = QtWidgets.QLabel("") self.error_label.setFont(self.font) self.error_label.setTextFormat(QtCore.Qt.RichText) self.error_label.setObjectName("error_label") self.error_label.setWordWrap(True) self.error_label.hide() self.form.addRow(self.ftsite_label, self.ftsite_input) self.form.addRow(self.user_label, self.user_input) self.form.addRow(self.api_label, self.api_input) self.form.addRow(self.error_label) self.btnGroup = QtWidgets.QHBoxLayout() self.btnGroup.addStretch(1) self.btnGroup.setObjectName("btnGroup") self.btnEnter = QtWidgets.QPushButton("Login") self.btnEnter.setToolTip( 'Set Username and API Key with entered values' ) self.btnEnter.clicked.connect(self.enter_credentials) self.btnClose = QtWidgets.QPushButton("Close") self.btnClose.setToolTip('Close this window') self.btnClose.clicked.connect(self._close_widget) self.btnFtrack = QtWidgets.QPushButton("Ftrack") self.btnFtrack.setToolTip('Open browser for Login to Ftrack') self.btnFtrack.clicked.connect(self.open_ftrack) self.btnGroup.addWidget(self.btnFtrack) self.btnGroup.addWidget(self.btnEnter) self.btnGroup.addWidget(self.btnClose) self.main.addLayout(self.form) self.main.addLayout(self.btnGroup) self.inputs.append(self.api_input) self.inputs.append(self.user_input) self.inputs.append(self.ftsite_input) self.enter_site() return self.main def enter_site(self): try: url = os.getenv('FTRACK_SERVER') newurl = self.checkUrl(url) if newurl is None: self.btnEnter.setEnabled(False) self.btnFtrack.setEnabled(False) for input in self.inputs: input.setEnabled(False) newurl = url self.ftsite_input.setText(newurl) except Exception: self.setError("FTRACK_SERVER is not set in templates") self.btnEnter.setEnabled(False) self.btnFtrack.setEnabled(False) for input in self.inputs: input.setEnabled(False) def setError(self, msg): self.error_label.setText(msg) self.error_label.show() def _user_changed(self): self.user_input.setStyleSheet("") def _api_changed(self): self.api_input.setStyleSheet("") def _invalid_input(self, entity): entity.setStyleSheet("border: 1px solid red;") def enter_credentials(self): username = self.user_input.text().strip() apiKey = self.api_input.text().strip() msg = "You didn't enter " missing = [] if username == "": missing.append("Username") self._invalid_input(self.user_input) if apiKey == "": missing.append("API Key") self._invalid_input(self.api_input) if len(missing) > 0: self.setError("{0} {1}".format(msg, " and ".join(missing))) return verification = credentials._check_credentials(username, apiKey) if verification: credentials._save_credentials(username, apiKey, self.is_event) credentials._set_env(username, apiKey) if self.parent is not None: self.parent.loginChange() self._close_widget() else: self._invalid_input(self.user_input) self._invalid_input(self.api_input) self.setError( "We're unable to sign in to Ftrack with these credentials" ) def open_ftrack(self): url = self.ftsite_input.text() self.loginWithCredentials(url, None, None) def checkUrl(self, url): url = url.strip('/ ') if not url: self.setError("There is no URL set in Templates") return if 'http' not in url: if url.endswith('ftrackapp.com'): url = 'https://' + url else: url = 'https://{0}.ftrackapp.com'.format(url) try: result = requests.get( url, # Old python API will not work with redirect. allow_redirects=False ) except requests.exceptions.RequestException: self.setError( 'The server URL set in Templates could not be reached.' ) return if ( result.status_code != 200 or 'FTRACK_VERSION' not in result.headers ): self.setError( 'The server URL set in Templates is not a valid ftrack server.' ) return return url def loginWithCredentials(self, url, username, apiKey): url = url.strip('/ ') if not url: self.setError( 'You need to specify a valid server URL, ' 'for example https://server-name.ftrackapp.com' ) return if 'http' not in url: if url.endswith('ftrackapp.com'): url = 'https://' + url else: url = 'https://{0}.ftrackapp.com'.format(url) try: result = requests.get( url, # Old python API will not work with redirect. allow_redirects=False ) except requests.exceptions.RequestException: self.setError( 'The server URL you provided could not be reached.' ) return if ( result.status_code != 200 or 'FTRACK_VERSION' not in result.headers ): self.setError( 'The server URL you provided is not a valid ftrack server.' ) return # If there is an existing server thread running we need to stop it. if self._login_server_thread: self._login_server_thread.quit() self._login_server_thread = None # If credentials are not properly set, try to get them using a http # server. if not username or not apiKey: self._login_server_thread = login_tools.LoginServerThread() self._login_server_thread.loginSignal.connect(self.loginSignal) self._login_server_thread.start(url) return verification = credentials._check_credentials(username, apiKey) if verification is True: credentials._save_credentials(username, apiKey, self.is_event) credentials._set_env(username, apiKey) if self.parent is not None: self.parent.loginChange() self._close_widget() def closeEvent(self, event): event.ignore() self._close_widget() def _close_widget(self): self.hide()
class CountdownThread(QtCore.QThread): # Senders signal_show_question = QtCore.Signal() signal_send_time = QtCore.Signal(object) signal_stop_timer = QtCore.Signal() signal_stop_countdown = QtCore.Signal() # Listeners signal_reset_timer = QtCore.Signal() signal_continue_timer = QtCore.Signal() def __init__(self, parent): super(CountdownThread, self).__init__() self.runs = True self.over_line = False config_data = self.load_timer_values() self.count_length = config_data['full_time'] * 60 self.border_line = config_data['message_time'] * 60 + 1 self.reset_count() self.signal_reset_timer.connect(self.reset_count) self.signal_continue_timer.connect(self.continue_timer) def continue_timer(self): self.over_line = False self.reset_count() def reset_count(self): if self.over_line is True: self.actual = self.border_line else: self.actual = self.count_length def stop(self): self.runs = False def run(self): thread_mouse = MouseThread(self) thread_mouse.start() thread_keyboard = KeyboardThread(self) thread_keyboard.start() while self.runs: if self.actual == self.border_line: self.signal_show_question.emit() self.over_line = True if self.actual <= self.border_line: self.signal_send_time.emit(self.actual) time.sleep(1) self.actual -= 1 if self.actual == 0: self.runs = False self.signal_stop_timer.emit() thread_mouse.signal_stop.emit() thread_mouse.terminate() thread_mouse.wait() thread_keyboard.signal_stop.emit() thread_keyboard.terminate() thread_keyboard.wait() def load_timer_values(self): templates = os.environ['PYPE_STUDIO_TEMPLATES'] path_items = [templates, 'presets', 'ftrack', 'ftrack_config.json'] filepath = os.path.sep.join(path_items) data = dict() try: with open(filepath) as data_file: json_dict = json.load(data_file) data = json_dict['timer'] except Exception as e: msg = ('Loading "Ftrack Config file" Failed.' ' Please check log for more information.' ' Times are set to default.') log.warning("{} - {}".format(msg, str(e))) data = self.validate_timer_values(data) return data def validate_timer_values(self, data): # default values if 'full_time' not in data: data['full_time'] = 15 if 'message_time' not in data: data['message_time'] = 0.5 # minimum values if data['full_time'] < 2: data['full_time'] = 2 # message time is earlier that full time if data['message_time'] > data['full_time']: data['message_time'] = data['full_time'] - 0.5 return data
class FtrackEventsThread(QtCore.QThread): # Senders signal_timer_started = QtCore.Signal() signal_timer_stopped = QtCore.Signal() # Listeners signal_stop_timer = QtCore.Signal() signal_restart_timer = QtCore.Signal() def __init__(self, parent): super(FtrackEventsThread, self).__init__() cred = credentials._get_credentials() self.username = cred['username'] self.signal_stop_timer.connect(self.ftrack_stop_timer) self.signal_restart_timer.connect(self.ftrack_restart_timer) self.user = None self.last_task = None def run(self): self.timer_session = ftrack_api.Session(auto_connect_event_hub=True) self.timer_session.event_hub.subscribe( 'topic=ftrack.update and source.user.username={}'.format( self.username), self.event_handler) user_query = 'User where username is "{}"'.format(self.username) self.user = self.timer_session.query(user_query).one() timer_query = 'Timer where user.username is "{}"'.format(self.username) timer = self.timer_session.query(timer_query).first() if timer is not None: self.last_task = timer['context'] self.signal_timer_started.emit() self.timer_session.event_hub.wait() def event_handler(self, event): try: if event['data']['entities'][0]['objectTypeId'] != 'timer': return except Exception: return new = event['data']['entities'][0]['changes']['start']['new'] old = event['data']['entities'][0]['changes']['start']['old'] if old is None and new is None: return timer_query = 'Timer where user.username is "{}"'.format(self.username) timer = self.timer_session.query(timer_query).first() if timer is not None: self.last_task = timer['context'] if old is None: self.signal_timer_started.emit() elif new is None: self.signal_timer_stopped.emit() def ftrack_stop_timer(self): try: self.user.stop_timer() self.timer_session.commit() except Exception as e: log.debug("Timer stop had issues: {}".format(e)) def ftrack_restart_timer(self): try: if (self.last_task is not None) and (self.user is not None): self.user.start_timer(self.last_task) self.timer_session.commit() except Exception as e: log.debug("Timer stop had issues: {}".format(e))