def createDockWindows(self): dock = QDockWidget("Available Garments Types", self) #dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.availableItems = QListWidget(dock) self.availableItems.setMinimumWidth(350) self.availableItems.setMaximumWidth(350) #self.availableItems.addItems(("stuff")) self.availableItems.itemClicked.connect(self.itemClicked_Click) dock.setWidget(self.availableItems) self.addDockWidget(Qt.RightDockWidgetArea, dock) self.viewMenu.addAction(dock.toggleViewAction()) dock.hide() self.dock = QDockWidget("Available Garment Sizes", self) self.orderItem = QTreeWidget(dock) #self.orderItem.setMinimumWidth(350) #self.orderItem.setMaximumWidth(350) #self.orderItem.insertText(("more stuff")) self.dock.setWidget(self.orderItem) self.addDockWidget(Qt.RightDockWidgetArea, self.dock) self.viewMenu.addAction(self.dock.toggleViewAction()) self.dock.hide() #Create a tree widget for use when the t-shirt is clicked. self.treeDock = QDockWidget("Order Items", self) self.garmentTree = QTreeWidget(self.treeDock) self.garmentTree.setObjectName('garmentTree') self.garmentTree.itemClicked.connect(CSRWidgets.sumQuantity) self.garmentTree.itemClicked.connect(lambda: CSRWidgets.updateNameDesign(self)) self.garmentTree.setMaximumWidth(480) self.garmentTree.setMinimumWidth(480) self.treeDock.hide()
def __setup_sub_window_dock(self, window: QWidget, config: dict, sub_window_data: SimpleNamespace): dock_name = config.get('DockName', '') dock_area = config.get('DockArea', Qt.NoDockWidgetArea) dock_show = config.get('DockShow', False) dock_float = config.get('DockFloat', False) dock_wnd = QDockWidget(dock_name, self) dock_wnd.setAllowedAreas( Qt.RightDockWidgetArea | Qt.LeftDockWidgetArea | Qt.TopDockWidgetArea | Qt.BottomDockWidgetArea) # With this setting, the dock widget cannot be closed # dock_wnd.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) if dock_area != Qt.NoDockWidgetArea: if dock_area == Qt.AllDockWidgetAreas: self.addDockWidget(Qt.TopDockWidgetArea, dock_wnd) dock_wnd.setFloating(True) dock_wnd.move(QApplication.desktop().screen().rect().center() - self.rect().center()) else: self.addDockWidget(dock_area, dock_wnd) else: self.addDockWidget(Qt.TopDockWidgetArea, dock_wnd) dock_wnd.setFloating(True) dock_wnd.setAllowedAreas(Qt.NoDockWidgetArea) dock_wnd.move(QApplication.desktop().screen().rect().center() - self.rect().center()) dock_wnd.setWidget(window) if dock_float: dock_wnd.setFloating(True) # self.geometry().center() - dock_wnd.rect().center() # dock_wnd.move() if dock_show: dock_wnd.show() else: dock_wnd.hide() sub_window_data.dock_wnd = dock_wnd
class InteractiveConsolePlugin(Plugin): locals = None def __init__(self, main_window_plugin: MainWindowPlugin): super().__init__() self.main_window = main_window_plugin.main_window self.console_widget = InteractiveConsoleWidget() self.console_widget.command_entered.connect(self.on_command_entered) self.interactive_console = self.create_console() self.dock_widget = QDockWidget('Interactive Console') self.dock_widget.setWidget(self.console_widget) self.dock_widget.hide() self.shortcut = QShortcut(Qt.CTRL + Qt.Key_Greater, self.main_window) def _install(self): self.main_window.addDockWidget(Qt.BottomDockWidgetArea, self.dock_widget) self.shortcut.activated.connect(self.on_shortcut_activated) def _remove(self): self.shortcut.activated.disconnect(self.on_shortcut_activated) self.main_window.removeDockWidget(self.dock_widget) # Remove all created references (otherwise some plugins may not be deleted) self.interactive_console.reset_locals() def create_console(self): return InteractiveConsole(self.locals.copy(), self.console_widget.append_output) def reset_console(self): self.interactive_console = self.create_console() def on_command_entered(self, command_text): stdout = io.StringIO() with redirect_stdout(stdout): more_input_required = self.interactive_console.push(command_text) output_text = stdout.getvalue() if output_text.endswith( '\n' ): # enter was redirected to stdout too, so we need to remove it output_text = output_text[:-1] if output_text: self.console_widget.append_output(output_text) print('InteractiveConsole >', output_text) self.console_widget.set_continue_input_prompt(more_input_required) def on_shortcut_activated(self): self.dock_widget.show() self.console_widget.focus_command_line()
def new_docked(self, widget, name, title, dock_area, hiden=False): dock = QDockWidget() dock.setWindowTitle(title) dock.setWidget(widget) if hiden: dock.hide() else: dock.show() self.main_window.addDockWidget(dock_area, dock) self.modules_dock[name] = dock return dock
class Browser(Application): # pylint: disable=too-many-instance-attributes """The main browser""" url_scheme: QWebEngineUrlScheme bridge_initialized: bool dev_view: QWebEngineView dev_page: WebPage qdock: QDockWidget def __init__(self): super().__init__() self.init() # self.load() def init(self): """Initialize browser""" logger.debug("Initializing Browser Window") if web_greeter_config["config"]["greeter"]["debug_mode"]: os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = '12345' url_scheme = "web-greeter" self.url_scheme = QWebEngineUrlScheme(url_scheme.encode()) self.url_scheme.setDefaultPort(QWebEngineUrlScheme.PortUnspecified) self.url_scheme.setFlags(QWebEngineUrlScheme.SecureScheme or QWebEngineUrlScheme.LocalScheme or QWebEngineUrlScheme.LocalAccessAllowed) QWebEngineUrlScheme.registerScheme(self.url_scheme) self.profile = QWebEngineProfile.defaultProfile() self.interceptor = QtUrlRequestInterceptor(url_scheme) self.url_scheme_handler = QtUrlSchemeHandler() self.view = QWebEngineView(parent=self.window) self.page = WebPage() self.view.setPage(self.page) self.page.setObjectName("WebG Page") self.view.setObjectName("WebG View") self.channel = QWebChannel(self.page) self.bridge_initialized = False self.profile.installUrlSchemeHandler(url_scheme.encode(), self.url_scheme_handler) self._initialize_page() if web_greeter_config["config"]["greeter"]["debug_mode"]: self._initialize_devtools() else: self.view.setContextMenuPolicy(Qt.PreventContextMenu) self._init_actions() if web_greeter_config["app"]["frame"]: self._init_menu_bar() else: self.window.setWindowFlags(self.window.windowFlags() | Qt.FramelessWindowHint) if web_greeter_config["config"]["greeter"]["secure_mode"]: if hasattr(QWebEngineProfile, "setUrlRequestInterceptor"): self.profile.setUrlRequestInterceptor(self.interceptor) else: # Older Qt5 versions self.profile.setRequestInterceptor(self.interceptor) self.page.setBackgroundColor(QColor(0, 0, 0)) self.window.setStyleSheet("""QMainWindow, QWebEngineView { background: #000000; }""") self.window.setCentralWidget(self.view) logger.debug("Browser Window created") def load(self): """Load theme and initialize bridge""" self.load_theme() self.bridge_objects = (self.greeter, self.greeter_config, self.theme_utils) self.initialize_bridge_objects() self.load_script(':/_greeter/js/bundle.js', 'Web Greeter Bundle') def _initialize_devtools(self): self.dev_view = QWebEngineView(parent=self.window) self.dev_page = WebPage() self.dev_view.setPage(self.dev_page) self.page.setDevToolsPage(self.dev_page) self.dev_view.setObjectName("Devtools view") self.dev_page.setObjectName("Devtools page") self.dev_page.windowCloseRequested.connect( lambda: self.toggle_devtools_value(False)) inspect_element_action = self.page.action(self.page.InspectElement) inspect_element_action.triggered.connect( lambda: self.toggle_devtools_value(True)) self.qdock = QDockWidget() self.qdock.setWidget(self.dev_view) self.qdock.setFeatures(QDockWidget.DockWidgetMovable or QDockWidget.DockWidgetClosable) self.window.addDockWidget(Qt.RightDockWidgetArea, self.qdock) self.qdock.hide() logger.debug("DevTools initialized") def toggle_devtools(self): """Toggle devtools""" if not web_greeter_config["config"]["greeter"]["debug_mode"]: return self.toggle_devtools_value(not self.qdock.isVisible()) def toggle_devtools_value(self, value: bool): """Toggle devtools by value""" if not web_greeter_config["config"]["greeter"]["debug_mode"]: return if value: self.qdock.show() self.dev_view.setFocus() else: self.qdock.hide() self.view.setFocus() def _init_actions(self): """Init browser actions""" self.exit_action = QAction(QIcon("exit.png"), "&Quit", self.window) self.exit_action.setShortcut("Ctrl+Q") self.exit_action.setStatusTip("Exit application") self.exit_action.triggered.connect(qApp.quit) self.toggle_dev_action = QAction("Toggle Developer Tools", self.window) self.toggle_dev_action.setShortcut("Ctrl+Shift+I") self.toggle_dev_action.triggered.connect(self.toggle_devtools) self.fullscreen_action = QAction("Toggle Fullscreen", self.window) self.fullscreen_action.setShortcut("F11") self.fullscreen_action.triggered.connect( lambda: self.toggle_fullscreen(not self.window.isFullScreen())) self.inc_zoom_action = QAction("Zoom In", self.window) self.inc_zoom_action.setShortcut("Ctrl++") self.inc_zoom_action.triggered.connect(self._inc_zoom) self.dec_zoom_action = QAction("Zoom Out", self.window) self.dec_zoom_action.setShortcut("Ctrl+-") self.dec_zoom_action.triggered.connect(self._dec_zoom) self.reset_zoom_action = QAction("Actual Size", self.window) self.reset_zoom_action.setShortcut("Ctrl+0") self.reset_zoom_action.triggered.connect(self._reset_zoom) self.window.addAction(self.exit_action) self.window.addAction(self.toggle_dev_action) self.window.addAction(self.fullscreen_action) self.window.addAction(self.inc_zoom_action) self.window.addAction(self.dec_zoom_action) self.window.addAction(self.reset_zoom_action) def _inc_zoom(self): if self.view.hasFocus(): self.page.increaseZoom() else: self.dev_page.increaseZoom() def _dec_zoom(self): if self.view.hasFocus(): self.page.decreaseZoom() else: self.dev_page.decreaseZoom() def _reset_zoom(self): if self.view.hasFocus(): self.page.setZoomFactor(1) else: self.dev_page.setZoomFactor(1) def _init_menu_bar(self): minimize_action = QAction("Minimize", self.window) minimize_action.setShortcut("Ctrl+M") minimize_action.triggered.connect(self.window.showMinimized) close_action = QAction("Close", self.window) close_action.setShortcut("Ctrl+W") close_action.triggered.connect(self.window.close) self.page.action( self.page.ReloadAndBypassCache).setText("Force Reload") self.page.fullScreenRequested.connect(self.accept_fullscreen) self.menu_bar = QMenuBar() file_menu = self.menu_bar.addMenu("&File") file_menu.addAction(self.exit_action) edit_menu = self.menu_bar.addMenu("&Edit") edit_menu.addAction(self.page.action(self.page.Undo)) edit_menu.addAction(self.page.action(self.page.Redo)) edit_menu.addSeparator() edit_menu.addAction(self.page.action(self.page.Cut)) edit_menu.addAction(self.page.action(self.page.Copy)) edit_menu.addAction(self.page.action(self.page.Paste)) edit_menu.addSeparator() edit_menu.addAction(self.page.action(self.page.SelectAll)) view_menu = self.menu_bar.addMenu("&View") view_menu.addAction(self.page.action(self.page.Reload)) view_menu.addAction(self.page.action(self.page.ReloadAndBypassCache)) view_menu.addAction(self.toggle_dev_action) view_menu.addSeparator() view_menu.addAction(self.reset_zoom_action) view_menu.addAction(self.inc_zoom_action) view_menu.addAction(self.dec_zoom_action) view_menu.addSeparator() view_menu.addAction(self.fullscreen_action) window_menu = self.menu_bar.addMenu("&Window") window_menu.addAction(minimize_action) window_menu.addAction(close_action) # help_menu = menu_bar.addMenu("&Help") self.window.setMenuBar(self.menu_bar) def accept_fullscreen(self, request): """Accepts fullscreen requests""" if web_greeter_config["config"]["greeter"]["debug_mode"]: request.reject() return if request.toggleOn(): self.toggle_fullscreen(True) else: self.toggle_fullscreen(False) request.accept() def toggle_fullscreen(self, value: bool): """Toggle fullscreen""" if not web_greeter_config["config"]["greeter"]["debug_mode"]: return if value: state = self.states["FULLSCREEN"] self.window.setWindowFlags(self.window.windowFlags() or Qt.FramelessWindowHint) self.menu_bar.setParent(None) self.window.setMenuBar(None) else: state = self.states["NORMAL"] self.window.setWindowFlags(self.window.windowFlags() or not Qt.FramelessWindowHint) self.window.setMenuBar(self.menu_bar) try: self.window.windowHandle().setWindowState(state) except (AttributeError, TypeError): self.window.setWindowState(state) def _initialize_page(self): page_settings = self.page.settings().globalSettings() if not web_greeter_config["config"]["greeter"]["secure_mode"]: ENABLED_SETTINGS.append('LocalContentCanAccessRemoteUrls') else: DISABLED_SETTINGS.append('LocalContentCanAccessRemoteUrls') for setting in DISABLED_SETTINGS: try: page_settings.setAttribute( getattr(QWebEngineSettings, setting), False) except AttributeError: pass for setting in ENABLED_SETTINGS: try: page_settings.setAttribute( getattr(QWebEngineSettings, setting), True) except AttributeError: pass self.page.setView(self.view) def load_theme(self): """Load theme""" theme = web_greeter_config["config"]["greeter"]["theme"] dir_t = "/usr/share/web-greeter/themes/" path_to_theme = os.path.join(dir_t, theme, "index.html") def_theme = "gruvbox" if theme.startswith("/"): path_to_theme = theme elif theme.__contains__(".") or theme.__contains__("/"): path_to_theme = os.path.join(os.getcwd(), theme) path_to_theme = os.path.realpath(path_to_theme) if not path_to_theme.endswith(".html"): path_to_theme = os.path.join(path_to_theme, "index.html") if not os.path.exists(path_to_theme): print("Path does not exists", path_to_theme) path_to_theme = os.path.join(dir_t, def_theme, "index.html") web_greeter_config["config"]["greeter"]["theme"] = path_to_theme url = QUrl(f"web-greeter://app/{path_to_theme}") self.page.load(url) logger.debug("Theme loaded") @staticmethod def _create_webengine_script(path: Url, name: str) -> QWebEngineScript: script = QWebEngineScript() script_file = QFile(path) # print(script_file, path) if script_file.open(QFile.ReadOnly): script_string = str(script_file.readAll(), 'utf-8') script.setInjectionPoint(QWebEngineScript.DocumentCreation) script.setName(name) script.setWorldId(QWebEngineScript.MainWorld) script.setSourceCode(script_string) # print(script_string) return script def _get_channel_api_script(self) -> QWebEngineScript: return self._create_webengine_script(':/qtwebchannel/qwebchannel.js', 'QWebChannel API') def _init_bridge_channel(self) -> None: self.page.setWebChannel(self.channel) self.bridge_initialized = True def initialize_bridge_objects(self) -> None: """Initialize bridge objects :D""" if not self.bridge_initialized: self._init_bridge_channel() registered_objects = self.channel.registeredObjects() for obj in self.bridge_objects: if obj not in registered_objects: # pylint: disable=protected-access self.channel.registerObject(obj._name, obj) # print("Registered", obj._name) def load_script(self, path: Url, name: str): """Loads a script in page""" qt_api = self._get_channel_api_script() qt_api_source = qt_api.sourceCode() script = self._create_webengine_script(path, name) script.setSourceCode(qt_api_source + "\n" + script.sourceCode()) self.page.scripts().insert(script)
class Kettle(QMainWindow): def __init__(self): super().__init__() self.init_ui() self.filename = "untitled" def save_file(self): name = self.filename if not self.filename or self.filename == "untitled": name = QFileDialog.getSaveFileName(self, 'Save File')[0] file = open(name, 'wt') save_text = self.current_editor.toPlainText() file.write(save_text) file.close() self.current_editor.set_change_name(self.tab_widget, False) def save_file_as(self): name = QFileDialog.getSaveFileName(self, 'Save File')[0] file = open(name, 'wt') save_text = self.current_editor.toPlainText() file.write(save_text) file.close() self.current_editor.set_change_name(self.tab_widget, False) def open_file(self): name = QFileDialog.getOpenFileName(self, 'Open File') self.filename = name[0] file_image_type = imghdr.what(name[0]) if file_image_type is not None: self.open_image(self.filename) else: file = open(name[0], 'r', encoding='utf-8', errors='ignore') with file: self.new_document(title=os.path.basename(self.filename)) self.current_editor.setPlainText(file.read()) self.current_editor.set_change_name(self.tab_widget, False) def open_image(self, filename): label = QLabel(self) pixmap = QPixmap(filename) label.setPixmap(pixmap) self.tab_widget.addTab(label, filename) self.tab_widget.setCurrentWidget(label) def run(self): run = subprocess.run([sys.executable, self.filename], stdout=subprocess.PIPE) print(run.stdout) def view_projectview(self, state): if state: self.dock_widget.show() config.update_config('view', 'view_projectview', 'True') else: self.dock_widget.hide() config.update_config('view', 'view_projectview', 'False') def load_project_structure(self, startpath, tree): for element in os.listdir(startpath): path_info = startpath + "/" + element parent_itm = QTreeWidgetItem( tree, [os.path.basename(element), os.path.join(startpath, element)]) if os.path.isdir(path_info): self.load_project_structure(path_info, parent_itm) parent_itm.setIcon(0, QIcon(themes.get_icon('folder.png'))) else: parent_itm.setIcon(0, QIcon(themes.get_icon('file.png'))) if not utils.str2bool( config.get_setting('General', 'show_hidden_items', 'False')): if element.startswith('.'): parent_itm.setHidden(True) def tree_clicked(self): self.filename = self.treeView.selectedItems()[0].text(1) if os.path.isdir(self.treeView.selectedItems()[0].text(1)): print("This is not a file, is a directory.") else: try: file_image_type = imghdr.what( self.treeView.selectedItems()[0].text(1)) if file_image_type is not None: self.open_image(self.treeView.selectedItems()[0].text(1)) else: file = open(self.treeView.selectedItems()[0].text(1), 'r', encoding='utf-8', errors='ignore') with file: text = file.read() self.new_document(title=os.path.basename( self.treeView.selectedItems()[0].text(1))) self.current_editor.setPlainText(text) self.current_editor.set_change_name( self.tab_widget, False) except FileNotFoundError as error: print("No such file found : " + str(error)) QMessageBox.question(self, 'Error', 'Error occured : ' + str(error), QMessageBox.Close) if self.filename.endswith('.html'): html_preview = HTMLPreview(self.filename, self.current_editor) self.addDockWidget(Qt.RightDockWidgetArea, html_preview) elif self.filename.endswith('.md'): markdown_preview = MarkdownPreview(self.filename, self.current_editor) self.addDockWidget(Qt.RightDockWidgetArea, markdown_preview) def open_prof(self): proj_folder = str( QFileDialog.getExistingDirectory(self, 'Select Directory')) self.treeView.clear() self.load_project_structure(proj_folder, self.treeView) self.treeView.setHeaderHidden(False) self.treeView.setHeaderLabel( os.path.basename(os.path.normpath(proj_folder))) config.update_config('General', 'last_opened_project', proj_folder) self.project_folder = proj_folder def open_settings(self): settings = Settings(self, themes) settings.show() def open_github_link(self): url = QUrl('https://github.com/Mozzo1000/kettle/') if not QDesktopServices.openUrl(url): QMessageBox.warning(self, 'Open URL', 'Could not open url') def open_about(self): about = About(self) about.show() def create_editor(self): text_editor = CodeEditor(config, themes) text_editor.textChanged.connect(self.on_text_changed) return text_editor def on_text_changed(self): self.current_editor.set_change_name(self.tab_widget) def remove_editor(self, index): if index is False: index = self.tab_widget.currentIndex() self.tab_widget.removeTab(index) if index < len(self.editors): del self.editors[index] def change_text_editor(self, index): if index < len(self.editors): self.current_editor = self.editors[index] def new_document(self, checked=False, title="Untitled"): self.current_editor = self.create_editor() self.current_editor.cursorPositionChanged.connect( self.statusbar.status_line_position) self.editors.append(self.current_editor) self.tab_widget.addTab(self.current_editor, str(title) + " - " + str(len(self.editors))) self.tab_widget.setCurrentWidget(self.current_editor) def open_notes_graph(self): notes_graph = NotesGraph(self) self.addDockWidget(Qt.BottomDockWidgetArea, notes_graph) def create_notes_project(self): notes_project = CreateNotesProject(self) notes_project.show() def init_ui(self): self.resize(800, 600) self.setWindowTitle('Kettle') self.current_editor = self.create_editor() self.editors = [] self.central_widget = QWidget(self) QFontDatabase.addApplicationFont('../assets/font/Monoid-Regular.ttf') sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) #self.statusbar = self.statusBar() self.statusbar = Statusbar(self) self.setStatusBar(self.statusbar) self.horizontal_layoutW = QWidget(self.central_widget) self.splitter = QSplitter(self.central_widget) self.tab_widget = QTabWidget(self.central_widget) self.tab_widget.setTabsClosable(True) self.tab_widget.currentChanged.connect(self.change_text_editor) self.tab_widget.tabCloseRequested.connect(self.remove_editor) self.new_document() self.dock_widget = QDockWidget('Project View', self.central_widget) print(self.sizeHint()) self.horizontal_layout = QHBoxLayout(self.central_widget) self.horizontal_layout.setSizeConstraint(QLayout.SetMaximumSize) self.treeView = QTreeWidget(self.central_widget) self.treeView.header().hide() self.treeView.itemDoubleClicked.connect(self.tree_clicked) self.dock_widget.setWidget(self.treeView) self.splitter.addWidget(self.tab_widget) self.horizontal_layout.addWidget(self.splitter) self.setCentralWidget(self.central_widget) self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_widget) if utils.str2bool( config.get_setting('view', 'view_projectview', 'True')): self.dock_widget.show() else: self.dock_widget.hide() self.statusbar.showMessage('Line 0 | Column 0') self.splitter.setSizes([5, 300]) if config.get_setting('General', 'last_opened_project'): self.load_project_structure( config.get_setting('General', 'last_opened_project'), self.treeView) self.project_folder = config.get_setting('General', 'last_opened_project') exit_action = QAction(QIcon('exit.png'), '&Exit', self) exit_action.setShortcut('Ctrl+Q') exit_action.setStatusTip('Exit application') exit_action.triggered.connect(qApp.quit) new_action = QAction('New', self) new_action.triggered.connect(self.new_document) new_action.setShortcut('Ctrl+N') save_action = QAction('Save', self) save_action.triggered.connect(self.save_file) save_action.setShortcut('Ctrl+S') save_as_action = QAction("Save as..", self) save_as_action.triggered.connect(self.save_file_as) save_as_action.setShortcut('Ctrl+Alt+S') open_action = QAction('Open', self) open_action.triggered.connect(self.open_file) open_action.setShortcut('Ctrl+O') open_proj_action = QAction('Open Project', self) open_proj_action.triggered.connect(self.open_prof) settings_action = QAction('Settings', self) settings_action.triggered.connect(self.open_settings) undo_action = QAction('Undo', self) undo_action.triggered.connect(self.current_editor.undo) undo_action.setShortcut('Ctrl+Z') redo_action = QAction('Redo', self) redo_action.triggered.connect(self.current_editor.redo) redo_action.setShortcut('Ctrl+Y') cut_action = QAction('Cut', self) cut_action.triggered.connect(self.current_editor.cut) cut_action.setShortcut('Ctrl+X') copy_action = QAction('Copy', self) copy_action.triggered.connect(self.current_editor.copy) copy_action.setShortcut('Ctrl+C') paste_action = QAction('Paste', self) paste_action.triggered.connect(self.current_editor.paste) paste_action.setShortcut('Ctrl+V') select_all_action = QAction('Select all', self) select_all_action.triggered.connect(self.current_editor.selectAll) select_all_action.setShortcut('Ctrl+A') run_action = QAction('Run', self) run_action.triggered.connect(self.run) run_action.setShortcut('Ctrl+SPACE') view_status_action = QAction('View statusbar', self, checkable=True) view_status_action.setChecked( utils.str2bool(config.get_setting('view', 'view_statusbar'))) view_status_action.triggered.connect(self.statusbar.view_status) view_projectview_action = QAction('View project view', self, checkable=True) view_projectview_action.setChecked( utils.str2bool( config.get_setting('view', 'view_projectview', 'True'))) view_projectview_action.triggered.connect(self.view_projectview) github_link_action = QAction('Github', self) github_link_action.triggered.connect(self.open_github_link) about_action = QAction('About', self) about_action.triggered.connect(self.open_about) close_current_editor_action = QAction('Close current file', self) close_current_editor_action.triggered.connect(self.remove_editor) close_current_editor_action.setShortcut('Ctrl+W') open_notes_graph_action = QAction('Open graph', self) open_notes_graph_action.triggered.connect(self.open_notes_graph) create_new_notes_project_action = QAction('Create notes project', self) create_new_notes_project_action.triggered.connect( self.create_notes_project) menubar = self.menuBar() notes_menu = QMenu('Notes', self) file_menu = menubar.addMenu('&File') edit_menu = menubar.addMenu('&Edit') run_menu = menubar.addMenu('&Run') view_menu = menubar.addMenu('&View') help_menu = menubar.addMenu('&Help') notes_menu.addAction(open_notes_graph_action) notes_menu.addAction(create_new_notes_project_action) file_menu.addAction(new_action) file_menu.addAction(open_action) file_menu.addAction(open_proj_action) file_menu.addAction(save_action) file_menu.addAction(save_as_action) file_menu.addAction(close_current_editor_action) file_menu.addAction(settings_action) file_menu.addAction(exit_action) file_menu.addMenu(notes_menu) edit_menu.addAction(undo_action) edit_menu.addAction(redo_action) edit_menu.addAction(cut_action) edit_menu.addAction(copy_action) edit_menu.addAction(paste_action) edit_menu.addAction(select_all_action) run_menu.addAction(run_action) view_menu.addAction(view_status_action) view_menu.addAction(view_projectview_action) help_menu.addAction(github_link_action) help_menu.addAction(about_action) self.showMaximized() self.show()
class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.centralwidget.hide() self.parser = argparse.ArgumentParser("playground") self.parser.add_argument("-d", "--data-dir", type=str, help="data dir") self.parser.add_argument("-a", "--console-address", type=str, help="console address", default='localhost') self.parser.add_argument("-p", "--console-port", type=int, help="console port", default=2222) self.args = self.parser.parse_args() self.data_dir = self.args.data_dir self.console_port = self.args.console_port self.console_address = self.args.console_address self.project = CetechProject() self.api = QtConsoleAPI(self.console_address, self.console_port) self.setTabPosition(Qt.AllDockWidgetAreas, QTabWidget.North) self.script_editor_widget = ScriptEditor(project_manager=self.project, api=self.api) self.script_editor_dock_widget = QDockWidget(self) self.script_editor_dock_widget.setWindowTitle("Script editor") self.script_editor_dock_widget.hide() self.script_editor_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures) self.script_editor_dock_widget.setWidget(self.script_editor_widget) self.addDockWidget(Qt.TopDockWidgetArea, self.script_editor_dock_widget) self.log_widget = LogWidget(self.api, self.script_editor_widget) self.log_dock_widget = QDockWidget(self) self.log_dock_widget.hide() self.log_dock_widget.setWindowTitle("Log") self.log_dock_widget.setWidget(self.log_widget) self.addDockWidget(Qt.BottomDockWidgetArea, self.log_dock_widget) self.assetb_widget = AssetBrowser() self.assetb_dock_widget = QDockWidget(self) self.assetb_dock_widget.hide() self.assetb_dock_widget.setWindowTitle("Asset browser") self.assetb_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures) self.assetb_dock_widget.setWidget(self.assetb_widget) self.addDockWidget(Qt.LeftDockWidgetArea, self.assetb_dock_widget) self.recorded_event_widget = RecordEventWidget(api=self.api) self.recorded_event_dock_widget = QDockWidget(self) self.recorded_event_dock_widget.setWindowTitle("Recorded events") self.recorded_event_dock_widget.hide() self.recorded_event_dock_widget.setFeatures(QDockWidget.AllDockWidgetFeatures) self.recorded_event_dock_widget.setWidget(self.recorded_event_widget) self.addDockWidget(Qt.RightDockWidgetArea, self.recorded_event_dock_widget) #TODO bug #114 workaround. Disable create sub engine... if platform.system().lower() != 'darwin': self.ogl_widget = CetechWidget(self, self.api) self.ogl_dock = QDockWidget(self) self.ogl_dock.hide() self.ogl_dock.setWidget(self.ogl_widget) self.addDockWidget(Qt.TopDockWidgetArea, self.ogl_dock) self.tabifyDockWidget(self.assetb_dock_widget, self.log_dock_widget) self.assetb_widget.asset_clicked.connect(self.open_asset) self.file_watch = QFileSystemWatcher(self) self.file_watch.fileChanged.connect(self.file_changed) self.file_watch.directoryChanged.connect(self.dir_changed) self.build_file_watch = QFileSystemWatcher(self) self.build_file_watch.fileChanged.connect(self.build_file_changed) self.build_file_watch.directoryChanged.connect(self.build_dir_changed) def open_asset(self, path, ext): if self.script_editor_widget.support_ext(ext): self.script_editor_widget.open_file(path) self.script_editor_dock_widget.show() self.script_editor_dock_widget.focusWidget() def open_project(self, name, dir): self.project.open_project(name, dir) # self.project.run_cetech(build_type=CetechProject.BUILD_DEBUG, compile=True, continu=True, daemon=True) if platform.system().lower() == 'darwin': wid = None else: wid = self.ogl_widget.winId() self.project.run_cetech(build_type=CetechProject.BUILD_DEBUG, compile_=True, continue_=True, wid=wid) self.api.start(QThread.LowPriority) self.assetb_widget.open_project(self.project.project_dir) self.assetb_dock_widget.show() self.log_dock_widget.show() #TODO bug #114 workaround. Disable create sub engine... if platform.system().lower() != 'darwin': self.ogl_dock.show() self.watch_project_dir() def watch_project_dir(self): files = self.file_watch.files() directories = self.file_watch.directories() if len(files): self.file_watch.removePaths(files) if len(directories): self.file_watch.removePaths(directories) files = self.build_file_watch.files() directories = self.build_file_watch.directories() if len(files): self.build_file_watch.removePaths(files) if len(directories): self.build_file_watch.removePaths(directories) files = [] it = QDirIterator(self.project.source_dir, QDirIterator.Subdirectories) while it.hasNext(): files.append(it.next()) self.file_watch.addPaths(files) files = [] it = QDirIterator(self.project.build_dir, QDirIterator.Subdirectories) while it.hasNext(): files.append(it.next()) self.build_file_watch.addPaths(files) def file_changed(self, path): self.api.compile_all() def dir_changed(self, path): self.watch_project_dir() def build_file_changed(self, path): self.api.autocomplete_list() def build_dir_changed(self, path): pass def open_script_editor(self): self.script_editor_dock_widget.show() def open_recorded_events(self): self.recorded_event_dock_widget.show() def closeEvent(self, evnt): self.api.disconnect() self.project.killall_process() self.statusbar.showMessage("Disconnecting ...") while self.api.connected: self.api.tick() self.statusbar.showMessage("Disconnected") evnt.accept()
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.chunk_directory = Directory( "CHUNK", QIcon(Assets.get_asset_path("document_a4_locked.png")), None) self.mod_directory = Directory( "MOD", QIcon(Assets.get_asset_path("document_a4.png")), None) self.workspace = Workspace([self.mod_directory, self.chunk_directory], parent=self) self.workspace.fileOpened.connect(self.handle_workspace_file_opened) self.workspace.fileClosed.connect(self.handle_workspace_file_closed) self.workspace.fileActivated.connect( self.handle_workspace_file_activated) self.workspace.fileLoadError.connect( self.handle_workspace_file_load_error) self.init_actions() self.init_menu_bar() self.init_toolbar() self.setStatusBar(QStatusBar()) self.setWindowTitle("MHW-Editor-Suite") self.init_file_tree(self.chunk_directory, "Chunk directory", self.open_chunk_directory_action, filtered=True) self.init_file_tree(self.mod_directory, "Mod directory", self.open_mod_directory_action) self.init_help() self.setCentralWidget(self.init_editor_tabs()) self.load_settings() def closeEvent(self, event): self.write_settings() def load_settings(self): self.settings = AppSettings() with self.settings.main_window() as group: size = group.get("size", QSize(1000, 800)) position = group.get("position", QPoint(300, 300)) with self.settings.application() as group: chunk_directory = group.get("chunk_directory", None) mod_directory = group.get("mod_directory", None) lang = group.get("lang", None) with self.settings.import_export() as group: self.import_export_default_attrs = { key: group.get(key, "").split(";") for key in group.childKeys() } # apply settings self.resize(size) self.move(position) if chunk_directory: self.chunk_directory.set_path(chunk_directory) if mod_directory: self.mod_directory.set_path(mod_directory) if lang: self.handle_set_lang_action(lang) def write_settings(self): with self.settings.main_window() as group: group["size"] = self.size() group["position"] = self.pos() with self.settings.application() as group: group["chunk_directory"] = self.chunk_directory.path group["mod_directory"] = self.mod_directory.path group["lang"] = FilePluginRegistry.lang with self.settings.import_export() as group: for key, value in self.import_export_default_attrs.items(): group[key] = ";".join(value) def get_icon(self, name): return self.style().standardIcon(name) def init_actions(self): self.open_chunk_directory_action = create_action( self.get_icon(QStyle.SP_DirOpenIcon), "Open chunk_directory ...", self.handle_open_chunk_directory, None) self.open_mod_directory_action = create_action( self.get_icon(QStyle.SP_DirOpenIcon), "Open mod directory ...", self.handle_open_mod_directory, QKeySequence.Open) self.save_file_action = create_action( self.get_icon(QStyle.SP_DriveHDIcon), "Save file", self.handle_save_file_action, QKeySequence.Save) self.save_file_action.setDisabled(True) self.export_action = create_action(self.get_icon(QStyle.SP_FileIcon), "Export file ...", self.handle_export_file_action) self.export_action.setDisabled(True) self.import_action = create_action(self.get_icon(QStyle.SP_FileIcon), "Import file ...", self.handle_import_file_action) self.import_action.setDisabled(True) self.help_action = create_action(None, "Show help", self.handle_show_help_action) self.about_action = create_action(None, "About", self.handle_about_action) self.lang_actions = { lang: create_action(None, name, partial(self.handle_set_lang_action, lang), checkable=True) for lang, name in LANG } self.quick_access_actions = [ create_action( None, title, partial(self.workspace.open_file_any_dir, file_rel_path)) for title, file_rel_path in QUICK_ACCESS_ITEMS ] def init_menu_bar(self): menu_bar = self.menuBar() # file menu file_menu = menu_bar.addMenu("File") file_menu.insertAction(None, self.open_chunk_directory_action) file_menu.insertAction(None, self.open_mod_directory_action) file_menu.insertAction(None, self.export_action) file_menu.insertAction(None, self.import_action) file_menu.insertAction(None, self.save_file_action) quick_access_menu = menu_bar.addMenu("Quick Access") for action in self.quick_access_actions: quick_access_menu.insertAction(None, action) # lang menu lang_menu = menu_bar.addMenu("Language") for action in self.lang_actions.values(): lang_menu.insertAction(None, action) # help menu help_menu = menu_bar.addMenu("Help") help_menu.insertAction(None, self.help_action) help_menu.insertAction(None, self.about_action) def init_toolbar(self): toolbar = self.addToolBar("Main") toolbar.setIconSize(QSize(16, 16)) toolbar.setFloatable(False) toolbar.setMovable(False) toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) toolbar.insertAction(None, self.open_mod_directory_action) toolbar.insertAction(None, self.save_file_action) def init_file_tree(self, directory, title, action, filtered=False): widget = DirectoryDockWidget(directory, filtered=filtered, parent=self) widget.path_label.addAction(action, QLineEdit.LeadingPosition) widget.tree_view.activated.connect( partial(self.handle_directory_tree_view_activated, directory)) dock = QDockWidget(title, self) dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) dock.setFeatures(QDockWidget.DockWidgetMovable) dock.setWidget(widget) self.addDockWidget(Qt.LeftDockWidgetArea, dock) def init_help(self): self.help_widget = HelpWidget(self) self.help_widget_dock = QDockWidget("Help", self) self.help_widget_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.help_widget_dock.setFeatures(QDockWidget.DockWidgetMovable) self.help_widget_dock.setWidget(self.help_widget) self.addDockWidget(Qt.RightDockWidgetArea, self.help_widget_dock) self.help_widget_dock.hide() def handle_show_help_action(self): if self.help_widget_dock.isVisible(): self.help_widget_dock.hide() else: self.help_widget_dock.show() def handle_directory_tree_view_activated(self, directory, qindex: QModelIndex): if qindex.model().isDir(qindex): return file_path = qindex.model().filePath(qindex) self.workspace.open_file(directory, file_path) def init_editor_tabs(self): self.editor_tabs = QTabWidget() self.editor_tabs.setDocumentMode(True) self.editor_tabs.setTabsClosable(True) self.editor_tabs.tabCloseRequested.connect( self.handle_editor_tab_close_requested) return self.editor_tabs def handle_workspace_file_opened(self, path, rel_path): ws_file = self.workspace.files[path] editor_view = EditorView.factory(self.editor_tabs, ws_file) editor_view.setObjectName(path) self.editor_tabs.addTab(editor_view, ws_file.directory.file_icon, f"{ws_file.directory.name}: {rel_path}") self.editor_tabs.setCurrentWidget(editor_view) self.save_file_action.setDisabled(False) self.export_action.setDisabled(False) self.import_action.setDisabled(False) def handle_workspace_file_activated(self, path, rel_path): widget = self.editor_tabs.findChild(QWidget, path) self.editor_tabs.setCurrentWidget(widget) def handle_workspace_file_closed(self, path, rel_path): widget = self.editor_tabs.findChild(QWidget, path) widget.deleteLater() has_no_files_open = not self.workspace.files self.save_file_action.setDisabled(has_no_files_open) self.export_action.setDisabled(has_no_files_open) self.import_action.setDisabled(has_no_files_open) def handle_workspace_file_load_error(self, path, rel_path, error): QMessageBox.warning(self, f"Error loading file `{rel_path}`", f"Error while loading\n{path}:\n\n{error}", QMessageBox.Ok, QMessageBox.Ok) def handle_editor_tab_close_requested(self, tab_index): editor_view = self.editor_tabs.widget(tab_index) self.workspace.close_file(editor_view.workspace_file) def handle_open_chunk_directory(self): path = QFileDialog.getExistingDirectory(parent=self, caption="Open chunk directory") if path: self.chunk_directory.set_path(os.path.normpath(path)) def handle_open_mod_directory(self): path = QFileDialog.getExistingDirectory(parent=self, caption="Open mod directory") if path: self.mod_directory.set_path(os.path.normpath(path)) def handle_save_file_action(self): main_ws_file = self.get_current_workspace_file() for ws_file in main_ws_file.get_files_modified(): if ws_file.directory is self.chunk_directory: if self.mod_directory.is_valid: self.transfer_file_to_mod_workspace( ws_file, ws_file is main_ws_file) else: self.save_base_content_file(ws_file) else: with show_error_dialog(self, "Error writing file"): self.save_workspace_file(ws_file) def handle_export_file_action(self): ws_file = self.get_current_workspace_file() plugin = FilePluginRegistry.get_plugin(ws_file.abs_path) fields = plugin.data_factory.EntryFactory.fields() data = [it.as_dict() for it in ws_file.data.entries] dialog = ExportDialog.init(self, data, fields, plugin.import_export.get("safe_attrs")) dialog.open() def handle_import_file_action(self): ws_file = self.get_current_workspace_file() plugin = FilePluginRegistry.get_plugin(ws_file.abs_path) fields = plugin.data_factory.EntryFactory.fields() dialog = ImportDialog.init(self, fields, plugin.import_export.get("safe_attrs"), as_list=True) if dialog: dialog.import_accepted.connect(self.handle_import_accepted) dialog.open() def handle_import_accepted(self, import_data): ws_file = self.get_current_workspace_file() num_items = min(len(import_data), len(ws_file.data)) for idx in range(num_items): ws_file.data[idx].update(import_data[idx]) self.statusBar().showMessage( f"Import contains {len(import_data)} items. " f"Model contains {len(ws_file.data)} items. " f"Imported {num_items}.", STATUSBAR_MESSAGE_TIMEOUT) def handle_set_lang_action(self, lang): FilePluginRegistry.lang = lang for act in self.lang_actions.values(): act.setChecked(False) self.lang_actions[lang].setChecked(True) def get_current_workspace_file(self): editor = self.editor_tabs.currentWidget() return editor.workspace_file def save_base_content_file(self, ws_file): result = QMessageBox.question( self, "Save base content file?", "Do you really want to update this chunk file?", QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Cancel) if result == QMessageBox.Ok: with show_error_dialog(self, "Error writing file"): self.save_workspace_file(ws_file) def transfer_file_to_mod_workspace(self, ws_file, reopen=False): mod_abs_path, exists = self.mod_directory.get_child_path( ws_file.rel_path) if not exists: return self.transfer_file(ws_file, self.mod_directory, reopen) result = QMessageBox.question( self, "File exists, overwrite?", f"File '{ws_file.rel_path}' already found in mod directory, overwrite?", QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok) if result == QMessageBox.Ok: self.transfer_file(ws_file, self.mod_directory, reopen) def transfer_file(self, ws_file, target_directory, reopen=False): if target_directory is ws_file.directory: return self.workspace.close_file(ws_file) ws_file.set_directory(target_directory) self.save_workspace_file(ws_file) if reopen: self.workspace.open_file(target_directory, ws_file.abs_path) def save_workspace_file(self, ws_file): ws_file.save() self.statusBar().showMessage(f"File '{ws_file.abs_path}' saved.", STATUSBAR_MESSAGE_TIMEOUT) def handle_about_action(self): dialog = QDialog(self) dialog.setWindowTitle("About MHW Editor Suite") layout = QVBoxLayout() dialog.setLayout(layout) about_text = QLabel(ABOUT_TEXT) about_text.setTextFormat(Qt.RichText) about_text.setTextInteractionFlags(Qt.TextBrowserInteraction) about_text.setOpenExternalLinks(True) layout.addWidget(about_text) dialog.exec()
class GUIWindow(QMainWindow): def __init__(self, app, pipeline=Pipeline()): super().__init__() self._app = app self._logger = logging.getLogger(self.__class__.__name__) self._is_initialized = False self.init_basic(pipeline) self.init_ui() self.init_controls() self.setWindowTitle("Cognigraph") self.setWindowIcon(QIcon(':/cognigraph_icon.png')) def init_basic(self, pipeline): self._pipeline = pipeline # type: Pipeline self._updater = AsyncUpdater(self._app, pipeline) self._pipeline._signal_sender.long_operation_started.connect( self._show_progress_dialog) self._pipeline._signal_sender.long_operation_finished.connect( self._hide_progress_dialog) self._pipeline._signal_sender.request_message.connect( self._show_message) self._pipeline._signal_sender.node_widget_added.connect( self._on_node_widget_added) self._controls = Controls(pipeline=self._pipeline) self._controls.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self._controls.tree_widget.node_removed.connect(self._on_node_removed) if hasattr(self, "central_widget"): for w in self.central_widget.subWindowList(): self.central_widget.removeSubWindow(w) def init_controls(self): self.controls_dock.setWidget(self._controls) self.run_toggle_action.triggered.disconnect() self.run_toggle_action.triggered.connect(self._updater.toggle) self._updater._sender.run_toggled.connect(self._on_run_button_toggled) self._updater._sender.errored.connect(self._show_message) self.is_initialized = False def init_ui(self): self.central_widget = QMdiArea() self.setCentralWidget(self.central_widget) # -------- controls widget -------- # self.controls_dock = QDockWidget("Processing pipeline setup", self) self.controls_dock.setObjectName("Controls") self.controls_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.controls_dock.visibilityChanged.connect( self._update_pipeline_tree_widget_action_text) self.addDockWidget(Qt.LeftDockWidgetArea, self.controls_dock) # self._controls.setMinimumWidth(800) # --------------------------------- # file_menu = self.menuBar().addMenu("&File") # file menu load_pipeline_action = self._createAction("&Load pipeline", self._load_pipeline) save_pipeline_action = self._createAction("&Save pipeline", self._save_pipeline) file_menu.addAction(load_pipeline_action) file_menu.addAction(save_pipeline_action) # -------- view menu & toolbar -------- # tile_windows_action = self._createAction( "&Tile windows", self.central_widget.tileSubWindows) view_menu = self.menuBar().addMenu("&View") view_menu.addAction(tile_windows_action) view_toolbar = self.addToolBar("View") view_toolbar.addAction(tile_windows_action) # ------------------------------------- # edit_menu = self.menuBar().addMenu("&Edit") self._toggle_pipeline_tree_widget_action = self._createAction( "&Hide pipeline settings", self._toggle_pipeline_tree_widget) edit_menu.addAction(self._toggle_pipeline_tree_widget_action) edit_toolbar = self.addToolBar("Edit") edit_toolbar.setObjectName("edit_toolbar") edit_toolbar.addAction(self._toggle_pipeline_tree_widget_action) # -------- run menu & toolbar -------- # self.run_toggle_action = self._createAction( "&Start", self._on_run_button_toggled) run_menu = self.menuBar().addMenu("&Run") self.initialize_pipeline = self._createAction("&Initialize pipeline", self.initialize) run_menu.addAction(self.run_toggle_action) run_menu.addAction(self.initialize_pipeline) run_toolbar = self.addToolBar("Run") run_toolbar.setObjectName("run_toolbar") run_toolbar.addAction(self.run_toggle_action) run_toolbar.addAction(self.initialize_pipeline) # ------------------------------------ # def _toggle_pipeline_tree_widget(self): if self.controls_dock.isHidden(): self.controls_dock.show() else: self.controls_dock.hide() def _update_pipeline_tree_widget_action_text(self, is_visible): if is_visible: self._toggle_pipeline_tree_widget_action.setText( "&Hide pipelne settings") else: self._toggle_pipeline_tree_widget_action.setText( "&Show pipelne settings") def _load_pipeline(self): file_dialog = QFileDialog(caption="Select pipeline file", directory=PIPELINES_DIR) ext_filter = "JSON file (*.json);; All files (*.*)" pipeline_path = file_dialog.getOpenFileName(filter=ext_filter)[0] if pipeline_path: self._logger.info("Loading pipeline configuration from %s" % pipeline_path) if not self._updater.is_paused: self.run_toggle_action.trigger() with open(pipeline_path, "r") as db: try: params_dict = json.load(db) except json.decoder.JSONDecodeError as e: self._show_message("Bad pipeline configuration file", detailed_text=str(e)) pipeline = self.assemble_pipeline(params_dict, "Pipeline") self.init_basic(pipeline) self.init_controls() # self.resize(self.sizeHint()) else: return def _save_pipeline(self): self._logger.info("Saving pipeline") file_dialog = QFileDialog(caption="Select pipeline file", directory=PIPELINES_DIR) ext_filter = "JSON file (*.json);; All files (*.*)" pipeline_path = file_dialog.getSaveFileName(filter=ext_filter)[0] if pipeline_path: self._logger.info("Saving pipeline configuration to %s" % pipeline_path) try: self._pipeline.save_pipeline(pipeline_path) except Exception as exc: self._show_message( "Cant`t save pipeline configuration to %s" % pipeline_path, detailed_text=str(exc), ) self._logger.exception(exc) def assemble_pipeline(self, d, class_name): node_class = getattr(nodes, class_name) node = node_class(**d["init_args"]) for child_class_name in d["children"]: child = self.assemble_pipeline(d["children"][child_class_name], child_class_name) node.add_child(child) return node def initialize(self): is_paused = self._updater.is_paused if not is_paused: self._updater.stop() self._logger.info("Initializing all nodes") async_initer = AsyncPipelineInitializer(pipeline=self._pipeline, parent=self) async_initer.no_blocking_execution() for node in self._pipeline.all_nodes: if hasattr(node, "widget"): if not node.widget.parent(): # widget not added to QMdiArea self._add_subwindow(node.widget, repr(node)) self.central_widget.tileSubWindows() self.run_toggle_action.setDisabled(False) if not is_paused: self._updater.start() def _finish_initialization(self): self.progress_dialog.hide() self.progress_dialog.deleteLater() for node in self._pipeline.all_nodes: if hasattr(node, "widget"): self._add_subwindow(node.widget, repr(node)) self.central_widget.tileSubWindows() def _add_subwindow(self, widget, title): sw = _HookedSubWindow(self.central_widget) sw.setWidget(widget) sw.setWindowTitle(title) widget.show() def _show_progress_dialog(self, text): # -------- setup progress dialog -------- # self.progress_dialog = QProgressDialog(self) self.progress_dialog.setLabelText(text) self.progress_dialog.setCancelButtonText(None) self.progress_dialog.setRange(0, 0) self.progress_dialog.show() def _hide_progress_dialog(self): self.progress_dialog.hide() self.progress_dialog.deleteLater() def _on_subwindow_close(self, close_event): pass def _on_node_widget_added(self, widget, widget_name): self._add_subwindow(widget, widget_name) self.central_widget.tileSubWindows() def _on_node_removed(self, tree_item): if hasattr(tree_item.node, "widget"): try: self.central_widget.removeSubWindow( tree_item.node.widget.parent()) except AttributeError: pass except Exception as exc: self._show_message( "Can`t remove widget for %s" % tree_item.node, detailed_text=str(exc), ) self._logger.exception(exc) def _show_message(self, text, detailed_text=None, level="error"): if level == "error": icon = QMessageBox.Critical elif level == "warning": icon = QMessageBox.Warning elif level == "info": icon = QMessageBox.Information msg = QMessageBox(self) msg.setIcon(icon) msg.setText(text) msg.setDetailedText(detailed_text) msg.show() def _createAction( self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, ): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if slot is not None: action.triggered.connect(slot) if checkable: action.setCheckable(True) return action def moveEvent(self, event): return super(GUIWindow, self).moveEvent(event) def _on_run_button_toggled(self, is_paused=True): if is_paused: self.run_toggle_action.setText("Start") else: self.run_toggle_action.setText("Pause") @property def is_initialized(self): return self._is_initialized @is_initialized.setter def is_initialized(self, value): if value: self.run_toggle_action.setDisabled(False) else: self.run_toggle_action.setDisabled(True) self._is_initialized = value @property def _node_widgets(self) -> List[QWidget]: node_widgets = list() for node in self._pipeline.all_nodes: try: node_widgets.append(node.widget) except AttributeError: pass return node_widgets
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.root_folder = os.path.expanduser("~") self.logger = logging.getLogger(name='MainWindow Logger') self.set_main_widget() #create menus self.file_menu = self.menuBar().addMenu('&File') self.view_menu = self.menuBar().addMenu('View') self.video_menu = self.menuBar().addMenu('Video') self.tracking_menu = self.menuBar().addMenu('Tracking') self.analysis_menu = self.menuBar().addMenu('Analysis') #create toolbar for navigating through videos self.video_toolbar = self.addToolBar('Video') self.video_trackbar = self.addToolBar('Video Track Bar') self.set_file_menu() self.set_video_menu() self.set_tracking_menu() self.set_analysis_menu() self.set_slider() self.set_status() self.set_file_explorer() self.set_statistic_toolbar() self.set_classification_toolbar() self.set_view_menu() def set_main_widget(self): self.video_player = MainVideoPlayer() self.setCentralWidget(self.video_player) def add_menu_action(self, menu, name, connection, status_tip, shortcut=None, icon=None, tool_bar=None, return_action=False): """Helper function for adding a QAction to a menu. Parameters ---------- menu : QMenu Which menu to add new QAction to. name : string Name of new QAction. This is displayed as the QAction text in the QMenu. connection : function Which function should the QAction be connected to. status_tip : string Status tip to display on MouseOver. shortcut : QKeySequence or None (default = None) Shortcut to execute action. icon : QIcon or None (default = None) Icon to attach to QAction. tool_bar : QToolBar or None QToolBar to attach QAction to (in addition to the specified QMenu). return_action : bool (default = False) Whether or not to return the action. """ if icon is None: action = QAction(name, self) else: action = QAction(icon, name, self) if shortcut is not None: action.setShortcut(shortcut) action.setStatusTip(status_tip) action.triggered.connect(connection) menu.addAction(action) if tool_bar is not None: tool_bar.addAction(action) if return_action: return action def set_file_menu(self): self.add_menu_action(menu=self.file_menu, name='Open Directory', connection=self.open_file_directory, status_tip='Open a folder in the file explorer.', shortcut=QKeySequence.Open) self.add_menu_action(menu=self.file_menu, name='Open Video', connection=self.open_video, status_tip='Open an individual video.', shortcut=None) self.add_menu_action( menu=self.file_menu, name='Open Tracking Summary', connection=self.open_tracking_summary, status_tip='Open a tracked video file (.fcts, .xlsx, etc)') def set_view_menu(self): """Sets up menu to allow users to select which DockWidgets/ToolBars are displayed.""" #file explorer display_file_explorer_action = self.file_dock_widget.toggleViewAction() self.view_menu.addAction(display_file_explorer_action) #statistic widget display_statistic_widget_action = self.statistic_toolbar.toggleViewAction( ) self.view_menu.addAction(display_statistic_widget_action) #video toolbar display_video_toolbar_action = self.video_toolbar.toggleViewAction() self.view_menu.addAction(display_video_toolbar_action) #slider toolbar display_slider_toolbar_action = self.video_trackbar.toggleViewAction() self.view_menu.addAction(display_slider_toolbar_action) def set_video_menu(self): self.previous_action = self.add_menu_action( menu=self.video_menu, name='Previous Frame', connection=self.video_player.previous, status_tip='Go to previous frame.', icon=QIcon(os.path.join(DIR, 'icons', 'prev_icon.png')), tool_bar=self.video_toolbar, return_action=True) self.previous_action.setEnabled(False) self.previous_action.setShortcut(QKeySequence(',')) self.play_action = self.add_menu_action( menu=self.video_menu, name='Play', connection=self.video_player.on, status_tip='Play Video.', icon=QIcon(os.path.join(DIR, 'icons', 'play_icon.png')), tool_bar=self.video_toolbar, return_action=True) self.play_action.setEnabled(False) self.play_action.setShortcut(QKeySequence(']')) self.stop_action = self.add_menu_action( menu=self.video_menu, name='Stop', connection=self.video_player.off, status_tip='Stop Video.', icon=QIcon(os.path.join(DIR, 'icons', 'stop_icon.png')), tool_bar=self.video_toolbar, return_action=True) self.stop_action.setEnabled(False) self.stop_action.setShortcut(QKeySequence('[')) self.next_action = self.add_menu_action( menu=self.video_menu, name='Next Frame', connection=self.video_player.next, status_tip='Go to next frame.', icon=QIcon(os.path.join(DIR, 'icons', 'next_icon.png')), tool_bar=self.video_toolbar, return_action=True) self.next_action.setEnabled(False) self.next_action.setShortcut(QKeySequence('.')) self.stop_start_action = self.add_menu_action( menu=self.video_menu, name='Pause/Play', connection=self.stop_start, status_tip='Start playing, pause, or resume playing video.', return_action=True) self.stop_start_action.setEnabled(False) self.stop_start_action.setShortcut(QKeySequence(Qt.Key_Space)) self.video_zoom_action = self.add_menu_action( menu=self.video_menu, name='Zoom', connection=self.zoom, status_tip='Zoom in on a segment of video.', return_action=True) self.video_zoom_enabled = False self.video_zoom_action.setEnabled(False) self.video_zoom_action.setShortcut(QKeySequence('Z')) self.video_menu.addSeparator() # Actions to control the speed of the video. self.videoMenuSpeedMenu = self.video_menu.addMenu('Playback Speed') speedFunctions = [ self.adjustSpeed1x, self.adjustSpeed1p5x, self.adjustSpeed2x, self.adjustSpeed3x, self.adjustSpeed5x, self.adjustSpeed10x ] speedFunctionNames = ['1x', '1.5x', '2x', '3x', '5x', '10x'] speedActionGroup = QActionGroup(self) for i in xrange(len(speedFunctionNames)): action = self.add_menu_action( menu=self.videoMenuSpeedMenu, name=speedFunctionNames[i], connection=speedFunctions[i], status_tip='Adjust the playback speed of the current video.', return_action=True) action.setCheckable(True) speedActionGroup.addAction(action) if i == 0: action.setChecked(True) def set_tracking_menu(self): self.add_menu_action(menu=self.tracking_menu, name='Batch Processing', connection=self.track_batch, status_tip='Open Batch Tracking Wizard.') def set_analysis_menu(self): self.add_menu_action(menu=self.analysis_menu, name='Signal Processing', connection=self.signal_processing, status_tip='Open Signal Processing Dialog.') def open_file_directory(self): file_dialog = QFileDialog() directory_name = str( file_dialog.getExistingDirectory(caption='Open Folder', options=QFileDialog.ShowDirsOnly)) if not os.path.isdir(directory_name): self.logger.warning( 'Passed directory was not valid (in ' + 'MainWindow.open_file_directory(), line ~282 of entry.py).') return self.file_explorer.set_path(directory_name) self.root_folder = directory_name def open_video(self, video_fname=None): """Opens an individual video for display in the central widget.""" if not isinstance(video_fname, str): file_dialog = QFileDialog(self) video_fname = str( file_dialog.getOpenFileName(caption='Open Video File', filter='Video Files (*.fmf)', directory=self.root_folder)[0]) if not os.path.isfile(video_fname): self.logger.warning( 'Passed `video_fname` was not valid (in ' + 'MainWindow.open_video(), line 290 of entry.py).') return self.video_player.set_video(video_fname) self.video_player.image_annotation = False self.video_player.tracking_summary = None self.enable_video_controls() def enable_video_controls(self): """Enables all video controls and connects signals/slots if necessary.""" #connect video_player signals self.video_player.frame_changed.connect(self.update_frame_label) #enable video controls self.previous_action.setEnabled(True) self.next_action.setEnabled(True) self.play_action.setEnabled(True) self.stop_action.setEnabled(True) self.stop_start_action.setEnabled(True) self.video_zoom_action.setEnabled(True) #enable slider self.slider.setMaximum(self.video_player.video.get_n_frames() - 1) self.slider.setValue(0) self.slider.setEnabled(True) self.frame_label.setText('Frame: 0') self.video_label.setText('Current Video: {}'.format( self.video_player.video_file_name)) def open_tracking_summary(self, fcts_fname=None, video_fname=None): """Opens a tracking summary file (.fcts, .xlsx, etc) for display.""" if not isinstance(fcts_fname, str): file_dialog = QFileDialog(self) fcts_fname = str( file_dialog.getOpenFileName( caption='Open Tracking Summary File', filter='Tracking Summary File (*.fcts *.xlsx)', directory=self.root_folder)[0]) if not os.path.isfile(fcts_fname): self.logger.warning( 'Passed `fcts_fname` was not valid (in ' + 'MainWindow.open_tracking_summary(), line 332 of entry.py).') return file_type = fcts_fname.split('.')[-1] if file_type == 'fcts': with open(fcts_fname, 'rb') as f: tracking_summary = pickle.load(f) elif file_type == 'xlsx': tracking_summary = FCTS().from_xlsx( fcts_fname) # TODO: Add from_xlsx() function else: return if os.path.exists(tracking_summary.video.filename): self.video_player.set_video(tracking_summary.video.filename) else: if not isinstance(video_fname, str): file_dialog = QFileDialog(self) video_fname = str( file_dialog.getOpenFileName( caption='Select Associated Video File', filter='Video File (*.fmf)', directory=self.root_folder)[0]) self.video_player.set_video(video_fname) self.video_player.tracking_summary = tracking_summary self.video_player.image_annotation = True self.video_player.update_label() self.enable_video_controls() # setup statistic toolbar self.statistic_toolbar.setEnabled(True) # calculate statistics about fly held in current experiment. lwa, rwa = wing_stats.individual_wing_angles(tracking_summary.male) fwa = wing_stats.full_wing_angle(tracking_summary.male) wd = wing_stats.wing_distances(tracking_summary.male) nn = spatial_stats.nearest_neighbor_centroid(tracking_summary.male, tracking_summary.female) n2e, t2e = spatial_stats.nose_and_tail_to_ellipse( tracking_summary.male, tracking_summary.female) vel = centroid_stats.centroid_velocity(tracking_summary.male) self.statistics_widget.statistics = { 'LeftWingAngle': lwa, 'RightWingAngle': rwa, 'FullWingAngle': fwa, 'WingDistance': wd, 'Centroid-to-Centroid': nn, 'Nose-to-Ellipse': n2e, 'Rear-to-Ellipse': t2e, 'CentroidVelocity': vel } self.statistics_widget.update_combobox() self.statistics_widget.update_stat_label(0) self.statistic_toolbar.show() self.classification_toolbar.setEnabled(True) self.classification_widget.set_tracking_summary(tracking_summary) self.classification_widget.statistics = \ tracking_summary.male.get_all_behaviors_as_dict() self.classification_widget.update_combobox() self.classification_widget.update_stat_label(0) self.classification_toolbar.show() def set_slider(self): """Places slider widget in video track bar menu.""" self.slider = QSlider(Qt.Horizontal) self.slider.setMinimum(0) self.video_trackbar.addWidget(self.slider) self.slider.valueChanged[int].connect( self.video_player.slider_update_label) self.video_player.frame_changed.connect(self.update_slider) self.slider.setEnabled(False) def set_status(self): """Annotates video statistics at bottom of main window.""" status = self.statusBar() status.setSizeGripEnabled(True) self.frame_label = QLabel() self.frame_label.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) self.frame_label.setText('Frame: NA (00:00:00)') self.video_label = QLabel() self.video_label.setText('Current Video: NA') status.addPermanentWidget(self.frame_label) status.addWidget(self.video_label) def set_file_explorer(self): """Initializes the file explorer as a DockWidget.""" self.file_explorer = FileExplorer() self.file_dock_widget = QDockWidget('File Explorer', self) self.file_dock_widget.setWidget(self.file_explorer) self.addDockWidget(Qt.RightDockWidgetArea, self.file_dock_widget) self.file_explorer.open_video.connect(self.load_video_from_file_exp) def set_statistic_toolbar(self): self.statistic_toolbar = QDockWidget('Tracking Statistics') self.statistics_widget = StatisticWindowWidget() self.statistic_toolbar.setWidget(self.statistics_widget) self.statistic_toolbar.setEnabled(False) self.statistic_toolbar.hide() self.video_player.frame_changed.connect( self.statistics_widget.update_stat_label) self.addDockWidget(Qt.TopDockWidgetArea, self.statistic_toolbar) def set_classification_toolbar(self): self.classification_toolbar = QDockWidget('Behavioral Classifications') self.classification_widget = ClassificationWindowWidget() self.classification_toolbar.setWidget(self.classification_widget) self.classification_toolbar.setEnabled(False) self.classification_toolbar.hide() self.video_player.frame_changed.connect( self.classification_widget.update_stat_label) self.addDockWidget(Qt.TopDockWidgetArea, self.classification_toolbar) self.tabifyDockWidget(self.statistic_toolbar, self.classification_toolbar) def track_batch(self): dialog = BatchTrackingDialog(self.root_folder) if dialog.exec_(): return def signal_processing(self): dialog = StatProcessing(root_folder=self.root_folder, parent=self) dialog.show() @pyqtSlot(int, str, int) def update_frame_label(self, ix, hms, frame_rate): self.frame_label.setText( 'Frame: {} ({}) | FPS: {} | Playback Speed: {}x'.format( ix, hms, frame_rate, self.video_player.playback_speed)) @pyqtSlot(str) def load_video_from_file_exp(self, fname): self.open_video(str(fname)) @pyqtSlot(int) def update_slider(self, ix): self.slider.setValue(ix) @pyqtSlot() def stop_start(self): if self.video_player.is_playing: self.video_player.off() else: self.video_player.on() @pyqtSlot() def zoom(self): """Allows user to select a region of the video to zoom in on.""" if self.video_zoom_enabled: self.video_zoom_enabled = False self.video_player.zoom_enabled = False non_zooming_cursor = QCursor(Qt.ArrowCursor) self.video_player.setCursor(non_zooming_cursor) self.video_player.close_zoom_window() return self.video_zoom_enabled = True zooming_cursor = QCursor(Qt.CrossCursor) self.video_player.setCursor(zooming_cursor) self.video_player.zoom_enabled = True # Playback speed adjustments @pyqtSlot() def adjustSpeed1x(self): self.video_player.playback_speed = 1 @pyqtSlot() def adjustSpeed1p5x(self): self.video_player.playback_speed = 1.5 @pyqtSlot() def adjustSpeed2x(self): self.video_player.playback_speed = 2 @pyqtSlot() def adjustSpeed3x(self): self.video_player.playback_speed = 3 @pyqtSlot() def adjustSpeed5x(self): self.video_player.playback_speed = 5 @pyqtSlot() def adjustSpeed10x(self): self.video_player.playback_speed = 10
class MainWindow(QMainWindow): dep_file_name_list = [ 'analytics', 'bookkeeping', 'development', 'finances', 'hr', 'marketing', 'purchasing', 'sales', 'testing' ] dep_name_list = [ 'Аналитический отдел', 'Бухгалтерия', 'Отдел закупок', 'Отдел кадров', 'Отдел маркетинга', 'Отдел разработки', 'Отдел продаж', 'Отдел тестирования', 'Финансовый отдел' ] def __init__(self): QMainWindow.__init__(self) MainWindow.departments_committed = pyqtSignal(list) data = self.__readDepartmentsData() self.firm = Firm(Human('Иван', 'Попов'), data) self.setWindowTitle('Симулятор офисного расписания') # parameters self.params_dock = QDockWidget() self.params_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.params_widget = ParametersWidget(data) self.params_dock.setWidget(self.params_widget) self.addDockWidget(Qt.LeftDockWidgetArea, self.params_dock) # filter self.filter_dock = QDockWidget() self.filter_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) # console console = QDockWidget() console.setAllowedAreas(Qt.BottomDockWidgetArea) # tabs tabs = QTabWidget() confWidget = QListWidget() confWidget.model().rowsInserted.connect(confWidget.scrollToBottom) tabs.addTab(confWidget, "История") console.setWidget(tabs) self.addDockWidget(Qt.BottomDockWidgetArea, console) # Calendar init_matrix = [[[] for i in range(0, 7)] for j in range(0, 9)] self.calendar_widget = CalendarWidget(Calendar(init_matrix), self) self.setCentralWidget(self.calendar_widget) self.tabs = tabs self.__createActions() self.__onCancelAction() self.__createMenus() self.__createToolBars() def __setDefaultState(self): self.params_dock.widget().getModel().uncheckAll() self.params_dock.show() self.startAction.setEnabled(True) self.newAction.setEnabled(False) self.pauseAction.setEnabled(False) self.cancelAction.setEnabled(False) self.nextAction.setEnabled(False) self.finishAction.setEnabled(False) self.centralWidget().setEnabled(False) self.filter_dock.hide() def __onCancelAction(self): self.tabs.widget(0).addItem('Сбросить параметры моделирования') self.__onResetAction() self.__setDefaultState() def __onResetAction(self): self.tabs.widget(0).addItem('Очистить календарь') self.calendar_widget.clear_widget() self.current_cell = {'row': 0, 'col': 0} self.repaint() def __onPauseAction(self): self.tabs.widget(0).addItem('Пауза моделирования') def __onStartAction(self): checked_departments = self.params_widget.getModel( ).getCheckedDepartmentList() self.checked_departments = checked_departments if len(checked_departments) == 0: self.tabs.widget(0).addItem( 'Ошибка [параметры]: выберите хотя бы один отдел') return num_of_days = self.params_widget.sb_period.value() self.Matrix = [[[] for i in range(0, num_of_days)] for j in range(0, 9)] if self.params_widget.chb_defaultSchedule.isChecked(): self.__readDefaultSchedule(num_of_days) self.filter_dock.setWidget(FilterWidget(checked_departments)) self.calendar_widget = CalendarWidget(Calendar(self.Matrix), self) self.calendar_widget.setFormData(checked_departments) self.setCentralWidget(self.calendar_widget) self.addDockWidget(Qt.RightDockWidgetArea, self.filter_dock) self.params_dock.hide() self.newAction.setEnabled(True) self.cancelAction.setEnabled(True) self.nextAction.setEnabled(True) self.finishAction.setEnabled(True) self.tabs.widget(0).addItem('Начало моделирования') self.startAction.setEnabled(False) self.pauseAction.setEnabled(False) self.filter_dock.show() from lib.logic_manager import LogicManager def __onNextAction(self): step = int(self.params_widget.cb_step.currentText().split()[0]) calendar = self.calendar_widget.getCalendar() (rest_events, next_cell) = LogicManager.simulate_next_step(calendar, step, self.current_cell) if next_cell is None: self.tabs.widget(0).addItem('Моделирование завершено') else: self.calendar_widget.highlightCell(self.current_cell) self.current_cell = next_cell self.tabs.widget(0).addItem('Следующий шаг: ' + str(rest_events) + ' осталось событий') def __onFinishAction(self): self.tabs.widget(0).addItem('Завершить моделирование...') width = len(self.calendar_widget.getCalendar().matrix[0]) height = len(self.calendar_widget.getCalendar().matrix) # sleeper = Sleeper(self.__onNextAction) for col_num in range(0, width, 1): for row_num in range(0, height, 1): self.__onNextAction() # sleeper.start() # sleeper.wait(1000) def __createActions(self): newAction = QAction('&Очистить календарь', self) newAction.setIcon(self.style().standardIcon(QStyle.SP_BrowserReload)) newAction.setShortcut(QKeySequence.Forward) newAction.setStatusTip('Очистить календарь') newAction.triggered.connect(self.__onResetAction) self.newAction = newAction cancelAction = QAction('&Сбросить параметры моделирования', self) cancelAction.setIcon(self.style().standardIcon(QStyle.SP_BrowserStop)) cancelAction.setShortcut(Qt.Key_Stop) cancelAction.setStatusTip('Сбросить параметры моделирования') self.cancelAction = cancelAction self.cancelAction.triggered.connect(self.__onCancelAction) startAction = QAction('&Начать', self) startAction.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) startAction.setShortcut(Qt.Key_Stop) startAction.setStatusTip('Начало моделирования') startAction.triggered.connect(self.__onStartAction) self.startAction = startAction nextAction = QAction('&Следующий шаг', self) nextAction.setIcon(self.style().standardIcon( QStyle.SP_MediaSeekForward)) nextAction.setShortcut(Qt.Key_Space) nextAction.setStatusTip('Следующий шаг') nextAction.triggered.connect(self.__onNextAction) self.nextAction = nextAction finishAction = QAction('&Завершить моделирование', self) finishAction.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipForward)) finishAction.setShortcut(QKeySequence.Forward) finishAction.setStatusTip('Завершить моделирование') finishAction.triggered.connect(self.__onFinishAction) self.finishAction = finishAction pauseAction = QAction('&Пауза', self) pauseAction.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) pauseAction.setShortcut(Qt.Key_Pause) pauseAction.setStatusTip('Пауза моделирования') pauseAction.triggered.connect(self.__onPauseAction) self.pauseAction = pauseAction exitAction = QAction('&Выход', self) exitAction.setShortcut(Qt.Key_Exit) exitAction.setStatusTip('Выход') exitAction.triggered.connect(self.close) self.exitAction = exitAction def __createMenus(self): sessionMenu = self.menuBar().addMenu('Сессия') sessionMenu.addAction(self.newAction) sessionMenu.addAction(self.cancelAction) sessionMenu.addSeparator() sessionMenu.addAction(self.exitAction) controlMenu = self.menuBar().addMenu('Управление') controlMenu.addAction(self.startAction) controlMenu.addAction(self.pauseAction) controlMenu.addAction(self.nextAction) controlMenu.addAction(self.finishAction) def __createToolBars(self): sessioToolBar = self.addToolBar('Сессия') sessioToolBar.addAction(self.newAction) sessioToolBar.addAction(self.cancelAction) controlToolBar = self.addToolBar('Управление') controlToolBar.addAction(self.startAction) controlToolBar.addAction(self.nextAction) controlToolBar.addAction(self.finishAction) controlToolBar.addAction(self.pauseAction) def __readDefaultSchedule(self, num_of_days): file_name = 'default' file = QFile(':/schedule/' + file_name + '.txt') if not file.open(QIODevice.ReadOnly | QIODevice.Text): raise FileNotFoundError(file_name) stream = QTextStream(file) stream.setCodec('UTF-8') Matrix = [[[] for i in range(0, num_of_days)] for j in range(0, 9)] days_of_week = [ '', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье' ] while not stream.atEnd(): week_day = stream.readLine()[:-1] line = stream.readLine() while line: params_of_event = line.split(',') time = int(params_of_event[0].replace(':', '')) duration = int(params_of_event[1]) title = params_of_event[2] location = params_of_event[3] department = params_of_event[4] start_day_number = days_of_week.index(week_day) days_list = [ k for k in range(start_day_number, num_of_days, 7) ] type = ScheduleEvent.Type.HEAD if department == 'Руководство' else ScheduleEvent.Type.DEP participants_list = [] if type == ScheduleEvent.Type.HEAD: participants_list.append(self.firm.getBoss()) for dep in self.checked_departments: participants_list.append(dep.getBoss()) elif type == ScheduleEvent.Type.DEP: for dep in self.checked_departments: if dep.getName() == department: participants_list.extend(dep.getEmployeeList()) else: raise Exception( 'Error while processing default schedule data: TYPE') for day in days_list: if len(participants_list) != 0: Matrix[int(time / 100) - 10][day - 1].append( ScheduleEvent(time=time, duration=duration, title=title, location=location, type=type, part_list=participants_list, day=day)) line = stream.readLine() self.Matrix = Matrix def __readDepartmentsData(self): department_list = [] # of Department for file_name in MainWindow.dep_file_name_list: count = 0 file = QFile(':/stuff/' + file_name + '.txt') if not file.open(QIODevice.ReadOnly | QIODevice.Text): raise FileNotFoundError(file_name) stream = QTextStream(file) stream.setCodec('UTF-8') dep_name = stream.readLine() if dep_name[-1] != ':': raise Exception('resource ' + file_name + ' with no department mark') dep_name = dep_name[:-1] new_dep_obj = Department(dep_name) while not stream.atEnd(): count += 1 (n, s) = stream.readLine().split() if count == 1: new_dep_obj.setBoss(Employee(n, s)) else: new_dep_obj.addEmployee(Employee(n, s)) if count == 0: raise Exception('resource ' + file_name + ' has no items') department_list.append(new_dep_obj) return department_list
class SimulatorWindow(QMainWindow): def __init__(self, parent=None): super(SimulatorWindow, self).__init__(parent) self.initWindow() def initWindow(self): self.setupToolBar() self.setupDockable() self.setupTerminal() self.setWindowTitle('模拟') def setupToolBar(self): self.toolBar = self.addToolBar('Control') self.toolBar.setIconSize(QSize(48, 48)) self.resetAction = QAction(QIcon('icons/reset.png'), '初始化(F9)', self, shortcut=QKeySequence('F9'), statusTip='初始化(F9)', triggered=self.resetSimulator) self.toolBar.addAction(self.resetAction) self.stepAction = QAction(QIcon('icons/step.png'), '单步(F10)', self, shortcut=QKeySequence('F10'), statusTip='单步(F10)', triggered=self.stepSimulator) self.toolBar.addAction(self.stepAction) self.runAction = QAction(QIcon('icons/run.png'), '运行(F11)', self, shortcut=QKeySequence('F11'), statusTip='运行(F11)', triggered=self.runSimulator) self.toolBar.addAction(self.runAction) def setupDockable(self): self.msgBrowser = MessageBrowser() self.bottomDock = QDockWidget('信息', self) self.bottomDock.setFeatures(QDockWidget.DockWidgetClosable) self.bottomDock.setWidget(self.msgBrowser) self.addDockWidget(Qt.BottomDockWidgetArea, self.bottomDock) self.bottomDock.hide() self.regBrowser = RegBrowser() self.leftDock = QDockWidget('寄存器', self) self.leftDock.setFeatures(QDockWidget.DockWidgetClosable) self.leftDock.setWidget(self.regBrowser) self.addDockWidget(Qt.LeftDockWidgetArea, self.leftDock) self.binBrowser = BinBrowser() self.rightDock = QDockWidget('内存', self) self.rightDock.setFeatures(QDockWidget.DockWidgetClosable) self.rightDock.setWidget(self.binBrowser) self.addDockWidget(Qt.RightDockWidgetArea, self.rightDock) def setupTerminal(self): self.terminal = TerminalBrowser() self.lineInput = TerminalInput() self.lineInput.returnPressed.connect(self.updateInput) layout = QVBoxLayout() layout.addWidget(self.terminal) layout.addWidget(self.lineInput) central = QWidget() central.setLayout(layout) self.setCentralWidget(central) def updateBrowser(self): self.regBrowser.showReg(simulator.reg + [simulator.pc, simulator.hi, simulator.lo]) self.binBrowser.showBin(simulator.mem, simulator.pc) self.terminal.insertHtml(parseHtml(simulator.get_output())) self.terminal.moveCursor(QTextCursor.End) def updateInput(self): simulator.input_data.extend(self.lineInput.text().split()) self.terminal.insertHtml('<font color="#93C763">' + parseHtml(self.lineInput.text()) + '</font>') self.terminal.moveCursor(QTextCursor.End) self.lineInput.clear() if self.state == 'STEP': self.stepSimulator() elif self.state == 'RUN': self.runSimulator() def setWidgetEnabled(self): self.stepAction.setEnabled(not simulator.program_end and self.state == 'IDLE') self.runAction.setEnabled(not simulator.program_end and self.state == 'IDLE') if self.state != 'IDLE': self.lineInput.setEnabled(True) self.lineInput.setFocus() else: self.lineInput.setEnabled(False) def loadSimulator(self, mem, init_pc): if init_pc < 0: simulator.load(mem, config.TEXT_ADDR_LOWER) self.resetSimulator() self.bottomDock.show() self.msgBrowser.append( '<font color="#FFCD22">[WARNING] Can not find "main" label. Program counter will be set to the lower bound of text segment instead.</font>' ) else: simulator.load(mem, init_pc) self.resetSimulator() def resetSimulator(self): simulator.reset() self.state = 'IDLE' self.bottomDock.hide() self.terminal.clear() self.lineInput.clear() self.msgBrowser.clear() self.updateBrowser() self.setWidgetEnabled() def stepSimulator(self): self.state = 'STEP' self.msgBrowser.clear() self.bottomDock.show() self.msgBrowser.append('Simulating...') try: simulator.step() except SimulationInfoException as e: self.msgBrowser.append('[INFO] %s' % (str(e))) except Exception as e: self.msgBrowser.append('<font color="red">[EXCEPTION] %s</font>' % (str(e))) self.msgBrowser.append('Simulation terminated.') self.state = 'IDLE' else: self.msgBrowser.append('Simulation terminated.') self.state = 'IDLE' self.updateBrowser() self.setWidgetEnabled() def runSimulator(self): self.state = 'RUN' self.msgBrowser.clear() self.bottomDock.show() self.msgBrowser.append('Simulating...') try: simulator.run() except SimulationInfoException as e: self.msgBrowser.append('[INFO] %s' % (str(e))) except Exception as e: self.msgBrowser.append('<font color="red">[EXCEPTION] %s</font>' % (str(e))) self.msgBrowser.append('Simulation terminated.') self.state = 'IDLE' else: self.msgBrowser.append('Simulation terminated.') self.state = 'IDLE' self.updateBrowser() self.setWidgetEnabled()
class InvoiceX(QMainWindow): def __init__(self): super().__init__() self.mainWindowLeft = 300 self.mainWindowTop = 300 self.mainWindowWidth = 680 self.mainWindowHeight = 480 self.fileLoaded = False self.dialog = None self.initUI() def initUI(self): # StatusBar self.statusBar() self.setStatusTip('Select a PDF to get started') self.set_menu_bar() self.set_dockview_fields() self.set_center_widget() self.set_toolbar() self.setGeometry(self.mainWindowLeft, self.mainWindowTop, self.mainWindowWidth, self.mainWindowHeight) self.setWindowTitle('Invoice-X') self.setWindowIcon( QIcon(os.path.join(os.path.dirname(__file__), 'icons/logo.ico'))) self.show() if not spawn.find_executable('convert'): QMessageBox.critical(self, 'Import Error', "Imagemagick is not installed", QMessageBox.Ok) self.close() if sys.platform[:3] == 'win': if not spawn.find_executable('magick'): QMessageBox.critical( self, 'Import Error', "Imagemagick and GhostScript are not installed", QMessageBox.Ok) self.close() def set_toolbar(self): toolbar = self.addToolBar('File') toolbar.addAction(self.openFile) toolbar.addAction(self.saveFile) toolbar.addAction(self.validateMetadata) toolbar.addAction(self.editFields) def set_center_widget(self): self.square = QLabel(self) self.square.setAlignment(Qt.AlignCenter) self.setCentralWidget(self.square) def set_dockview_fields(self): self.fields = QDockWidget("Fields", self) self.fields.installEventFilter(self) self.fieldsQWidget = QWidget() self.fieldsScrollArea = QScrollArea() self.fieldsScrollArea.setWidgetResizable(True) self.fieldsScrollArea.setWidget(self.fieldsQWidget) self.layout = QGridLayout() self.fieldsQWidget.setLayout(self.layout) self.fields.setWidget(self.fieldsScrollArea) self.fields.setFloating(False) self.fields.setMinimumWidth(360) self.fields.setStyleSheet("QWidget { background-color: #AAB2BD}") self.addDockWidget(Qt.RightDockWidgetArea, self.fields) def set_menu_bar(self): self.exitAct = QAction( QIcon(os.path.join(os.path.dirname(__file__), 'icons/exit.png')), 'Exit', self) self.exitAct.setShortcut('Ctrl+Q') self.exitAct.setStatusTip('Exit application') self.exitAct.triggered.connect(self.close) self.openFile = QAction( QIcon(os.path.join(os.path.dirname(__file__), 'icons/pdf.png')), 'Open', self) self.openFile.setShortcut('Ctrl+O') self.openFile.setStatusTip('Open new File') self.openFile.triggered.connect(self.show_file_dialog) self.saveFile = QAction( QIcon(os.path.join(os.path.dirname(__file__), 'icons/save.png')), 'Save', self) self.saveFile.setShortcut('Ctrl+S') self.saveFile.setStatusTip('Save File') self.saveFile.triggered.connect(self.save_file_dialog) self.saveAsFile = QAction('Save As', self) self.saveAsFile.setStatusTip('Save File as a new File') self.saveAsFile.triggered.connect(self.show_save_as_dialog) self.viewDock = QAction('View Fields', self, checkable=True) self.viewDock.setStatusTip('View Fields') self.viewDock.setChecked(True) self.viewDock.triggered.connect(self.view_dock_field_toggle) extractFields = QAction('Extract Fields', self) extractFields.setStatusTip('Extract Fields from PDF and add to XML') extractFields.triggered.connect(self.extract_fields_from_pdf) jsonFormat = QAction('JSON', self) jsonFormat.setStatusTip('Export file to JSON') jsonFormat.triggered.connect(lambda: self.export_fields('json')) xmlFormat = QAction('XML', self) xmlFormat.setStatusTip('Export file to XML') xmlFormat.triggered.connect(lambda: self.export_fields('xml')) ymlFormat = QAction('YML', self) ymlFormat.setStatusTip('Export file to YML') ymlFormat.triggered.connect(lambda: self.export_fields('yml')) self.validateMetadata = QAction( QIcon(os.path.join(os.path.dirname(__file__), 'icons/validate.png')), 'Validate', self) self.validateMetadata.setStatusTip('Validate XML') self.validateMetadata.triggered.connect(self.validate_xml) addMetadata = QAction('Add Metadata', self) addMetadata.setStatusTip('Add metadata to PDF') self.editFields = QAction( QIcon(os.path.join(os.path.dirname(__file__), 'icons/edit.png')), 'Edit Metadata', self) self.editFields.setStatusTip('Edit Metadata in XML') self.editFields.triggered.connect(self.edit_fields_dialog) documentation = QAction('Documentation', self) documentation.setStatusTip('Open Documentation for Invoice-X') documentation.triggered.connect(self.documentation_menubar) aboutApp = QAction('About', self) aboutApp.setStatusTip('Know about Invoice-X') aboutApp.triggered.connect(self.about_app_menubar) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(self.openFile) fileMenu.addAction(self.saveFile) fileMenu.addAction(self.saveAsFile) fileMenu.addAction(self.viewDock) fileMenu.addAction(self.exitAct) commandMenu = menubar.addMenu('&Command') exportMetadata = commandMenu.addMenu('&Export Metadata') exportMetadata.addAction(jsonFormat) exportMetadata.addAction(xmlFormat) exportMetadata.addAction(ymlFormat) commandMenu.addAction(self.validateMetadata) commandMenu.addAction(self.editFields) commandMenu.addAction(addMetadata) commandMenu.addAction(extractFields) helpMenu = menubar.addMenu('&Help') helpMenu.addAction(documentation) helpMenu.addAction(aboutApp) def view_dock_field_toggle(self, state): if state: self.fields.show() else: self.fields.hide() def validate_xml(self): try: if self.factx.is_valid(): QMessageBox.information(self, 'Valid XML', "The XML is Valid", QMessageBox.Ok) else: QMessageBox.critical(self, 'Invalid XML', "The XML is invalid", QMessageBox.Ok) except AttributeError: QMessageBox.critical(self, 'File Not Found', "Load a PDF first", QMessageBox.Ok) def set_pdf_preview(self): # print(str(fileName[0])) if not os.path.exists('.load'): os.mkdir('.load') if sys.platform[:3] == 'win': convert = [ 'magick', self.fileName[0], '-flatten', '.load/preview.jpg' ] else: convert = [ 'convert', '-verbose', '-density', '150', '-trim', self.fileName[0], '-quality', '100', '-flatten', '-sharpen', '0x1.0', '.load/preview.jpg' ] subprocess.call(convert) self.pdfPreviewImage = '.load/preview.jpg' self.fileLoaded = True self.square.setPixmap( QPixmap(self.pdfPreviewImage).scaled(self.square.size().width(), self.square.size().height(), Qt.KeepAspectRatio, Qt.SmoothTransformation)) def edit_fields_dialog(self): try: self.dialog = EditFieldsClass(self, self.factx, self.fieldsDict, self.metadata_field) self.dialog.installEventFilter(self) # self.dialog.show() except AttributeError: QMessageBox.critical(self, 'File Not Found', "Load a PDF first", QMessageBox.Ok) def update_dock_fields(self): self.factx.write_json('.load/output.json') with open('.load/output.json') as jsonFile: self.fieldsDict = json.load(jsonFile) os.remove('.load/output.json') # print(self.fieldsDict) i = 0 self.metadata_field = { 'amount_tax': 'Amount Tax', 'amount_total': 'Amount Total', 'amount_untaxed': 'Amount Untaxed', 'buyer': 'Buyer', 'currency': 'Currency', 'date': 'Date', 'date_due': 'Date Due', 'invoice_number': 'Invoice Number', 'name': 'Name', 'notes': 'Notes', 'seller': 'Seller', 'type': 'Type', 'version': 'Version' } for key in sorted(self.fieldsDict): i += 1 try: self.factx[key] except IndexError: self.fieldsDict[key] = "Field Not Specified" except TypeError: pass fieldKey = QLabel(self.metadata_field[key] + ": ") if self.fieldsDict[key] is None: fieldValue = QLabel("NA") else: if key[:4] == "date" and \ self.fieldsDict[key] != "Field Not Specified": self.fieldsDict[key] = self.fieldsDict[key][:4] \ + "/" + self.fieldsDict[key][4:6] \ + "/" + self.fieldsDict[key][6:8] if self.fieldsDict[key] == "Field Not Specified": fieldValue = QLabel(self.fieldsDict[key]) fieldValue.setStyleSheet("QLabel { color: #666666}") else: fieldValue = QLabel(self.fieldsDict[key]) # fieldValue.setFrameShape(QFrame.Panel) # fieldValue.setFrameShadow(QFrame.Plain) # fieldValue.setLineWidth(3) self.layout.addWidget(fieldKey, i, 0) self.layout.addWidget(fieldValue, i, 1) def show_file_dialog(self): self.fileName = QFileDialog.getOpenFileName(self, 'Open file', os.path.expanduser("~"), "pdf (*.pdf)") self.load_pdf_file() def load_pdf_file(self): if self.fileName[0]: if self.check_xml_for_pdf() is None: self.standard = None self.level = None self.choose_standard_level() if self.standard is not None: self.factx = FacturX(self.fileName[0], self.standard, self.level) else: self.factx = FacturX(self.fileName[0]) if hasattr(self, 'factx'): self.set_pdf_preview() self.update_dock_fields() self.setStatusTip("PDF is Ready") def choose_standard_level(self): self.chooseStandardDialog = QDialog() layout = QGridLayout() noXMLLabel = QLabel("No XML found", self) layout.addWidget(noXMLLabel, 0, 0) chooseStandardLabel = QLabel("Standard", self) chooseStandardCombo = QComboBox(self) chooseStandardCombo.addItem("Factur-X") chooseStandardCombo.addItem("Zugferd") chooseStandardCombo.addItem("UBL") chooseStandardCombo.model().item(2).setEnabled(False) chooseStandardCombo.activated[str].connect(self.on_select_level) chooseLevelLabel = QLabel("Level", self) self.chooseLevelCombo = QComboBox(self) self.chooseLevelCombo.addItem("Minimum") self.chooseLevelCombo.addItem("Basic WL") self.chooseLevelCombo.addItem("Basic") self.chooseLevelCombo.addItem("EN16931") self.chooseLevelCombo.activated[str].connect(self.set_level) applyStandard = QPushButton("Apply") applyStandard.clicked.connect(self.set_standard_level) discardStandard = QPushButton("Cancel") discardStandard.clicked.connect(self.discard_standard_level) layout.addWidget(chooseStandardLabel, 1, 0) layout.addWidget(chooseStandardCombo, 1, 1) layout.addWidget(chooseLevelLabel, 2, 0) layout.addWidget(self.chooseLevelCombo, 2, 1) layout.addWidget(discardStandard, 3, 0) layout.addWidget(applyStandard, 3, 1) self.chooseStandardDialog.setLayout(layout) self.chooseStandardDialog.setWindowTitle("Choose Standard") self.chooseStandardDialog.setWindowModality(Qt.ApplicationModal) self.chooseStandardDialog.exec_() def set_standard_level(self): try: self.standard = self.standard_temp self.level = self.level_temp except AttributeError: self.standard = 'factur-x' self.level = 'minimum' self.chooseStandardDialog.close() def discard_standard_level(self): self.chooseStandardDialog.close() def on_select_level(self, text): if text == "Factur-X": self.chooseLevelCombo.clear() self.chooseLevelCombo.addItem("Minimum") self.chooseLevelCombo.addItem("Basic WL") self.chooseLevelCombo.addItem("Basic") self.chooseLevelCombo.addItem("EN16931") elif text == "Zugferd": self.chooseLevelCombo.clear() self.chooseLevelCombo.addItem("Basic") self.chooseLevelCombo.addItem("Comfort") elif text == "UBL": self.chooseLevelCombo.clear() self.chooseLevelCombo.addItem("UBL 2.0") self.chooseLevelCombo.addItem("UBL 2.1") standard_dict = { 'Factur-X': ['factur-x', 'minimum'], 'Zugferd': ['zugferd', 'basic'], } self.standard_temp = standard_dict[text][0] self.level_temp = standard_dict[text][1] def set_level(self, text): level_dict = { 'Minimum': 'minimum', 'Basic WL': 'basicwl', 'Basic': 'basic', 'EN16931': 'en16931', 'Comfort': 'comfort' } self.level_temp = level_dict[text] def check_xml_for_pdf(self): pdf = PdfFileReader(self.fileName[0]) pdf_root = pdf.trailer['/Root'] if '/Names' not in pdf_root or '/EmbeddedFiles' not in \ pdf_root['/Names']: return None for file in pdf_root['/Names']['/EmbeddedFiles']['/Names']: if isinstance(file, IndirectObject): obj = file.getObject() if obj['/F'] in xml_flavor.valid_xmp_filenames(): xml_root = etree.fromstring(obj['/EF']['/F'].getData()) xml_content = xml_root return xml_content def save_file_dialog(self): if self.fileLoaded: if self.confirm_save_dialog(): try: self.factx.write_pdf(self.fileName[0]) except TypeError: QMessageBox.critical(self, 'Type Error', "Some field value(s) are invalid", QMessageBox.Ok) else: QMessageBox.critical(self, 'File Not Found', "Load a PDF first", QMessageBox.Ok) def confirm_save_dialog(self): reply = QMessageBox.question( self, 'Message', "Do you want to save? This cannot be undone", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: return True else: return False def show_save_as_dialog(self): if self.fileLoaded: try: self.saveFileName = QFileDialog.getSaveFileName( self, 'Save file', os.path.expanduser("~"), "pdf (*.pdf)") if self.saveFileName[0]: if self.saveFileName[0].endswith('.pdf'): fileName = self.saveFileName[0] else: fileName = self.saveFileName[0] + '.pdf' self.factx.write_pdf(fileName) except TypeError: QMessageBox.critical(self, 'Type Error', "Some field value(s) are not valid", QMessageBox.Ok) else: QMessageBox.critical(self, 'File Not Found', "Load a PDF first", QMessageBox.Ok) def extract_fields_from_pdf(self): if self.fileLoaded: self.populate = PopulateFieldClass(self, self.factx, self.fieldsDict, self.metadata_field) else: QMessageBox.critical(self, 'File Not Found', "Load a PDF first", QMessageBox.Ok) def documentation_menubar(self): pass def about_app_menubar(self): pass def export_fields(self, outputformat): if self.fileLoaded: self.exportFileName = QFileDialog.getSaveFileName( self, 'Export file', os.path.expanduser("~") + '/output.%s' % outputformat, "%s (*.%s)" % (outputformat, outputformat)) if self.exportFileName[0]: if outputformat is "json": self.pdf_write_json(self.exportFileName[0]) elif outputformat is "xml": self.pdf_write_xml(self.exportFileName[0]) elif outputformat is "yml": self.pdf_write_yml(self.exportFileName[0]) else: QMessageBox.critical(self, 'File Not Found', "Load a PDF first", QMessageBox.Ok) def pdf_write_json(self, fileName): self.factx.write_json(fileName) def pdf_write_xml(self, fileName): self.factx.write_xml(fileName) def pdf_write_yml(self, fileName): self.factx.write_yml(fileName) def resizeEvent(self, event): if self.fileLoaded: self.square.setPixmap( QPixmap(self.pdfPreviewImage).scaled( self.square.size().width(), self.square.size().height(), Qt.KeepAspectRatio, Qt.SmoothTransformation)) self.square.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Ignored) QMainWindow.resizeEvent(self, event) def eventFilter(self, source, event): if event.type() == QEvent.Close and source is self.fields: self.viewDock.setChecked(False) return QMainWindow.eventFilter(self, source, event) def closeEvent(self, event): if os.path.isdir('.load'): shutil.rmtree('.load/')
class MainWindow(QMainWindow): var1 = "" var2 = "" def __init__(self): super(MainWindow, self).__init__() self.setUpMenus() CSRWidgets.changeCentralWidget(self, CSRWidgets.createDesignButtons(self, 'default')) #Sets central widget on init. self.setWindowTitle("CSR Proving Ground") self.resize(1500, 900) qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def setUpMenus(self): self.createMenus() self.createToolBars() self.createStatusBar() self.createDockWindows() def about(self): QMessageBox.about(self, "C3PO", "His high exaltedness, the Great Jabba the Hutt, has decreed that you are to be terminated immediately.") def createMenus(self): CSRWidgets.createActions(self) self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addSeparator() self.fileMenu.addAction(self.quitAct) self.editMenu = self.menuBar().addMenu("&Edit") self.viewMenu = self.menuBar().addMenu("&View") self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) def createToolBars(self): self.homeToolBar = self.addToolBar("Home") self.homeToolBar.addAction(self.homeAct) self.homeToolBar.addAction(self.quitAct) self.searchToolBar = self.addToolBar("Search") self.searchToolBar.addAction(self.searchAct) self.searchBar = QLineEdit() self.searchBar.setMaximumWidth(150) self.searchBar.returnPressed.connect(self.btnSearch_Click) self.searchToolBar.addWidget(self.searchBar) self.searchToolBar.addSeparator() self.searchToolBar.addAction(self.undoAct) self.searchToolBar.addSeparator() btnNameChange = QPushButton('Change Name', self) btnNameChange.clicked.connect(self.btnNameChange_Click) self.lblVar1 = QLabel() self.lblVar1.setFont(QFont('Veranda', 14, QFont.Bold)) #self.lblVar1.setMargin(10) self.lblVar1.setStyleSheet('padding-left:10px') self.lblTxtVar1 = QLabel() self.lblTxtVar1.setFont(QFont('Veranda', 14, QFont.Bold)) #self.lblTxtVar1.setMargin(0) self.lblTxtVar1.setStyleSheet('padding-left:1px') self.lblVar2 = QLabel() self.lblVar2.setFont(QFont('Veranda', 14, QFont.Bold)) self.lblVar2.setMargin(10) self.lblTxtVar2 = QLabel() self.lblTxtVar2.setFont(QFont('Veranda', 14, QFont.Bold)) self.lblTxtVar2.setMargin(0) self.lblSkuName = QLabel() self.lblSkuName.setFont(QFont('Veranda', 14, QFont.Bold)) self.lblSkuName.setMargin(10) self.searchToolBar.addWidget(btnNameChange) self.searchToolBar.addWidget(self.lblVar1) self.searchToolBar.addWidget(self.lblTxtVar1) self.searchToolBar.addWidget(self.lblVar2) self.searchToolBar.addWidget(self.lblTxtVar2) self.searchToolBar.addWidget(self.lblSkuName) def createStatusBar(self): self.statusBar().showMessage("Ready") def createDockWindows(self): dock = QDockWidget("Available Garments Types", self) #dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.availableItems = QListWidget(dock) self.availableItems.setMinimumWidth(350) self.availableItems.setMaximumWidth(350) #self.availableItems.addItems(("stuff")) self.availableItems.itemClicked.connect(self.itemClicked_Click) dock.setWidget(self.availableItems) self.addDockWidget(Qt.RightDockWidgetArea, dock) self.viewMenu.addAction(dock.toggleViewAction()) dock.hide() self.dock = QDockWidget("Available Garment Sizes", self) self.orderItem = QTreeWidget(dock) #self.orderItem.setMinimumWidth(350) #self.orderItem.setMaximumWidth(350) #self.orderItem.insertText(("more stuff")) self.dock.setWidget(self.orderItem) self.addDockWidget(Qt.RightDockWidgetArea, self.dock) self.viewMenu.addAction(self.dock.toggleViewAction()) self.dock.hide() #Create a tree widget for use when the t-shirt is clicked. self.treeDock = QDockWidget("Order Items", self) self.garmentTree = QTreeWidget(self.treeDock) self.garmentTree.setObjectName('garmentTree') self.garmentTree.itemClicked.connect(CSRWidgets.sumQuantity) self.garmentTree.itemClicked.connect(lambda: CSRWidgets.updateNameDesign(self)) self.garmentTree.setMaximumWidth(480) self.garmentTree.setMinimumWidth(480) self.treeDock.hide() def btnSale_Click(self): btnName = self.sender() sku_code = str(btnName.objectName()) # #print(sku_code) # sv = mysql_db.getSecondVar(self, sku_code) # if self.var1 == "": # CSRWidgets.getCustomerName(self, sku_code) # elif self.var1 != "" and not self.var2: # sv = mysql_db.getSecondVar(self, sku_code) # print(sv) # if sv: # CSRWidgets.getCustomerName(self, sku_code) # else: # self.var2 = None # self.lblVar2.hide() # self.lblTxtVar2.hide() CSRWidgets.loadDesignItem(self, sku_code) def btnNameChange_Click(self): CSRWidgets.changeCustName(self) def btnHome_Click(self): CSRWidgets.changeCentralWidget(self, CSRWidgets.createDesignButtons(self,'default')) self.availableItems.clear() itSku = QTreeWidgetItemIterator(self.garmentTree) ################################################################################# while itSku.value(): if itSku.value().parent() != None: itSku.value().setExpanded(False) itSku += 1 ################################################################################# def btnSearch_Click(self): self.availableItems.clear() #self.orderItem.clear() searchTerm = self.searchBar.text() CSRWidgets.changeCentralWidget(self, CSRWidgets.createDesignButtons(self,searchTerm)) def btnUndo_Click(self): CSRWidgets.undo(self) def itemClicked_Click(self): button = self.sender() txtItem = button.uniqueId CSRWidgets.loadGarmentInfo(self, self.currentInfo[txtItem][2], self.currentInfo[txtItem][1], self.currentInfo[txtItem][0], self.currentInfo[txtItem][6])
class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.initAssembler() self.initWindow() # -------------------------------------------------------------------------- # Initialize assembler # -------------------------------------------------------------------------- def initAssembler(self): # Load config and pseudo instructions pseudo.load_pseudo(config.CONFIG_FILE) config.load_config(config.CONFIG_FILE) # -------------------------------------------------------------------------- # Initialize main window # -------------------------------------------------------------------------- def initWindow(self): self.currentFile = '' self.dirty = False self.setupFileMenu() self.setupSettingMenu() self.setupAssembleMenu() self.setupHelpMenu() self.setupEditor() self.setupDockable() self.setCentralWidget(self.editor) self.setWindowTitle('Untitled - YAME') self.setWindowIcon(QIcon('icons/yame.png')) self.simulatorWindow = SimulatorWindow(self) # -------------------------------------------------------------------------- # Set when text in the editor is modified # -------------------------------------------------------------------------- def setDirty(self): self.dirty = True self.updateStatus() # -------------------------------------------------------------------------- # Clear dirty state # -------------------------------------------------------------------------- def clearDirty(self): self.dirty = False self.updateStatus() # -------------------------------------------------------------------------- # Check if text in the editor is modified # -------------------------------------------------------------------------- def isDirty(self): return self.dirty and (self.currentFile or self.editor.toPlainText()) # -------------------------------------------------------------------------- # YAME's main window # -------------------------------------------------------------------------- def updateStatus(self): title = '* ' if self.isDirty() else '' if self.currentFile: title += self.currentFile else: title += 'Untitled' title += ' - YAME' self.setWindowTitle(title) # -------------------------------------------------------------------------- # Confirm message box # -------------------------------------------------------------------------- def okToContinue(self): if self.isDirty(): reply = QMessageBox.question( self, 'YAME - 尚未保存的修改', '<p align="center" style="font-size: 16px;">存在尚未保存的修改,是否保存?</p>', QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if reply == QMessageBox.Cancel: return False elif reply == QMessageBox.Yes: return self.saveFile() return True # -------------------------------------------------------------------------- # Quit the app # -------------------------------------------------------------------------- def closeEvent(self, event): if self.okToContinue(): # Save config and pseudo instructions pseudo.save_pseudo(config.CONFIG_FILE) config.save_config(config.CONFIG_FILE) event.accept() else: event.ignore() # -------------------------------------------------------------------------- # Assemble text to machine code # -------------------------------------------------------------------------- def assemble(self): self.msgBrowser.clear() self.bottomDock.show() self.msgBrowser.append('Assembling...') try: mem, init_pc = assembler.assemble(self.editor.toPlainText()) except Exception as e: # Move editor to the corresponding line regex_res = re.search('Line ([0-9]+?):', str(e)) if regex_res != None: line_num = int(regex_res.group(1)) self.editor.moveCursor(QTextCursor.End) cursor = QTextCursor( self.editor.document().findBlockByLineNumber(line_num - 1)) self.editor.setTextCursor(cursor) self.msgBrowser.append('<font color="red">[ERROR] %s</font>' % (str(e))) self.msgBrowser.append('Assembling procedure terminated.') return False else: self.msgBrowser.append('Assembling procedure finished.') self.binBrowser.init_pc = init_pc self.binBrowser.showBin(mem) self.rightDock.show() return True # -------------------------------------------------------------------------- # Disassemble machine code to text # -------------------------------------------------------------------------- def disassemble(self): if not self.okToContinue(): return False self.msgBrowser.clear() self.bottomDock.show() self.rightDock.show() self.msgBrowser.append('Disassembling...') try: text = disassembler.disassemble(self.binBrowser.mem) except Exception as e: self.msgBrowser.append('<font color="red">[ERROR] %s</font>' % (str(e))) self.msgBrowser.append('Disassembling procedure terminated.') return False else: self.msgBrowser.append('Disassembling procedure finished.') self.currentFile = '' self.editor.setPlainText(text) return True # -------------------------------------------------------------------------- # Simulate MIPS instructions # -------------------------------------------------------------------------- def simulate(self): if not self.assemble(): return False self.simulatorWindow.loadSimulator(self.binBrowser.mem, self.binBrowser.init_pc) self.simulatorWindow.show() return True # -------------------------------------------------------------------------- # Pesudo instructions management # -------------------------------------------------------------------------- def pseudoIns(self): pseudoDialog = PseudoDialog(self) pseudoDialog.exec_() # Update highlighter self.highlighter = MipsHighlighter(self.editor.document()) # -------------------------------------------------------------------------- # Setting memory size, text segment address, etc. # -------------------------------------------------------------------------- def setting(self): settingDialog = SettingDialog(self) settingDialog.exec_() # -------------------------------------------------------------------------- # About message box # -------------------------------------------------------------------------- def about(self): QMessageBox.about( self, '关于 YAME', '<p style="font-size: 16px;">YAME: A MIPS Editor</p>'\ '<p style="font-size: 16px;">Made by TsReaper</p>'\ '<p style="font-size: 16px;">YAME 是一个简单的 MIPS 编辑器 / 汇编器 / 反汇编器 / 模拟器。</p>' '<p style="font-size: 16px;">工程 github 页面:<a href="https://github.com/TsReaper/YAME-A-MIPS-Editor">https://github.com/TsReaper/YAME-A-MIPS-Editor</a></p>' ) # -------------------------------------------------------------------------- # Clear editor # -------------------------------------------------------------------------- def newFile(self): if not self.okToContinue(): return False self.editor.clear() self.currentFile = '' self.clearDirty() return True # -------------------------------------------------------------------------- # Open a file in the disk # -------------------------------------------------------------------------- def openFile(self): if not self.okToContinue(): return False path, _ = QFileDialog.getOpenFileName(self, '打开', '', '汇编文件 (*.asm)') if path: try: # Try to use gbk decoder file = open(path, 'r') self.editor.setPlainText(file.read()) except: # Try to use utf-8 decoder file.close() file = open(path, 'r', encoding='utf-8') self.editor.setPlainText(file.read()) file.close() self.currentFile = path self.clearDirty() return True return False # -------------------------------------------------------------------------- # Save current text # -------------------------------------------------------------------------- def saveFile(self): if not self.currentFile: return self.saveAnotherFile() file = open(self.currentFile, 'w') file.write(self.editor.toPlainText()) file.close() self.clearDirty() return True # -------------------------------------------------------------------------- # Save copy of current text # -------------------------------------------------------------------------- def saveAnotherFile(self): path, _ = QFileDialog.getSaveFileName( self, '另存为', self.currentFile if self.currentFile else '', '汇编文件 (*.asm)') if path: file = open(path, 'w') file.write(self.editor.toPlainText()) file.close() self.currentFile = path self.clearDirty() return True return False # -------------------------------------------------------------------------- # Import coe or bin file # -------------------------------------------------------------------------- def importFile(self): self.newFile() path, _ = QFileDialog.getOpenFileName(self, '导入', '', 'COE文件 (*.coe);;二进制文件 (*.bin)') try: if path.split('.')[-1] == 'coe': mem = coe_file.read(path) elif path.split('.')[-1] == 'bin': mem = bin_file.read(path) else: return False except Exception as e: self.msgBrowser.clear() self.bottomDock.show() self.msgBrowser.append('<font color="red">[ERROR] %s</font>' % (str(e))) return False self.rightDock.show() self.binBrowser.showBin(mem) return self.disassemble() # -------------------------------------------------------------------------- # Export coe or bin file # -------------------------------------------------------------------------- def exportFile(self): if not self.assemble(): return False path, _ = QFileDialog.getSaveFileName(self, '导出', '', 'COE文件 (*.coe);;二进制文件 (*.bin)') if path.split('.')[-1] == 'coe': coe_file.write(path, self.binBrowser.mem) return True if path.split('.')[-1] == 'bin': bin_file.write(path, self.binBrowser.mem) return True return False # -------------------------------------------------------------------------- # Setup file menu # -------------------------------------------------------------------------- def setupFileMenu(self): fileMenu = QMenu('文件(&F)', self) self.menuBar().addMenu(fileMenu) fileMenu.addAction('新建(&N)', self.newFile, 'Ctrl+N') fileMenu.addAction('打开(&O)...', self.openFile, 'Ctrl+O') fileMenu.addAction('保存(&S)', self.saveFile, 'Ctrl+S') fileMenu.addAction('另存为(&A)...', self.saveAnotherFile, 'Ctrl+Alt+S') fileMenu.addAction('导入(&I)...', self.importFile, 'Ctrl+I') fileMenu.addAction('导出(&E)...', self.exportFile, 'Ctrl+E') fileMenu.addAction('退出(&X)', self.close, 'Alt+F4') # -------------------------------------------------------------------------- # Setup setting menu # -------------------------------------------------------------------------- def setupSettingMenu(self): settingMenu = QMenu('设置(&S)', self) self.menuBar().addMenu(settingMenu) settingMenu.addAction('汇编器设置', self.setting, 'F6') settingMenu.addAction('伪指令', self.pseudoIns, 'F7') # -------------------------------------------------------------------------- # Setup assemble menu # -------------------------------------------------------------------------- def setupAssembleMenu(self): assembleMenu = QMenu('汇编(&A)', self) self.menuBar().addMenu(assembleMenu) assembleMenu.addAction('汇编(&A)', self.assemble, 'F9') assembleMenu.addAction('反汇编(&D)', self.disassemble, 'F10') assembleMenu.addAction('模拟(&S)', self.simulate, 'F11') # -------------------------------------------------------------------------- # Setup help menu # -------------------------------------------------------------------------- def setupHelpMenu(self): helpMenu = QMenu("帮助(&H)", self) self.menuBar().addMenu(helpMenu) helpMenu.addAction('关于(&A)', self.about) # -------------------------------------------------------------------------- # Setup mips editor # -------------------------------------------------------------------------- def setupEditor(self): self.editor = MipsEditor() self.editor.textChanged.connect(self.setDirty) self.highlighter = MipsHighlighter(self.editor.document()) # -------------------------------------------------------------------------- # Setup dockable widgets # -------------------------------------------------------------------------- def setupDockable(self): self.msgBrowser = MessageBrowser() self.bottomDock = QDockWidget('信息', self) self.bottomDock.setFeatures(QDockWidget.DockWidgetClosable) self.bottomDock.setWidget(self.msgBrowser) self.addDockWidget(Qt.BottomDockWidgetArea, self.bottomDock) self.bottomDock.hide() self.binBrowser = BinBrowser() self.rightDock = QDockWidget('机器码', self) self.rightDock.setFeatures(QDockWidget.DockWidgetClosable) self.rightDock.setWidget(self.binBrowser) self.addDockWidget(Qt.RightDockWidgetArea, self.rightDock) self.rightDock.hide()
class Ui_MainWindow(object): def setupUi(self, MainWindow): # ============================================================================ # Header MainWindow.setObjectName("") MainWindow.setMinimumSize(603, 534) MainWindow.setMaximumSize(603, 534) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") # =================Sessao de Empresa Ativa==================== self.LabelCnpjCompany = QtWidgets.QLabel(self.centralwidget) self.LabelCnpjCompany.setGeometry(QtCore.QRect(240, 0, 90, 21)) self.LabelCnpjCompany.setText("CNPJ: ") self.ActiveCNPJ = QtWidgets.QLabel(self.centralwidget) self.ActiveCNPJ.setGeometry(QtCore.QRect(280, 0, 111, 21)) self.ActiveCNPJ.setText("") self.ActiveCNPJ.setObjectName("ActiveCNPJ") self.TxtCnpjCompany = QtWidgets.QLabel(self.centralwidget) self.TxtCnpjCompany.setGeometry(QtCore.QRect(420, 0, 90, 21)) self.TxtCnpjCompany.setText("Empresa: ") self.ActiveCompany = QtWidgets.QLabel(self.centralwidget) self.ActiveCompany.setGeometry(QtCore.QRect(486, 0, 111, 21)) self.ActiveCompany.setText("") self.ActiveCompany.setObjectName("ActiveCompany") # ==================================================================================== # ==================================================================================== # Criar Menu # ==================================================================================== MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 603, 22)) self.menubar.setObjectName("menubar") self.menuEmpresa = QtWidgets.QMenu(self.menubar) self.menuEmpresa.setObjectName("menuEmpresa") self.menuImportar = QtWidgets.QMenu(self.menubar) self.menuImportar.setObjectName("menuImportar") self.menuExportar = QtWidgets.QMenu(self.menubar) self.menuExportar.setObjectName("menuExportar") self.menuAnalise = QtWidgets.QMenu(self.menubar) self.menuAnalise.setObjectName('menuAnalise') self.menuCorrecoes = QtWidgets.QMenu(self.menubar) self.menuCorrecoes.setObjectName("menuCorrecoes") self.menuUteis = QtWidgets.QMenu(self.menubar) self.menuUteis.setObjectName('menuUteis') MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) # ==================================================================================== # ==================================================================================== # Criação das telas # ==================================================================================== self.AlertScreen = QDockWidget(self.centralwidget) self.AlertScreen.hide() # ==================Ativar Empresa==================================================== self.AtivarEmpresaScreen = QDockWidget(self.centralwidget) self.AtivarEmpresaScreen.hide() # ==================Cadastrar Empresa================================================= self.CadastrarEmpresaScreen = QDockWidget(self.centralwidget) self.CadastrarEmpresaScreen.hide() # ==================Editar Empresa==================================================== self.EditarEmpresaScreen = QDockWidget(self.centralwidget) self.EditarEmpresaScreen.hide() # ==================================================================================== # ==================Importar XML==================================================== self.ImportarXMLScreen = QDockWidget(self.centralwidget) self.ImportarXMLScreen.hide() # ==================================================================================== # ==================Importar Registro C170============================================ self.ImportarC170Screen = QDockWidget(self.centralwidget) self.ImportarC170Screen.hide() # ==================================================================================== # ==================Corrigir cadastro - CEST========================================== self.CorrgirCestScreen = QDockWidget(self.centralwidget) self.CorrgirCestScreen.hide() # ==================================================================================== # ==================Corrigir cadastro - 0220========================================== self.Corrgir0220Screen = QDockWidget(self.centralwidget) self.Corrgir0220Screen.hide() # ==================================================================================== # ==================XML em SPED======================================================= self.XMLinSPEDScreen = QDockWidget(self.centralwidget) self.XMLinSPEDScreen.hide() # ==================================================================================== # ==================Calcular Quant ICMS Ressarcimento================================= self.Calc_Quant_ICMS_RessarScreen = QDockWidget(self.centralwidget) self.Calc_Quant_ICMS_RessarScreen.hide() # ==================================================================================== # ==================Exportar Saldo Inicial - Tela===================================== self.ExportarSaldoInicialScreen = QDockWidget(self.centralwidget) self.ExportarSaldoInicialScreen.hide() # ==================================================================================== # ==================Exportar Saldo Inicial - Tela===================================== self.FindXMlWithoutStScreen = QDockWidget(self.centralwidget) self.FindXMlWithoutStScreen.hide() # ==================================================================================== # ==================Importar Cadatro produtis - Tela================================== self.CadstroProdutosScreen = QDockWidget(self.centralwidget) self.CadstroProdutosScreen.hide() # ==================================================================================== # ==================Importar Registro H010- Tela====================================== self.ImportarRegistroH010Screen = QDockWidget(self.centralwidget) self.ImportarRegistroH010Screen.hide() # ==================================================================================== # ==================Importar Codigo de Relacionamento Tela============================ self.ImportarCodigoRelacionamentoScreen = QDockWidget( self.centralwidget) self.ImportarCodigoRelacionamentoScreen.hide() # ==================================================================================== # ==================================================================================== self.actionAtivar_empresa = QtWidgets.QAction(MainWindow) self.actionAtivar_empresa.setObjectName("actionAtivar_empresa") self.actionAtivar_empresa.triggered.connect( lambda: self.handleAtiverEmpresa()) self.actionCadastrar = QtWidgets.QAction(MainWindow) self.actionCadastrar.setObjectName("actionCadastrar") self.actionCadastrar.triggered.connect( lambda: self.handleCadastrarEmpresa()) #====================Action Importar XML ==================================== self.actionXML_Entrada = QtWidgets.QAction(MainWindow) self.actionXML_Entrada.setObjectName("actionXML_Entrada") self.actionXML_Entrada.triggered.connect( lambda: self.handleImportarXML()) #=========================================================================== #===================Action Editar=========================================== self.actionEditar = QtWidgets.QAction(MainWindow) self.actionEditar.setObjectName("actionEditar") self.actionEditar.triggered.connect(lambda: self.handleEditarEmpresa()) #=========================================================================== self.actionCodigo_de_relacionamento_2 = QtWidgets.QAction(MainWindow) self.actionCodigo_de_relacionamento_2.setObjectName( "actionCodigo_de_relacionamento_2") self.actionGerar_SPED_com_0220 = QtWidgets.QAction(MainWindow) self.actionGerar_SPED_com_0220.setObjectName( "actionGerar_SPED_com_0220") #====================SPED_Corrigir_CEST======================================= self.actionAdicionar_SPED_Corrigir_CEST = QtWidgets.QAction(MainWindow) self.actionAdicionar_SPED_Corrigir_CEST.setObjectName( "actionAdicionar_SPED_Corrigir_CEST") self.actionAdicionar_SPED_Corrigir_CEST.triggered.connect( lambda: self.handleCorrgirCest()) #============================================================================= #====================Action Registro C170 ==================================== self.actionRegistro_C170_SPED = QtWidgets.QAction(MainWindow) self.actionRegistro_C170_SPED.setObjectName("actionRegistro_C170_SPED") self.actionRegistro_C170_SPED.triggered.connect( lambda: self.handleImportarC170()) #============================================================================= #====================Action adicionar 0220==================================== self.actionAdicionar_registro_0220_no_SPED = QtWidgets.QAction( MainWindow) self.actionAdicionar_registro_0220_no_SPED.setObjectName( "actionAdicionar_registro_0220_no_SPED") self.actionAdicionar_registro_0220_no_SPED.triggered.connect( lambda: self.handleCorrgir0220()) #============================================================================= self.actionFator_de_convers_o = QtWidgets.QAction(MainWindow) self.actionFator_de_convers_o.setObjectName("actionFator_de_convers_o") # ======================Calcular SALDO INICIAL================================ self.actionSaldo_inicial = QtWidgets.QAction(MainWindow) self.actionSaldo_inicial.setObjectName("actionSaldo_inicial") self.actionSaldo_inicial.triggered.connect( lambda: self.handleCalSaldoInicial()) # ============================================================================= self.actionVerificarXMLInSPED = QtWidgets.QAction(MainWindow) self.actionVerificarXMLInSPED.setObjectName( "actionactionVerificarXMLInSPED") self.actionVerificarXMLInSPED.triggered.connect( lambda: self.handleXMLInSPED()) # =========================Action calcular quant icms ressarcimento============ self.actionCalcQuantICMSRessar = QtWidgets.QAction(MainWindow) self.actionCalcQuantICMSRessar.setObjectName( "actionCalcQuantICMSRessar") self.actionCalcQuantICMSRessar.triggered.connect( lambda: self.handleCalcularICMSRessarcimento()) # ============================================================================= # =========================Action Encontar XML sem ST============ self.actionFindXMLWitoughtST = QtWidgets.QAction(MainWindow) self.actionFindXMLWitoughtST.setObjectName("actionFindXMLWitoughtST") self.actionFindXMLWitoughtST.triggered.connect( lambda: self.handleFindXMLWhithoughtST()) # ============================================================================= # =========================Action Impoartar Cadastro produtos================== self.actionImportarCadastroProduto = QtWidgets.QAction(MainWindow) self.actionImportarCadastroProduto.setObjectName( "actionImportarCadastroProduto") self.actionImportarCadastroProduto.triggered.connect( lambda: self.handleCadastroProdutos()) # ============================================================================= # =========================Action importar Registro H010======================= self.actionImportarRegistroH010 = QtWidgets.QAction(MainWindow) self.actionImportarRegistroH010.setObjectName( "actionImportarRegistroH010") self.actionImportarRegistroH010.triggered.connect( lambda: self.handleImportarRegistroH010()) # ============================================================================= # =========================Action importar Codigo de Relacionamento============ self.actionImportarCodigoRelacionamento = QtWidgets.QAction(MainWindow) self.actionImportarCodigoRelacionamento.setObjectName( "actionImportarCodigoRelacionamento") self.actionImportarCodigoRelacionamento.triggered.connect( lambda: self.handleImportarCodigoRelacionamento()) # ============================================================================= # ======================= Adicionar Ações no menu ============================= self.menuEmpresa.addAction(self.actionAtivar_empresa) self.menuEmpresa.addAction(self.actionCadastrar) self.menuEmpresa.addAction(self.actionEditar) self.menuImportar.addAction(self.actionXML_Entrada) self.menuImportar.addAction(self.actionRegistro_C170_SPED) self.menuImportar.addAction(self.actionFator_de_convers_o) self.menuImportar.addAction(self.actionImportarCadastroProduto) self.menuImportar.addAction(self.actionImportarRegistroH010) self.menuImportar.addAction(self.actionImportarCodigoRelacionamento) self.menuExportar.addAction(self.actionCodigo_de_relacionamento_2) self.menuExportar.addAction(self.actionSaldo_inicial) self.menuAnalise.addAction(self.actionVerificarXMLInSPED) self.menuCorrecoes.addAction(self.actionAdicionar_SPED_Corrigir_CEST) self.menuCorrecoes.addAction( self.actionAdicionar_registro_0220_no_SPED) self.menuUteis.addAction(self.actionCalcQuantICMSRessar) self.menuUteis.addAction(self.actionFindXMLWitoughtST) self.menubar.addAction(self.menuEmpresa.menuAction()) self.menubar.addAction(self.menuImportar.menuAction()) self.menubar.addAction(self.menuExportar.menuAction()) self.menubar.addAction(self.menuAnalise.menuAction()) self.menubar.addAction(self.menuCorrecoes.menuAction()) self.menubar.addAction(self.menuUteis.menuAction()) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.ActiveCompany.setWhatsThis( _translate( "MainWindow", "<html><head/><body><p>Empresa ativa</p></body></html>")) self.menuEmpresa.setTitle(_translate("MainWindow", "Empresa")) self.menuImportar.setTitle(_translate("MainWindow", "Importar")) self.menuExportar.setTitle(_translate("MainWindow", "Exportar")) self.menuAnalise.setTitle(_translate("MainWindow", "Analises")) self.menuCorrecoes.setTitle(_translate("MainWindow", "Correções")) self.menuUteis.setTitle(_translate("MainWindow", "Uteis")) self.actionAtivar_empresa.setText(_translate("MainWindow", "Ativar")) self.actionCadastrar.setText(_translate("MainWindow", "Cadastrar")) self.actionXML_Entrada.setText(_translate("MainWindow", "XML Entrada")) self.actionEditar.setText(_translate("MainWindow", "Editar")) self.actionCodigo_de_relacionamento_2.setText( _translate("MainWindow", "Codigo de relacionamento")) self.actionGerar_SPED_com_0220.setText( _translate("MainWindow", "Adicionar registro 0220 no SPED")) self.actionAdicionar_SPED_Corrigir_CEST.setText( _translate("MainWindow", "SPED - Corrigir CEST")) self.actionRegistro_C170_SPED.setText( _translate("MainWindow", "Registro C170 - SPED")) self.actionAdicionar_registro_0220_no_SPED.setText( _translate("MainWindow", "SPED - Adicionar 0220")) self.actionFator_de_convers_o.setText( _translate("MainWindow", "Fator de conversão")) self.actionSaldo_inicial.setText( _translate("MainWindow", "Saldo inicial")) self.actionVerificarXMLInSPED.setText( _translate("MainWindow", "Verificar XML em SPED")) self.actionCalcQuantICMSRessar.setText( _translate("MainWindow", "Calcular ICMS Ressarcimento")) self.actionFindXMLWitoughtST.setText( _translate("MainWindow", "Encontrar XML Transf S/ ST")) self.actionImportarCadastroProduto.setText( _translate("MainWindow", "Cadastro de Produtos")) self.actionImportarRegistroH010.setText( _translate("MainWindow", "Registro H010")) self.actionImportarCodigoRelacionamento.setText( _translate("MainWindow", "Codigo Relacionamento")) def handleAtiverEmpresa(self): AtivarFeature(self.AtivarEmpresaScreen, self.ActiveCompany, self.ActiveCNPJ) def handleCadastrarEmpresa(self): CadastrarFeature(self.CadastrarEmpresaScreen) def handleImportarXML(self): XMLFeature(self.ImportarXMLScreen, self.ActiveCNPJ, self.AlertScreen) def handleImportarC170(self): RegistroC170Feature(self.ImportarC170Screen, self.ActiveCNPJ) def handleCorrgirCest(self): CorrigirCestFeature(self.CorrgirCestScreen, self.ActiveCNPJ) def handleCorrgir0220(self): Corrigir0220Feature(self.Corrgir0220Screen, self.ActiveCNPJ) def handleEditarEmpresa(self): EditarFeature(self.EditarEmpresaScreen, self.ActiveCNPJ) def handleXMLInSPED(self): XMLInSPEDFeature(self.XMLinSPEDScreen, self.ActiveCNPJ) def handleCalcularICMSRessarcimento(self): CalcICMSRessarFeature(self.XMLinSPEDScreen, self.ActiveCNPJ) def handleCalSaldoInicial(self): SaldoInicialFeature(self.ExportarSaldoInicialScreen, self.ActiveCNPJ) def handleFindXMLWhithoughtST(self): FindXMlWithoutStFeature(self.FindXMlWithoutStScreen, self.ActiveCNPJ) def handleCadastroProdutos(self): ImportarCadastroProdutosFeature(self.FindXMlWithoutStScreen, self.ActiveCNPJ) def handleImportarRegistroH010(self): RegistroH010Feature(self.FindXMlWithoutStScreen, self.ActiveCNPJ) def handleImportarCodigoRelacionamento(self): ImportarCodigoRelacionamentoFeature(self.FindXMlWithoutStScreen, self.ActiveCNPJ)
class Window(QMainWindow): def __init__(self): super(Window, self).__init__() self.setWindowTitle('MIPS') # 窗口标题 # 设置各项菜单 self.setupFileMenu() self.setupAssembleMenu() self.setupDebugMenu() self.setupHelpMenu() self.setupEditor() # 设置编辑器 self.setCentralWidget(self.editor) self.setupDock() # 设置Dock栏 def setupEditor(self): self.editor = Editor() # 创建编辑器对象 def setupFileMenu(self): fileMenu = QMenu('文件(&F)', self) self.menuBar().addMenu(fileMenu) self.currentFile = '' # 设置当前文件路径为空值 fileMenu.addAction('新建(&N)', self.newFile, 'Ctrl+N') # 新建立一个文件 fileMenu.addAction('打开(&O)...', self.openFile, 'Ctrl+O') # 打开已有的文件 fileMenu.addAction('保存(&S)', self.saveFile, 'Ctrl+S') # 将当前文件保存 fileMenu.addAction('另存为(&A)...', self.saveAnotherFile, 'Ctrl+Alt+S') # 将当前文件保存到指定路径 fileMenu.addAction('退出(&X)', self.close, 'Ctrl+F4') # 退出MIPS汇编器 def setupAssembleMenu(self): assembleMenu = QMenu('汇编(&A)', self) self.menuBar().addMenu(assembleMenu) self.assembler = Assembler() # 创建汇编器对象 assembleMenu.addAction('汇编(&A)', self.assemble, 'F10') # 对当前代码实行汇编操作 assembleMenu.addAction('反汇编(&D)', self.disassemble, 'F11') # 对当前代码实行反汇编操作 def setupDebugMenu(self): assembleMenu = QMenu('调试(&D)', self) self.menuBar().addMenu(assembleMenu) self.isStart = False # 设置是否开始调试布尔值为否 assembleMenu.addAction('启动调试(&S)', self.startDebug, 'F5') # 启动调试 assembleMenu.addAction('继续调试(&C)', self.contiuneDebug, 'F5') # 将调试进行到最后一步 assembleMenu.addAction('单步执行(&I)', self.nextDebug, 'F11') # 单步进行调试 assembleMenu.addAction('停止调试(&S)', self.stopDebug, 'Shift+F5') # 停止调试过程 assembleMenu.addAction('重启调试(&R)', self.resetDebug, 'Ctrl+Shift+F5') # 重新启动调试过程 def setupHelpMenu(self): helpMenu = QMenu("帮助(&H)", self) self.menuBar().addMenu(helpMenu) helpMenu.addAction('关于(&A)', self.about) # 本程序的小介绍 def setupDock(self): # 建立输出运行结果的窗口 self.rightBrowser = Browser() # 建立在窗口右端 self.rightDock = QDockWidget('运行结果/内存', self) self.rightDock.setFeatures(QDockWidget.DockWidgetClosable) self.rightDock.setWidget(self.rightBrowser) self.addDockWidget(Qt.RightDockWidgetArea, self.rightDock) self.rightDock.hide() # 窗口自动隐藏 # 建立输出调试过程的窗口 self.bottomBrowser = Browser() # 建立在窗口底端 self.bottomDock = QDockWidget('调试窗口', self) self.bottomDock.setFeatures(QDockWidget.DockWidgetClosable) self.bottomDock.setWidget(self.bottomBrowser) self.addDockWidget(Qt.BottomDockWidgetArea, self.bottomDock) self.bottomDock.hide() def newFile(self): self.editor.clear() # 清空当前屏幕 self.rightDock.hide() # 隐藏Dock栏 self.bottomDock.hide() self.currentFile = '' return True def openFile(self): # 打开汇编文件或二进制文件 path, _ = QFileDialog.getOpenFileName( self, '打开', '', '汇编文件 (*.asm);;二进制文件(*.coe *.bin)') if path: file = open(path, 'r') self.editor.setPlainText(file.read()) file.close() self.rightDock.hide() self.bottomDock.hide() self.currentFile = path return True return False def saveFile(self): # 如果没有文件名则跳转到另存为 if not self.currentFile: return self.saveAnotherFile() # 将编辑器内容写入到当前路径文件 file = open(self.currentFile, 'w') file.write(self.editor.toPlainText()) file.close() return True def saveAnotherFile(self): # 选择存入文件路径 path, _ = QFileDialog.getSaveFileName( self, '另存为', self.currentFile if self.currentFile else '', '汇编文件 (*.asm);;二进制文件(*.coe *.bin)') # 路径存在则将编辑器内容写入 if path: file = open(path, 'w') file.write(self.editor.toPlainText()) file.close() self.currentFile = path return True return False def assemble(self): self.saveFile() # 执行前保存文件 try: self.rightBrowser.setText(self.assembler.assembly( self.currentFile)) # 执行汇编并在右侧输出结果 except: self.rightBrowser.setText( 'error!!! \ncheck your code!!!') # 代码有误不能正确汇编 return self.rightDock.show() def disassemble(self): self.saveFile() try: self.rightBrowser.setText( self.assembler.disassembly(self.currentFile)) # 执行反汇编并在右侧输出结果 except: self.rightBrowser.setText( 'error!!! \ncheck your code!!!') # 代码有误不能正确反汇编 return self.rightDock.show() def startDebug(self): self.saveFile() self.assembler.step = 0 # 初始化执行步数 self.debugStr = '' # 初始化结果字符 self.isStart = True # 设定已经开始 # 初始化寄存器内容 for k in self.assembler.registers: self.assembler.registers[k] = '00000000' self.assembler.memory = {} # 初始化内存 try: self.assembler.debug(self.currentFile) self.debugStr = str(self.assembler.memory).strip("{}").replace( "'", '').replace(':', ' ').replace(',', ' ') # 执行单步模拟操作 except: self.debugStr += '\nthe debug is over\nnow check your code' # 模拟完成或代码有误则停止 return False # 将寄存器内容展示在底部,结果展示在右部 self.bottomBrowser.setText(' ' + str(self.assembler.registers).strip( "{},").replace(':', '\t').replace(',', '\t').replace("'", '')) self.rightBrowser.setText(self.debugStr) self.rightDock.show() self.bottomDock.show() return True def contiuneDebug(self): # 如果没有开始则开始调试 if not self.isStart: self.startDebug() # 模拟进行到最后一步 while self.nextDebug(): continue self.bottomBrowser.setText( str(self.assembler.registers).strip("{},").replace( ':', '\t').replace(',', '\t').replace("'", '')) self.rightBrowser.setText(self.debugStr) self.rightDock.show() self.bottomDock.show() return True def nextDebug(self): if not self.isStart: return self.startDebug() try: self.assembler.debug(self.currentFile) self.debugStr = str(self.assembler.memory).strip("{}").replace( "'", '').replace(':', ' ').replace(',', ' ') except: self.debugStr += '\nthe debug is over\nnow check your code' self.rightBrowser.setText(self.debugStr) self.rightDock.show() return False self.bottomBrowser.setText( str(self.assembler.registers).strip("{},").replace( ':', '\t').replace(',', '\t').replace("'", '')) self.rightBrowser.setText(self.debugStr) self.rightDock.show() self.bottomDock.show() return True def stopDebug(self): self.isStart = False # 结束调试并将开始置否 self.bottomDock.hide() self.rightDock.hide() return True def resetDebug(self): self.stopDebug() return self.startDebug() def about(self): # 简短介绍本程序 QMessageBox.about( self, '关于本MIPS汇编器', '<p style="font-size: 16px;">Made By Aaron</p>' '<p style="font-size: 16px;">可实现MIPS汇编器(支持伪码),反汇编器,调试器</p>' '<p style="font-size: 16px;">介绍请见README.md</p>' '<p style="font-size: 16px;">具体细节请参考实验报告')
class _QtDock(_AbstractDock): def _dock_initialize(self): self.dock = QDockWidget() self.scroll = QScrollArea(self.dock) self.dock.setWidget(self.scroll) widget = QWidget(self.scroll) self.scroll.setWidget(widget) self.scroll.setWidgetResizable(True) self.dock.setAllowedAreas(Qt.LeftDockWidgetArea) self.dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.plotter.app_window.addDockWidget(Qt.LeftDockWidgetArea, self.dock) self.dock_layout = QVBoxLayout() widget.setLayout(self.dock_layout) def _dock_finalize(self): self.dock.setMinimumSize(self.dock.sizeHint().width(), 0) self._dock_add_stretch(self.dock_layout) def _dock_show(self): self.dock.show() def _dock_hide(self): self.dock.hide() def _dock_add_stretch(self, layout): layout.addStretch() def _dock_add_layout(self, vertical=True): layout = QVBoxLayout() if vertical else QHBoxLayout() return layout def _dock_add_label(self, value, align=False, layout=None): layout = self.dock_layout if layout is None else layout widget = QLabel() if align: widget.setAlignment(Qt.AlignCenter) widget.setText(value) layout.addWidget(widget) return widget def _dock_add_button(self, name, callback, layout=None): layout = self.dock_layout if layout is None else layout # If we want one with text instead of an icon, we should use # QPushButton(name) widget = QToolButton() widget.clicked.connect(callback) widget.setText(name) layout.addWidget(widget) return widget def _dock_named_layout(self, name, layout, compact): layout = self.dock_layout if layout is None else layout if name is not None: hlayout = self._dock_add_layout(not compact) self._dock_add_label(value=name, align=not compact, layout=hlayout) layout.addLayout(hlayout) layout = hlayout return layout def _dock_add_slider(self, name, value, rng, callback, compact=True, double=False, layout=None, stretch=0): layout = self._dock_named_layout(name, layout, compact) slider_class = QFloatSlider if double else QSlider cast = float if double else int widget = slider_class(Qt.Horizontal) widget.setMinimum(cast(rng[0])) widget.setMaximum(cast(rng[1])) widget.setValue(cast(value)) widget.valueChanged.connect(callback) layout.addWidget(widget) return widget def _dock_add_spin_box(self, name, value, rng, callback, compact=True, double=True, layout=None): layout = self._dock_named_layout(name, layout, compact) value = value if double else int(value) widget = QDoubleSpinBox() if double else QSpinBox() widget.setAlignment(Qt.AlignCenter) widget.setMinimum(rng[0]) widget.setMaximum(rng[1]) inc = (rng[1] - rng[0]) / 20. inc = max(int(round(inc)), 1) if not double else inc widget.setKeyboardTracking(False) widget.setSingleStep(inc) widget.setValue(value) widget.valueChanged.connect(callback) layout.addWidget(widget) return widget def _dock_add_combo_box(self, name, value, rng, callback, compact=True, layout=None): layout = self._dock_named_layout(name, layout, compact) widget = QComboBox() widget.addItems(rng) widget.setCurrentText(value) widget.currentTextChanged.connect(callback) widget.setSizeAdjustPolicy(QComboBox.AdjustToContents) layout.addWidget(widget) return widget def _dock_add_group_box(self, name, layout=None): layout = self.dock_layout if layout is None else layout hlayout = QVBoxLayout() widget = QGroupBox(name) widget.setLayout(hlayout) layout.addWidget(widget) return hlayout
class pyviViewerWindow(QtGui.QMainWindow): def __init__(self, flowchart): QtGui.QMainWindow.__init__(self) self.resize(1000, 800) self.setWindowTitle('Viewer') self.fc = flowchart self.fc.sigChartChanged.connect(self.nodeEvent) self.fc.sigChartLoaded.connect(self.loadChartEvent) self.fc.widget().resize(1000, 800) self.pyviwin = SimpleWindow() ## http://blog.qt.io/blog/2013/02/19/introducing-qwidgetcreatewindowcontainer/ pyvi_widget = QWidget.createWindowContainer(self.pyviwin) pyvi_widget.setMinimumSize(200, 200) pyvi_widget.resize(800, 800) self.setCentralWidget(pyvi_widget) self.layerDockWidget = QDockWidget('Layers') self.layerDockWidget.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.layerDockWidget.setWidget(self.pyviwin.layerWidget) self.pyviwin.layerWidget.resize(200, 500) self.addDockWidget(Qt.RightDockWidgetArea, self.layerDockWidget) self.plotDockWidget = QDockWidget('Plot') self.plotDockWidget.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable) self.plotWidget = PlotWidget() self.plotDockWidget.setWidget(self.plotWidget) self.plotWidget.resize(100, 100) # self.plotDockWidget.show() # self.addDockWidget(Qt.RightDockWidgetArea, self.plotDockWidget) self.plotList = {'plot 1': self.plotWidget} self.plot3DDockWidget = QDockWidget('Plot3D') self.plot3DDockWidget.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable) self.pyviwin_plot = SimpleWindow() pyviwin_plot_widget = QWidget.createWindowContainer(self.pyviwin_plot) pyviwin_plot_widget.setMinimumSize(100, 100) pyviwin_plot_widget.resize(200, 200) self.plot3DDockWidget.setWidget(pyviwin_plot_widget) self.plot3DDockWidget.show() # self.plot3D.resize(100,100) self.plotLayerDockWidget = QDockWidget('Plot Layers') self.plotLayerDockWidget.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.plotLayerDockWidget.setWidget(self.pyviwin_plot.layerWidget) self.pyviwin_plot.layerWidget.resize(200, 500) self.addDockWidget(Qt.RightDockWidgetArea, self.plotLayerDockWidget) # self.dockWidgetDict = {} self.createActions() self.createMenus() self.show() self.fc.widget().show() def save(self): try: self.fc.saveFile() except: raise def open(self): self.fc.loadFile() def createActions(self): self.saveAct = QAction("&Save...", self, shortcut=QtGui.QKeySequence.Save, statusTip="Save the current form letter", triggered=self.save) self.openAct = QAction("&Open...", self, shortcut=QtGui.QKeySequence.Open, statusTip="Save the current form letter", triggered=self.open) self.reloadAct = QAction("&Reload nodelibs...", self, shortcut=QtGui.QKeySequence.Refresh, statusTip="Reload nodelibraries", triggered=self.fc.widget().reloadLibrary) self.quitAct = QAction("&Quit", self, shortcut=QtGui.QKeySequence.Quit, statusTip="Quit the application", triggered=self.close) self.toggleViewerAct = QAction("&Toggle Viewer", self, statusTip="Toggle viewer window", triggered=self.toggleViewer) self.toggleFlowchartAct = QAction("&Toggle Flowchart", self, statusTip="Toggle flowchart window", triggered=self.toggleFlowchart) self.togglePlotterAct = QAction("&Toggle Plotter", self, statusTip="Toggle plot window", triggered=self.togglePlotter) def toggleViewer(self): if self.isHidden(): self.show() else: self.hide() def togglePlotter(self): if self.plotDockWidget.isHidden(): self.plotDockWidget.show() else: self.plotDockWidget.hide() def toggleFlowchart(self): if self.fc.widget().isHidden(): self.fc.widget().show() else: self.fc.widget().hide() def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.reloadAct) # self.fileMenu.addSeparator() # self.fileMenu.addAction(self.quitAct) # self.editMenu = self.menuBar().addMenu("&Edit") # self.editMenu.addAction(self.undoAct) self.viewMenu = self.menuBar().addMenu("&View") self.viewMenu.addAction(self.toggleViewerAct) self.viewMenu.addAction(self.toggleFlowchartAct) self.viewMenu.addAction(self.togglePlotterAct) def loadChartEvent(self): # self.clearDock() for node in self.fc.nodes().values(): self.addNode(node) def nodeEvent(self, flowchart, action, node): if action == 'add': self.addNode(node) elif action == 'remove': self.removeNode(node) elif action == 'rename': pass # try: # self.dockWidgetDict[node].setWindowTitle(node.name()) # except KeyError: # pass def addNode(self, node): # ctrlWidget = node.ctrlWidget() # if ctrlWidget: # dock = QDockWidget(node.name(), self) # dock.setWidget(node.ctrlWidget()) # dock.hide() # # nodeDock.hideTitleBar() # # self.da.addDock(nodeDock, 'right', ) # self.addDockWidget(Qt.RightDockWidgetArea, dock) # self.viewMenu.addAction(dock.toggleViewAction()) # self.dockWidgetDict[node] = dock if type(node) is pvWindowNode: node.setPyViWindow(self.pyviwin, self.pyviwin_plot) elif type(node) is PlotWidgetNode: node.setPlotList(self.plotList) node.setPlot(self.plotWidget) def removeNode(self, node): print("removing...", node)
class OpenposeGUI(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("OpencvGUI") self.setWindowIcon(QIcon("icon/logo.png")) # QAction self.action_autosave = QAction(QIcon("icon/autosave.png"), "自动保存", self) self.action_save = QAction(QIcon("icon/save.png"), "保存", self) self.action_image = QAction(QIcon("icon/image.png"), "打开图片", self) self.action_video = QAction(QIcon("icon/video.png"), "打开视频", self) self.action_camera = QAction(QIcon("icon/camera.png"), "打开摄像头", self) self.action_folder = QAction(QIcon("icon/folder.png"), "打开文件夹", self) self.action_setting = QAction(QIcon("icon/setting.png"), "设置", self) self.action_filetree = QAction(QIcon("icon/filetree.png"), "目录树", self) self.action_camera.setCheckable(True) self.action_video.setCheckable(True) self.action_setting.setCheckable(True) self.action_filetree.setCheckable(True) self.action_autosave.setCheckable(True) # 菜单栏 self.menu_bar = QMenuBar() self.menu_open = self.menu_bar.addMenu("Open") self.menu_open.addAction(self.action_image) self.menu_open.addAction(self.action_video) self.menu_open.addAction(self.action_camera) self.menu_view = self.menu_bar.addMenu("View") self.menu_view.addAction(self.action_setting) self.menu_view.addAction(self.action_filetree) self.menu_function = self.menu_bar.addMenu("Function") self.action_background = self.menu_function.addAction( "Black/RGB Blackground") self.action_geture = self.menu_function.addAction( "Gesture Recognition") self.setMenuBar(self.menu_bar) # 工具栏 self.tool_bar = QToolBar() self.tool_bar.addAction(self.action_save) self.tool_bar.addAction(self.action_autosave) self.tool_bar.addSeparator() self.tool_bar.addAction(self.action_folder) self.tool_bar.addAction(self.action_camera) self.tool_bar.addAction(self.action_image) self.tool_bar.addAction(self.action_video) self.tool_bar.addSeparator() self.tool_bar.addAction(self.action_setting) self.tool_bar.addAction(self.action_filetree) self.addToolBar(self.tool_bar) # 状态栏 self.status_bar = QStatusBar() self.status_fps = QLabel("FPS:00.0") self.status_bar.addPermanentWidget(self.status_fps) self.setStatusBar(self.status_bar) # 组件 self.timer = QTimer() self.camera = Camera(self) self.setting_widget = SettingWidget(self) self.label_frame = LabelFrame(self) self.file_system_tree = FileSystemTreeView(self) self.openpose_model = OpenposeModel(self) self.media_control = MediaControl(self) self.save_widget = SaveWidget() self.gesture_model = GestureModel() # 设置dock self.dock_filetree = QDockWidget(self) self.dock_filetree.setWidget(self.file_system_tree) self.dock_file_label = QLabel("Current Directory") self.dock_file_label.setMinimumHeight(25) self.dock_file_label.setAlignment(Qt.AlignCenter | Qt.AlignHCenter) self.dock_filetree.setTitleBarWidget(self.dock_file_label) self.dock_filetree.setFeatures(QDockWidget.AllDockWidgetFeatures) self.dock_filetree.hide() self.dock_setting = QDockWidget(self) self.dock_setting.setWidget(self.setting_widget) self.dock_setting_label = QLabel("Openpose Settings") self.dock_setting_label.setMinimumHeight(25) self.dock_setting_label.setAlignment(Qt.AlignCenter | Qt.AlignHCenter) self.dock_setting.setTitleBarWidget(self.dock_setting_label) self.dock_setting.setFeatures(QDockWidget.AllDockWidgetFeatures) self.dock_setting.hide() self.dock_media = QDockWidget(self) self.dock_media.setWidget(self.media_control) self.dock_media.setFeatures(QDockWidget.NoDockWidgetFeatures) self.dock_media.hide() self.setCentralWidget(self.label_frame) self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_setting) self.addDockWidget(Qt.LeftDockWidgetArea, self.dock_filetree) self.addDockWidget(Qt.BottomDockWidgetArea, self.dock_media) # 信号与槽 self.setting_widget.horizontalSlider_Body.sliderReleased.connect( self.change_body_threshold) self.setting_widget.horizontalSlider_Face.sliderReleased.connect( self.change_face_threshold) self.setting_widget.horizontalSlider_Hand.sliderReleased.connect( self.change_hand_threshold) self.setting_widget.checkBox_body.stateChanged.connect( self.check_body) # 状态改变触发check_box_changed函数 self.setting_widget.checkBox_hand.stateChanged.connect( self.check_hand) # 状态改变触发check_box_changed函数 self.setting_widget.checkBox_face.stateChanged.connect( self.check_face) # 状态改变触发check_box_changed函数 self.setting_widget.radioButton_black.toggled.connect( self.change_background) self.setting_widget.comboBox_resolution.currentIndexChanged.connect( self.change_resolution) self.media_control.play_button.toggled.connect(self.play_media) self.action_image.triggered.connect(self.open_image) self.action_video.triggered.connect(self.open_video) self.action_folder.triggered.connect(self.open_folder) self.action_camera.triggered.connect(self.open_camera) self.action_filetree.triggered.connect(self.show_filetree) self.action_setting.triggered.connect(self.show_setting) self.action_autosave.triggered.connect(self.auto_save) self.action_save.triggered.connect(self.save_current) self.action_setting.triggered.connect(self.setting_widget.show) self.file_system_tree.doubleClicked.connect(self.open_image) self.camera.timer.timeout.connect(self.update) self.timer.timeout.connect(self.save_current) def update(self): start_time = time.time() frame = self.camera.frame() self.media_control.update(self.camera.frame_pos, self.camera.frame_count) if frame is None: return None result, keypoints = self.openpose_model(frame) result, keypoints = self.gesture_recognition(result, keypoints) message = self.generate_message(keypoints) self.label_frame.update_frame(result) fps = 1 / (time.time() - start_time) self.status_fps.setText("FPS:{:.1f}".format(fps)) self.status_bar.showMessage(message, 2000) return result, keypoints def gesture_recognition(self, result, keypoints): """实现手势识别""" if self.setting_widget.gesture_on(): hands = keypoints[1] person_num = hands[0].shape[0] for i in range(person_num): for hand in hands: rect = self.gesture_model.hand_bbox(hand[i]) gesture = self.gesture_model(hand[i]) if rect: print(rect) x, y, w, h = rect cv2.rectangle(result, (x, y), (x + w, y + h), (255, 255, 255)) cv2.putText(result, gesture, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255)) return result, keypoints def generate_message(self, keypoints): """获取识别结果信息""" if keypoints[0].size != 1: person_num = keypoints[0].shape[0] message = "person: {}".format(person_num) for i in range(person_num): message += " | person{}(".format(i + 1) if self.setting_widget.body_on(): pose_keypoints = keypoints[0][i, :, 2] pose_detected = pose_keypoints[ pose_keypoints > self.setting_widget.body_threshold()] message += "pose: {:>2d}/{}".format(pose_detected.size, 25) if self.setting_widget.hand_on(): right_hand_keypoinys = keypoints[1][0][i, :, 2] left_hand_keypoinys = keypoints[1][1][i, :, 2] right_hand_detected = right_hand_keypoinys[ right_hand_keypoinys > self.setting_widget.hand_threshold()] left_hand_detected = left_hand_keypoinys[ left_hand_keypoinys > self.setting_widget.hand_threshold()] message += " | right hand: {:>2d}/{}".format( right_hand_detected.size, 21) message += " | left hand: {:>2d}/{}".format( left_hand_detected.size, 21) message += ")" else: message = "person: {}".format(0) return message def save_current(self): if not self.label_frame.pixmap(): QMessageBox.warning(self, "Note", "No data in frame", QMessageBox.Yes) return pixmap = self.label_frame.cvimg2pixmap( self.openpose_model.get_rendered_image()) body_keypoints, hand_keypoints, face_keypoints = self.openpose_model.get_keypoints( ) body_keypoints = copy.deepcopy( body_keypoints) if self.setting_widget.body_on() else None hand_keypoints = copy.deepcopy( hand_keypoints) if self.setting_widget.hand_on() else None face_keypoints = copy.deepcopy( face_keypoints) if self.setting_widget.face_on() else None keypoints = (body_keypoints, hand_keypoints, face_keypoints) if self.timer.isActive(): self.save_widget.save(pixmap.copy(), *keypoints) else: message = self.generate_message(keypoints) self.save_widget.setFrame(pixmap.copy(), *keypoints, message) self.save_widget.show() def auto_save(self): if not self.camera.is_open(): self.action_autosave.setChecked(False) if self.action_autosave.isChecked(): self.timer.start(self.setting_widget.save_interval() * 1000) else: self.timer.stop() def update_setting(self): pass def update_openpose(self, key, value): pass # 槽函数 # 参数 def check_body(self, status): # 姿态估计 flag = True if status == Qt.Checked else False render_pose = 1 if status == Qt.Checked else 0 self.setting_widget.horizontalSlider_Body.setEnabled(flag) self.setting_widget.radioButton_black.setEnabled(flag) self.setting_widget.radioButton_rgb.setEnabled(flag) self.openpose_model.update_wrapper("render_pose", render_pose) def check_hand(self, status): # 手部估计 flag = True if status == Qt.Checked else False self.setting_widget.horizontalSlider_Hand.setEnabled(flag) self.setting_widget.checkBox_gesture.setEnabled(flag) self.openpose_model.update_wrapper("hand", flag) def check_face(self, status): # 脸部估计 flag = True if status == Qt.Checked else False self.setting_widget.horizontalSlider_Face.setEnabled(flag) self.setting_widget.checkBox_emotion.setEnabled(flag) self.openpose_model.update_wrapper("face", flag) def change_body_threshold(self): # 姿态估计阈值 value = self.setting_widget.body_threshold() self.setting_widget.label_threshold_body.setText(str(value * 100)) self.openpose_model.update_wrapper("render_threshold", value) def change_hand_threshold(self): # 手部估计阈值 value = self.setting_widget.hand_threshold() self.setting_widget.label_threshold_hand.setText(str(value * 100)) self.openpose_model.update_wrapper("hand_render_threshold", value) def change_face_threshold(self): # 脸部估计阈值 value = self.setting_widget.face_threshold() self.setting_widget.label_threshold_face.setText(str(value * 100)) self.openpose_model.update_wrapper("face_render_threshold", value) def change_resolution(self): resolution = self.setting_widget.net_resolution() self.openpose_model.update_wrapper("net_resolution", resolution) def change_background(self): # 背景 self.openpose_model.update_wrapper( "disable_blending", self.setting_widget.black_background()) # 功能 def show_setting(self): if self.dock_setting.isHidden(): self.dock_setting.show() else: self.dock_setting.hide() def show_filetree(self): if self.dock_filetree.isHidden(): self.dock_filetree.show() else: self.dock_filetree.hide() def open_image(self, file_index=None): if file_index: file = self.file_system_tree.fileSystemModel.filePath(file_index) else: file, _ = QFileDialog.getOpenFileName( self, '请选择图片', './', 'Image files(*.jpg *.png *.JPG *.PNG)') # 可设置默认路径 if not file or not file.endswith((".jpg", ".png", ".JPG", ".PNG")): return False image = cv2.imread(file) result, keypoints = self.openpose_model(image) message = self.generate_message(keypoints) # self.label_frame.resize(*image.shape[:2]) self.label_frame.update_frame(result) self.status_bar.showMessage(message) def open_video(self): if self.action_video.isChecked(): file, _ = QFileDialog.getOpenFileName( self, '请选择视频', './', 'Video files(*.mp4 *.avi)') # 可设置默认路径 if not file: self.action_video.setChecked(False) return self.camera.start(file) self.label_frame.resize(*self.camera.resolution) self.action_video.setIcon(QIcon('icon/stop.png')) self.update() # 初始化画面 self.camera.is_pause = True self.media_control.pause() self.dock_media.show() else: self.label_frame.clear() self.camera.stop() self.status_fps.setText("FPS:00.0") self.action_video.setIcon(QIcon("icon/video.png")) self.media_control.play() self.dock_media.hide() def open_folder(self): new_foler = QFileDialog.getExistingDirectory(self, '请选择目录', './') # 可设置默认路径 if not new_foler: return self.file_system_tree.alter_dir(new_foler) self.dock_filetree.show() self.status_bar.showMessage("current folder: {}".format(new_foler), 3000) def open_camera(self): if self.action_camera.isChecked(): self.camera.start() self.action_camera.setIcon(QIcon('icon/stop.png')) else: self.label_frame.clear() self.camera.stop() self.status_fps.setText("FPS:00.0") self.action_camera.setIcon(QIcon("icon/camera.png")) def play_media(self): if not self.media_control.is_play(): self.media_control.pause() self.camera.is_pause = True else: self.media_control.play() self.camera.is_pause = False
def __init__(self, ClassObject): super(QMainWindow, self).__init__() w = ClassObject() w.app_main_window = self self._widget = w if len(w.mainmenu) > 0: w._mainmenu = self.__initMainMenu(w.mainmenu) w.init_form() if conf.PYFORMS_USE_QT5: self.layout().setContentsMargins(conf.PYFORMS_MAINWINDOW_MARGIN, conf.PYFORMS_MAINWINDOW_MARGIN, conf.PYFORMS_MAINWINDOW_MARGIN, conf.PYFORMS_MAINWINDOW_MARGIN) else: self.layout().setMargin(conf.PYFORMS_MAINWINDOW_MARGIN) self.setCentralWidget(w) self.setWindowTitle(w.title) docks = {} for name, item in w.controls.items(): if isinstance(item, ControlDockWidget): if item.side not in docks: docks[item.side] = [] docks[item.side].append((name, item)) for key, widgets in docks.items(): side = QtCore.Qt.RightDockWidgetArea if key == 'left': side = QtCore.Qt.LeftDockWidgetArea elif key == 'right': side = QtCore.Qt.RightDockWidgetArea elif key == 'top': side = QtCore.Qt.TopDockWidgetArea elif key == 'bottom': side = QtCore.Qt.BottomDockWidgetArea else: side = QtCore.Qt.LeftDockWidgetArea if isinstance(widgets, list): widgets = sorted(widgets, key=lambda x: x[1].order) for name, widget in widgets: dock = QDockWidget(self) dock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable) dock.setObjectName(name) if conf.PYFORMS_USE_QT5: dock.setContentsMargins(0, 0, 0, 0) widget.form.layout().setContentsMargins( widget.margin, widget.margin, widget.margin, widget.margin) else: dock.setMargin(0) widget.form.layout().setMargin(widget.margin) # print dock.objectName(),1 dock.setWidget(widget.form) dock.setWindowTitle(widget.label) widget.dock = dock if not widget._show: dock.hide() self.addDockWidget(side, dock) else: dock = QDockWidget(self) dock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable | QDockWidget.DockWidgetMovable) # dock.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea) if conf.PYFORMS_USE_QT5: widget.form.layout().setContentsMargins( widget.margin, widget.margin, widget.margin, widget.margin) else: widget.form.layout().setMargin(widget.margin) # print dock.objectName(), 2 dock.setObjectName(name) dock.setWidget(widget.form) self.addDockWidget(side, dock) dock.setWindowTitle(widget.label) widget.dock = dock if not widget._show: dock.hide() if conf.PYFORMS_STYLESHEET: stylesheet_files = [conf.PYFORMS_STYLESHEET] p = platform.system() if p == 'Windows' and conf.PYFORMS_STYLESHEET_WINDOWS: stylesheet_files.append(conf.PYFORMS_STYLESHEET_WINDOWS) elif p == 'Darwin' and conf.PYFORMS_STYLESHEET_DARWIN: stylesheet_files.append(conf.PYFORMS_STYLESHEET_DARWIN) elif p == 'Linux' and conf.PYFORMS_STYLESHEET_LINUX: stylesheet_files.append(conf.PYFORMS_STYLESHEET_LINUX) logger.debug('Import stylesheets: {0}'.format(stylesheet_files)) self.loadStyleSheetFile(stylesheet_files)
class _QtDock(_AbstractDock): def _dock_initialize(self): self.dock = QDockWidget() self.scroll = QScrollArea(self.dock) self.dock.setWidget(self.scroll) widget = QWidget(self.scroll) self.scroll.setWidget(widget) self.scroll.setWidgetResizable(True) self.dock.setAllowedAreas(Qt.LeftDockWidgetArea) self.dock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.plotter.app_window.addDockWidget(Qt.LeftDockWidgetArea, self.dock) self.dock_layout = QVBoxLayout() widget.setLayout(self.dock_layout) def _dock_finalize(self): self.dock.setMinimumSize(self.dock.sizeHint().width(), 0) self._dock_add_stretch(self.dock_layout) def _dock_show(self): self.dock.show() def _dock_hide(self): self.dock.hide() def _dock_add_stretch(self, layout): layout.addStretch() def _dock_add_layout(self, vertical=True): layout = QVBoxLayout() if vertical else QHBoxLayout() return layout def _dock_add_label(self, value, align=False, layout=None): layout = self.dock_layout if layout is None else layout widget = QLabel() if align: widget.setAlignment(Qt.AlignCenter) widget.setText(value) layout.addWidget(widget) return widget def _dock_add_button(self, name, callback, layout=None): layout = self.dock_layout if layout is None else layout widget = QPushButton(name) widget.released.connect(callback) layout.addWidget(widget) return widget def _dock_add_text(self, value, callback, validator=None, layout=None): layout = self.dock_layout if layout is None else layout widget = QLineEdit(value) widget.setAlignment(Qt.AlignCenter) if validator is not None: widget.setValidator(QDoubleValidator(validator[0], validator[1], 2)) def _callback(): callback(float(widget.text())) else: def _callback(): callback(widget.text()) widget.returnPressed.connect(_callback) layout.addWidget(widget) return widget def _dock_add_slider(self, name, value, rng, callback, compact=True, double=False, layout=None): layout = self.dock_layout if layout is None else layout hlayout = self._dock_add_layout(not compact) if name is not None: self._dock_add_label(value=name, align=not compact, layout=hlayout) slider_class = QFloatSlider if double else QSlider widget = slider_class(Qt.Horizontal) widget.setMinimum(rng[0] if double else int(rng[0])) widget.setMaximum(rng[1] if double else int(rng[1])) widget.setValue(value if double else int(value)) widget.valueChanged.connect(callback) hlayout.addWidget(widget) layout.addLayout(hlayout) return widget def _dock_add_spin_box(self, name, value, rng, callback, compact=True, double=True, layout=None): layout = self.dock_layout if layout is None else layout hlayout = self._dock_add_layout(not compact) if name is not None: self._dock_add_label(value=name, align=not compact, layout=hlayout) value = value if double else int(value) widget = QDoubleSpinBox() if double else QSpinBox() widget.setAlignment(Qt.AlignCenter) widget.setMinimum(rng[0]) widget.setMaximum(rng[1]) widget.setValue(value) widget.valueChanged.connect(callback) hlayout.addWidget(widget) layout.addLayout(hlayout) return widget def _dock_add_combo_box(self, name, value, rng, callback, compact=True, layout=None): layout = self.dock_layout if layout is None else layout hlayout = self._dock_add_layout(not compact) if name is not None: self._dock_add_label(value=name, align=not compact, layout=hlayout) widget = QComboBox() widget.addItems(rng) widget.setCurrentText(value) widget.currentTextChanged.connect(callback) hlayout.addWidget(widget) layout.addLayout(hlayout) return widget def _dock_add_group_box(self, name, layout=None): layout = self.dock_layout if layout is None else layout hlayout = QVBoxLayout() widget = QGroupBox(name) widget.setLayout(hlayout) layout.addWidget(widget) return hlayout