class ProcessManager: configuration = Configuration() utility: Utility = Utility() def start(self, path: str) -> Tuple[ActionResult, Optional[Popen]]: """ Open file path using ahk executable path Args: path (str): file path Returns: Tuple[ActionResult, Optional[Popen]]: ActionResult: return error if failed to start script Optional[Popen]: launched ahk process """ result = ActionResult() if not self.utility.is_file(path): result.add_error( ErrorMessages.script_path_not_valid.format(path)) return result, None ahk_path = ProcessManager.configuration.utility.ahk_executable if not ahk_path: result.add_error( ErrorMessages.autohotkey_path_is_not_valid.format(ahk_path)) return result, None try: process = subprocess.Popen([ahk_path, path], shell=False) return result, process except Exception: result.add_error( ErrorMessages.could_not_start_script.format(path)) return result, None def open_explorer(self, path: str) -> ActionResult: """ Open path in file explorer for windows only Args: path (str): file path Returns: ActionResult: return error if for some reason failed to open path """ result = ActionResult() try: subprocess.Popen('explorer /select,{}'.format(path)) except Exception: result.add_error(ErrorMessages.could_not_open_path.format(path)) return result
def error(self, msg): from src.core.utility.configuration import Configuration configuration = Configuration() if configuration.utility.log_level > self._log_level['error']: return msg = self._format_message('ERROR', msg) if configuration.utility.enable_logging: self.logger.error(msg) if configuration.utility.enable_debugging: print(msg)
def critical(self, msg): from src.core.utility.configuration import Configuration configuration = Configuration() if configuration.utility.log_level > self._log_level['critical']: return msg = self._format_message('CRITICAL', msg) if configuration.utility.enable_logging: self.logger.critical(msg) if configuration.utility.enable_debugging: print(msg)
def log(self, msg): from src.core.utility.configuration import Configuration configuration = Configuration() if int(configuration.utility.log_level) > int(self._log_level['log']): return msg = self._format_message('', msg) if configuration.utility.enable_logging: self.logger.debug(msg) if configuration.utility.enable_debugging: print(msg)
def warning(self, msg): from src.core.utility.configuration import Configuration configuration = Configuration() if configuration.utility.log_level > self._log_level['warning']: return msg = self._format_message('Warning', msg) if configuration.utility.enable_logging: self.logger.warning(msg) if configuration.utility.enable_debugging: print(msg)
class Application(QApplication): app_service = AppService() configuration = Configuration() def __init__(self): QApplication.__init__(self, sys.argv) self.app_service.app_model.application = self self.setStyle(QtWidgets.QStyleFactory.create('Fusion')) self.setWindowIcon( QtGui.QIcon(self.configuration.main_window.icon_path)) self.setQuitOnLastWindowClosed(False) self.windows = [] # create main window self.windows.append(MainWindow())
class AppService: configuration: Configuration = Configuration() app_model: AppModel = AppModel() profile_selected_events: List[Callable] = [] library_selected_events: List[Callable] = [] # region public methods def get_library_list(self) -> List[Library]: return library_service.repository.library_list def get_profile_list(self) -> List[Profile]: return profile_service.repository.profile_list def get_selected_library_scripts(self) -> List[Script]: if not self.app_model.selected_library_id: return [] library = library_service.find(self.app_model.selected_library_id) return library.script_list if library else [] def get_selected_profile_scripts(self) -> List[Library]: if not self.app_model.selected_profile_id: return [] return profile_service.get_profile_scripts( self.app_model.selected_profile_id) def refresh(self): self.app_model.main_window.refresh() def save_configuration(self): self.configuration.save(profile_service.repository, library_service.repository) # endregion public methods # region events def on_profile_selected(self, identifier: str): profile = profile_service.find(identifier) if not profile: self.app_model.selected_profile_id = None else: self.app_model.selected_profile_id = identifier self._exec_events(self.profile_selected_events) def on_library_selected(self, identifier: str): library = library_service.find(identifier) if not library: self.app_model.selected_library_id = None else: self.app_model.selected_library_id = identifier self._exec_events(self.library_selected_events) # endregion events # region private methods def _exec_events(self, events): for method in events: try: method() except Exception as error: print(error)
class SettingsDialog(QDialog): save_button_size = QSize(60, 30) browse_button_size = QSize(30, 20) file_type_splitter = ';' row_height = 40 configuration = Configuration() def __init__(self, parent): QDialog.__init__(self, parent) self.path_line_edit = None self.file_type_line_edit = None self._init() def _init(self): config = self.configuration.settings_dialog # set attribute self.setWindowTitle(config.name) self.resize(config.width, config.height) # setup layout layout = QVBoxLayout(self) settings_layout = QGridLayout() ok_layout = QHBoxLayout() layout.addLayout(settings_layout) layout.addStretch(1) ok_layout.setStretch(0, 0) # AHK path path_label = QLabel('AutoHotKey executable path:', self) settings_layout.addWidget(path_label, 0, 0, 1, 1) self.path_line_edit = QLineEdit(self) self.path_line_edit.setText(self.configuration.utility.ahk_executable) settings_layout.addWidget(self.path_line_edit, 0, 1, 1, 1) browse_button = QPushButton('...', self) browse_button.setFixedSize(self.browse_button_size) settings_layout.addWidget(browse_button, 0, 2, 1, 1) browse_button.clicked.connect(self.on_browse_button_clicked) # file types file_type_label = QLabel('AutoHotKey file type:', self) settings_layout.addWidget(file_type_label, 1, 0, 1, 1) self.file_type_line_edit = QLineEdit(self) self.file_type_line_edit.setText( self.file_type_splitter.join( self.configuration.utility.file_types)) settings_layout.addWidget(self.file_type_line_edit, 1, 1, 1, 1) # ok and cancel button layout.addLayout(ok_layout) save_button = QPushButton('Save', self) save_button.setFixedSize(self.save_button_size) ok_layout.addWidget(save_button) save_button.clicked.connect(self.on_save_button_clicked) cancel_button = QPushButton('Cancel', self) ok_layout.addWidget(cancel_button) cancel_button.setFixedSize(self.save_button_size) cancel_button.clicked.connect(self.on_cancel_button_clicked) # region event def on_save_button_clicked(self): self.configuration.utility.ahk_executable = self.path_line_edit.text() self.configuration.utility.file_types = \ self.file_type_line_edit.text().split(self.file_type_splitter) self.configuration.save_general_configs() self.accept() def on_cancel_button_clicked(self): self.reject() def on_browse_button_clicked(self): dialog = QFileDialog(self, 'AutoHotKey program') dialog.setNameFilters(['Program Files (*.exe)', 'All (*.*)']) dialog.selectNameFilter('Program Files (*.exe)') if dialog.exec_(): filenames = dialog.selectedFiles() if not filenames: return self.path_line_edit.setText(filenames[0]) def closeEvent(self, _): self.configuration.settings_dialog.width = self.width() self.configuration.settings_dialog.height = self.height() self.configuration.save_general_configs() self.close()
import os from src.core.service.library_service import library_service from src.core.service.message_service import MessageService from src.core.service.profile_service import ProfileService from src.core.utility.configuration import Configuration path = os.getcwd() + '\\test_data\\AutoHotKey' message_service = MessageService() profile_service = ProfileService() configuration = Configuration() configuration.load() library_service.add(path) profile_service.add('programming') profile_service.add('gaming') # repo_manager = RepoManager.from_json(configs.load_repository()) library_service.refresh() script = library_service.find_script( os.getcwd() + '\\test_data\\AutoHotKey\\Startup\\Duplicate Line.ahk') script2 = library_service.find_script( os.getcwd() + '\\test_data\\AutoHotKey\\Common\\Select Line.ahk') profile_service.add_script('programming', script) profile_service.add_script('gaming', script2) gaming = profile_service.find('gaming') programming = profile_service.find('programming') profile_service.start('gaming') for msg in message_service.messages: print(msg)
class ScriptManager: process_manager = ProcessManager() configuration = Configuration() utility: Utility = Utility() def init_script(self, path: str) -> Tuple[ActionResult, Script]: """ Initialize script Args: path (str): script path Returns: Tuple[ActionResult, Script]: return error if script path is invalid """ result = ActionResult() path = self.utility.format_path(path) # check if path not the file type we want temp_result = self._is_script_file(path) result.merge(temp_result) if not temp_result.success(): return result, None script = Script(path) return result, script # region public methods def remove(self, script: Script) -> ActionResult: """ Remove script, trying to stop script first Args: script (Script): Returns: ActionResult: return error if script not allow state change or not exists """ # for some reason we can not stop the script result, script = self.stop(script) if not result.success(): result.add_error( ErrorMessages.could_not_remove_script_could_not_stop.format( script.identifier())) return result def refresh(self, script: Script) -> Tuple[ActionResult, Script]: """ Refresh script, check whether it exists Args: script (Script): Returns: Tuple[ActionResult, Script]: """ result = ActionResult() # check whether file exists if not script.exists(): result.add_error( ErrorMessages.could_not_refresh_script_script_removed.format( script.identifier())) return result, script # endregion public methods # region command def start(self, script: Script) -> Tuple[ActionResult, Script]: """ Start script Args: script (Script): Returns: Tuple[ActionResult, Script]: """ result = ActionResult() # check whether script is locked or not exists if not script.allow_state_change and not script.is_running(): result.add_error( ErrorMessages.could_not_start_locked_script.format( script.identifier())) return result, script if script.is_running(): return result, script return self._start_script(script) def stop(self, script: Script) -> Tuple[ActionResult, Script]: """ Stop script Args: script (Script): Returns: Tuple[ActionResult, Script]: """ result = ActionResult() if not script.is_running(): return result, script # check whether script is locked or not exists if not script.allow_state_change(): result.add_error( ErrorMessages.could_not_stop_locked_script.format( script.identifier())) return result, script # trying to kill the process try: script.process.kill() script.stop() except Exception: result.add_error( ErrorMessages.could_not_stop_script.format( script.identifier())) return result, script def force_start(self, script: Script) -> Tuple[ActionResult, Script]: """ Force start script, script will be locked after this completed Args: script (Script): Returns: Tuple[ActionResult, Script]: """ result = ActionResult() temp_result, script = self._start_script(script) result.merge(temp_result) if temp_result.success(): script.lock() return result, script def restart(self, script: Script) -> Tuple[ActionResult, Script]: """ Restart script Args: script (Script): Returns: Tuple[ActionResult, Script]: """ result = ActionResult() if not script.allow_state_change(): result.add_error( ErrorMessages.could_not_restart_script.format( script.identifier())) return result, script temp_result, script = self.stop(script) if not temp_result.success(): return temp_result, script return self._start_script(script) def pause(self, script: Script) -> Tuple[ActionResult, Script]: """ Pause script Args: script (Script): Returns: Tuple[ActionResult, Script]: return error when process cannot be stopped """ result = ActionResult() if not script.is_running(): return result, script # * check whether script is locked or not exists if not script.allow_state_change(): result.add_error( ErrorMessages.could_not_stop_locked_script.format( script.identifier())) return result, script # trying to kill the process try: script.process.kill() script.pause() except Exception: result.add_error( ErrorMessages.could_not_stop_script.format( script.identifier())) return result, script def resume(self, script: Script) -> Tuple[ActionResult, Script]: """ Resume script if it is being paused Args: script (Script): Returns: Tuple[ActionResult, Script]: Return error when script cannot start """ if not script.is_paused(): return ActionResult(), script result = ActionResult() # check whether script is locked or not exists if not script.allow_state_change(): result.add_error( ErrorMessages.could_not_start_locked_script.format( script.identifier())) return result, script result, script = self._start_script(script) if result.success(): script.resume() return result, script # endregion command def _start_script(self, script: Script) -> Tuple[ActionResult, Script]: result = ActionResult() temp_result, process = self.process_manager.start(script.path) if not temp_result.success() or not process: return temp_result, script script.start(process) return result, script def _is_script_file(self, path: str) -> ActionResult: result = ActionResult() if not self.utility.is_file(path): result.add_error(ErrorMessages.path_is_not_file.format(path)) return result is_script_file = self.utility.get_file_extension(path) in \ ScriptManager.configuration.utility.file_types if not is_script_file: result.add_error( ErrorMessages.path_is_not_script_file.format(path)) return result
class MainWindow(QMainWindow): configuration = Configuration() app_service = AppService() def __init__(self): QMainWindow.__init__(self) self._load_configs() self._init() self.app_service.app_model.main_window = self # create a vertical layout in the window # all widget should insert into the layout central_widget = QWidget(self) vertical_layout = QVBoxLayout(central_widget) self.setCentralWidget(central_widget) # initialize tab widget self.tab_widget = TabWidget(self) vertical_layout.addWidget(self.tab_widget) # add tray icon self.tray_icon = TrayIcon(self) self.refresh() self.show() def _init(self): config = self.configuration.main_window # set attributes self.setWindowTitle(config.name) self.resize(config.width, config.height) self._create_menus() # region events def closeEvent(self, event): library_service.stop_all() # Save configuration when window is closed self.configuration.main_window.width = self.width() self.configuration.main_window.height = self.height() self.app_service.save_configuration() self.tray_icon.hide() sys.exit() def changeEvent(self, event): if event.type() == QEvent.WindowStateChange: if self.windowState() & Qt.WindowMinimized: self.setVisible(False) # endregion events # region public methods def refresh(self): self.tab_widget.refresh() # endregion public methods # region private methods def _load_configs(self): # load saved settings self.configuration.load() repo = self.configuration.load_libraries() if repo: library_service.repository = LibraryRepository.from_json(repo) repo = self.configuration.load_profiles() if repo: profile_service.repository = ProfileRepository.from_json(repo) def _create_menus(self): main_menu = self.menuBar() # setting settings_menu = main_menu.addMenu('Settings') settings_action = QAction("Settings", self) settings_action.triggered.connect(self._show_settings) settings_menu.addAction(settings_action) # # library # libraryMenu = mainMenu.addMenu('Library') # libraryMenu.addAction(settingsAction) # # profile # profileMenu = mainMenu.addMenu('Profile') # profileMenu.addAction(settingsAction) def _show_settings(self): dialog = SettingsDialog(self) dialog.exec_()
class AddScriptToProfileDialog(QDialog): add_button_size = QSize(50, 40) ok_button_size = QSize(100, 60) app_service: AppService = AppService() configuration: Configuration = Configuration() def __init__(self, parent): QDialog.__init__(self, parent) self.available_scripts: List[Script] = [] self.selected_scripts: List[Script] = [] self.available_script_table: TableWidget = None self.selected_script_table: TableWidget = None self._init_available_scripts() self._init() self.show() def _init(self): config = self.configuration.add_script_dialog # set attributes self.setWindowTitle(config.name) self.resize(config.width, config.height) # setup layouts layout = QVBoxLayout(self) script_table_layout = QHBoxLayout() ok_layout = QHBoxLayout() available_layout = QVBoxLayout() button_layout = QVBoxLayout() selected_layout = QVBoxLayout() layout.addLayout(script_table_layout) layout.addLayout(ok_layout) script_table_layout.addLayout(available_layout) script_table_layout.addLayout(button_layout) script_table_layout.addLayout(selected_layout) # initialize available script table self.available_script_table = AddScriptDialogTableWidget( self, self.available_scripts) self.available_script_table.itemDoubleClicked.connect( self.on_available_script_table_item_double_clicked) available_layout.addWidget(self.available_script_table) self.available_script_table.refresh() # initialize selected script table self.selected_script_table = AddScriptDialogTableWidget( self, self.selected_scripts) self.selected_script_table.itemDoubleClicked.connect( self.on_selected_script_table_item_double_clicked) selected_layout.addWidget(self.selected_script_table) self.available_script_table.refresh() # add and remove button button_layout.addStretch(1) add_button = QPushButton('>', self) add_button.setFixedSize(self.add_button_size) button_layout.addWidget(add_button) add_button.clicked.connect(self.on_add_button_clicked) add_all_button = QPushButton('>>>', self) add_all_button.setFixedSize(self.add_button_size) button_layout.addWidget(add_all_button) add_all_button.clicked.connect(self.on_add_all_button_clicked) button_layout.addStretch(1) remove_button = QPushButton('<', self) button_layout.addWidget(remove_button) remove_button.setFixedSize(self.add_button_size) remove_button.clicked.connect(self.on_remove_button_clicked) remove_all_button = QPushButton('<<<', self) button_layout.addWidget(remove_all_button) remove_all_button.setFixedSize(self.add_button_size) remove_all_button.clicked.connect(self.on_remove_all_button_clicked) button_layout.addStretch(1) # ok and cancel button ok_button = QPushButton('Ok', self) ok_button.setFixedSize(self.ok_button_size) ok_layout.addWidget(ok_button) ok_button.clicked.connect(self.on_ok_button_clicked) cancel_button = QPushButton('Cancel', self) ok_layout.addWidget(cancel_button) cancel_button.setFixedSize(self.ok_button_size) cancel_button.clicked.connect(self.on_cancel_button_clicked) def get_selected_scripts(self) -> List[Script]: return self.selected_script_table.scripts # region events def on_ok_button_clicked(self): self.accept() def on_cancel_button_clicked(self): self.reject() def on_add_button_clicked(self): # get selected table items selected_items = self.available_script_table.selectedItems() if not selected_items: return # each row has x number of columns step = len(self.available_script_table.columns) i = 0 while i < len(selected_items): item = selected_items[i] self._select_script(item.script_id) i += step def on_add_all_button_clicked(self): # reset the scripts # now you will have everything available in avaliable_script list self._init_available_scripts() # set selected as available scripts self.selected_scripts = self.available_scripts self.available_scripts = [] # set the table scripts self.selected_script_table.scripts = self.selected_scripts self.available_script_table.scripts = self.available_scripts # refresh tables self.available_script_table.refresh() self.selected_script_table.refresh() def on_remove_all_button_clicked(self): # reset all data self._init_available_scripts() self.selected_script_table.scripts = self.selected_scripts self.available_script_table.scripts = self.available_scripts self.available_script_table.refresh() self.selected_script_table.refresh() def on_remove_button_clicked(self): selected_items = self.selected_script_table.selectedItems() if not selected_items: return # each row has x number of columns step = len(self.selected_script_table.columns) i = 0 while i < len(selected_items): item = selected_items[i] self._unselect_script(item.script_id) i += step def on_available_script_table_item_double_clicked(self, item): self._select_script(item.script_id) def on_selected_script_table_item_double_clicked(self, item): self._unselect_script(item.script_id) def closeEvent(self, _): self.configuration.add_script_dialog.width = self.width() self.configuration.add_script_dialog.height = self.height() self.configuration.save_general_configs() self.close() # endregion events def _init_available_scripts(self): profile = profile_service.find( self.app_service.app_model.selected_profile_id) if not profile: return self.available_scripts = [] self.selected_scripts = [] scripts = library_service.get_all_scripts() for script_id in profile.script_id_list: found = next((x for x in scripts if x.has_id(script_id)), None) if not found: continue scripts.remove(found) self.available_scripts = scripts def _select_script(self, script_id): script = next( (x for x in self.available_scripts if x.has_id(script_id)), None) if not script: return self.selected_scripts.append(script) self.available_scripts.remove(script) self.selected_script_table.refresh() self.available_script_table.refresh() def _unselect_script(self, script_id): script = next( (x for x in self.selected_scripts if x.has_id(script_id)), None) if not script: return self.available_scripts.append(script) self.selected_scripts.remove(script) self.available_script_table.refresh() self.selected_script_table.refresh()
class TrayIcon(QSystemTrayIcon): configuration: Configuration = Configuration() app_service: AppService = AppService() def __init__(self, parent=None): QSystemTrayIcon.__init__(self, parent) # set tray icon self.setIcon(QtGui.QIcon(self.configuration.main_window.icon_path)) # double click event self.activated.connect(self.on_activated) # add right click menu menu = QMenu(parent) pause_action = menu.addAction(button_text_pause) pause_action.triggered.connect(self.on_pause_triggered) resume_action = menu.addAction(button_text_resume) resume_action.triggered.connect(self.on_resume_triggered) stop_all_action = menu.addAction(button_text_stop) stop_all_action.triggered.connect(self.on_stop_triggered) menu.addSeparator() show_action = menu.addAction(button_text_show) show_action.triggered.connect(self.show_triggered) exit_action = menu.addAction(button_text_exit) exit_action.triggered.connect(self.on_exit_triggered) self.setContextMenu(menu) self.show() def on_activated(self, reason): if reason == QSystemTrayIcon.DoubleClick: self.show_triggered() def show_triggered(self): self.app_service.app_model.main_window.setVisible(True) self.app_service.app_model.main_window.setWindowState(Qt.WindowActive) def on_exit_triggered(self): self.app_service.app_model.main_window.closeEvent(QCloseEvent()) def on_stop_triggered(self): library_service.stop_all() profile_service.stop_all() self._refresh_main_window() self._show_message_box(dialog_message_stop) def on_pause_triggered(self): library_service.pause_all() self._refresh_main_window() self._show_message_box(dialog_message_pause) def on_resume_triggered(self): library_service.resume_all() self._refresh_main_window() self._show_message_box(dialog_message_resume) # region private methods def _show_message_box(self, message: str): # * Show notification box message_box = QMessageBox(None) message_box.setIcon(QMessageBox.Information) message_box.setText(message) message_box.setWindowTitle(dialog_title) message_box.exec_() def _refresh_main_window(self): # * Refresh UI self.app_service.app_model.main_window.refresh()