class ResultWindow(QMainWindow): def __init__(self, parent, app, **kwargs): super().__init__(parent, **kwargs) self.app = app self._setupUi() self.resultsModel = app.RESULT_MODEL_CLASS(self.app, self.resultsView) self.stats = StatsLabel(app.model.stats_label, self.statusLabel) self._update_column_actions_status() self.menuColumns.triggered.connect(self.columnToggled) self.resultsView.doubleClicked.connect(self.resultsDoubleClicked) self.resultsView.spacePressed.connect(self.resultsSpacePressed) self.detailsButton.clicked.connect(self.actionDetails.triggered) self.dupesOnlyCheckBox.stateChanged.connect(self.powerMarkerTriggered) self.deltaValuesCheckBox.stateChanged.connect(self.deltaTriggered) self.searchEdit.searchChanged.connect(self.searchChanged) self.app.willSavePrefs.connect(self.appWillSavePrefs) def _setupActions(self): # (name, shortcut, icon, desc, func) ACTIONS = [ ('actionDetails', 'Ctrl+I', '', tr("Details"), self.detailsTriggered), ('actionActions', '', '', tr("Actions"), self.actionsTriggered), ('actionPowerMarker', 'Ctrl+1', '', tr("Show Dupes Only"), self.powerMarkerTriggered), ('actionDelta', 'Ctrl+2', '', tr("Show Delta Values"), self.deltaTriggered), ('actionDeleteMarked', 'Ctrl+D', '', tr("Send Marked to Recycle Bin..."), self.deleteTriggered), ('actionMoveMarked', 'Ctrl+M', '', tr("Move Marked to..."), self.moveTriggered), ('actionCopyMarked', 'Ctrl+Shift+M', '', tr("Copy Marked to..."), self.copyTriggered), ('actionRemoveMarked', 'Ctrl+R', '', tr("Remove Marked from Results"), self.removeMarkedTriggered), ('actionReprioritize', '', '', tr("Re-Prioritize Results..."), self.reprioritizeTriggered), ('actionRemoveSelected', 'Ctrl+Del', '', tr("Remove Selected from Results"), self.removeSelectedTriggered), ('actionIgnoreSelected', 'Ctrl+Shift+Del', '', tr("Add Selected to Ignore List"), self.addToIgnoreListTriggered), ('actionMakeSelectedReference', 'Ctrl+Space', '', tr("Make Selected into Reference"), self.app.model.make_selected_reference), ('actionOpenSelected', 'Ctrl+O', '', tr("Open Selected with Default Application"), self.openTriggered), ('actionRevealSelected', 'Ctrl+Shift+O', '', tr("Open Containing Folder of Selected"), self.revealTriggered), ('actionRenameSelected', 'F2', '', tr("Rename Selected"), self.renameTriggered), ('actionMarkAll', 'Ctrl+A', '', tr("Mark All"), self.markAllTriggered), ('actionMarkNone', 'Ctrl+Shift+A', '', tr("Mark None"), self.markNoneTriggered), ('actionInvertMarking', 'Ctrl+Alt+A', '', tr("Invert Marking"), self.markInvertTriggered), ('actionMarkSelected', '', '', tr("Mark Selected"), self.markSelectedTriggered), ('actionExportToHTML', '', '', tr("Export To HTML"), self.app.model.export_to_xhtml), ('actionExportToCSV', '', '', tr("Export To CSV"), self.app.model.export_to_csv), ('actionSaveResults', 'Ctrl+S', '', tr("Save Results..."), self.saveResultsTriggered), ('actionInvokeCustomCommand', 'Ctrl+Alt+I', '', tr("Invoke Custom Command"), self.app.invokeCustomCommand), ] createActions(ACTIONS, self) self.actionDelta.setCheckable(True) self.actionPowerMarker.setCheckable(True) def _setupMenu(self): self.menubar = QMenuBar() self.menubar.setGeometry(QRect(0, 0, 630, 22)) self.menuFile = QMenu(self.menubar) self.menuFile.setTitle(tr("File")) self.menuMark = QMenu(self.menubar) self.menuMark.setTitle(tr("Mark")) self.menuActions = QMenu(self.menubar) self.menuActions.setTitle(tr("Actions")) self.menuColumns = QMenu(self.menubar) self.menuColumns.setTitle(tr("Columns")) self.menuView = QMenu(self.menubar) self.menuView.setTitle(tr("View")) self.menuHelp = QMenu(self.menubar) self.menuHelp.setTitle(tr("Help")) self.setMenuBar(self.menubar) self.menuActions.addAction(self.actionDeleteMarked) self.menuActions.addAction(self.actionMoveMarked) self.menuActions.addAction(self.actionCopyMarked) self.menuActions.addAction(self.actionRemoveMarked) self.menuActions.addAction(self.actionReprioritize) self.menuActions.addSeparator() self.menuActions.addAction(self.actionRemoveSelected) self.menuActions.addAction(self.actionIgnoreSelected) self.menuActions.addAction(self.actionMakeSelectedReference) self.menuActions.addSeparator() self.menuActions.addAction(self.actionOpenSelected) self.menuActions.addAction(self.actionRevealSelected) self.menuActions.addAction(self.actionInvokeCustomCommand) self.menuActions.addAction(self.actionRenameSelected) self.menuMark.addAction(self.actionMarkAll) self.menuMark.addAction(self.actionMarkNone) self.menuMark.addAction(self.actionInvertMarking) self.menuMark.addAction(self.actionMarkSelected) self.menuView.addAction(self.actionPowerMarker) self.menuView.addAction(self.actionDelta) self.menuView.addSeparator() self.menuView.addAction(self.actionDetails) self.menuView.addAction(self.app.actionIgnoreList) self.menuView.addAction(self.app.actionPreferences) self.menuHelp.addAction(self.app.actionShowHelp) self.menuHelp.addAction(self.app.actionOpenDebugLog) self.menuHelp.addAction(self.app.actionAbout) self.menuFile.addAction(self.actionSaveResults) self.menuFile.addAction(self.actionExportToHTML) self.menuFile.addAction(self.actionExportToCSV) self.menuFile.addSeparator() self.menuFile.addAction(self.app.actionQuit) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuMark.menuAction()) self.menubar.addAction(self.menuActions.menuAction()) self.menubar.addAction(self.menuColumns.menuAction()) self.menubar.addAction(self.menuView.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) # Columns menu menu = self.menuColumns self._column_actions = [] for index, (display, visible) in enumerate(self.app.model.result_table.columns.menu_items()): action = menu.addAction(display) action.setCheckable(True) action.setChecked(visible) action.item_index = index self._column_actions.append(action) menu.addSeparator() action = menu.addAction(tr("Reset to Defaults")) action.item_index = -1 # Action menu actionMenu = QMenu(tr("Actions"), self.menubar) actionMenu.addAction(self.actionDeleteMarked) actionMenu.addAction(self.actionMoveMarked) actionMenu.addAction(self.actionCopyMarked) actionMenu.addAction(self.actionRemoveMarked) actionMenu.addSeparator() actionMenu.addAction(self.actionRemoveSelected) actionMenu.addAction(self.actionIgnoreSelected) actionMenu.addAction(self.actionMakeSelectedReference) actionMenu.addSeparator() actionMenu.addAction(self.actionOpenSelected) actionMenu.addAction(self.actionRevealSelected) actionMenu.addAction(self.actionInvokeCustomCommand) actionMenu.addAction(self.actionRenameSelected) self.actionActions.setMenu(actionMenu) self.actionsButton.setMenu(self.actionActions.menu()) def _setupUi(self): self.setWindowTitle(tr("{} Results").format(self.app.NAME)) self.resize(630, 514) self.centralwidget = QWidget(self) self.verticalLayout = QVBoxLayout(self.centralwidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setSpacing(0) self.actionsButton = QPushButton(tr("Actions")) self.detailsButton = QPushButton(tr("Details")) self.dupesOnlyCheckBox = QCheckBox(tr("Dupes Only")) self.deltaValuesCheckBox = QCheckBox(tr("Delta Values")) self.searchEdit = SearchEdit() self.searchEdit.setMaximumWidth(300) self.horizontalLayout = horizontalWrap([self.actionsButton, self.detailsButton, self.dupesOnlyCheckBox, self.deltaValuesCheckBox, None, self.searchEdit, 8]) self.horizontalLayout.setSpacing(8) self.verticalLayout.addLayout(self.horizontalLayout) self.resultsView = ResultsView(self.centralwidget) self.resultsView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.resultsView.setSelectionBehavior(QAbstractItemView.SelectRows) self.resultsView.setSortingEnabled(True) self.resultsView.verticalHeader().setVisible(False) h = self.resultsView.horizontalHeader() h.setHighlightSections(False) h.setSectionsMovable(True) h.setStretchLastSection(False) h.setDefaultAlignment(Qt.AlignLeft) self.verticalLayout.addWidget(self.resultsView) self.setCentralWidget(self.centralwidget) self._setupActions() self._setupMenu() self.statusbar = QStatusBar(self) self.statusbar.setSizeGripEnabled(True) self.setStatusBar(self.statusbar) self.statusLabel = QLabel(self) self.statusbar.addPermanentWidget(self.statusLabel, 1) if self.app.prefs.resultWindowIsMaximized: self.setWindowState(self.windowState() | Qt.WindowMaximized) else: if self.app.prefs.resultWindowRect is not None: self.setGeometry(self.app.prefs.resultWindowRect) else: moveToScreenCenter(self) #--- Private def _update_column_actions_status(self): # Update menu checked state menu_items = self.app.model.result_table.columns.menu_items() for action, (display, visible) in zip(self._column_actions, menu_items): action.setChecked(visible) #--- Actions def actionsTriggered(self): self.actionsButton.showMenu() def addToIgnoreListTriggered(self): self.app.model.add_selected_to_ignore_list() def copyTriggered(self): self.app.model.copy_or_move_marked(True) def deleteTriggered(self): self.app.model.delete_marked() def deltaTriggered(self, state=None): # The sender can be either the action or the checkbox, but both have a isChecked() method. self.resultsModel.delta_values = self.sender().isChecked() self.actionDelta.setChecked(self.resultsModel.delta_values) self.deltaValuesCheckBox.setChecked(self.resultsModel.delta_values) def detailsTriggered(self): self.app.show_details() def markAllTriggered(self): self.app.model.mark_all() def markInvertTriggered(self): self.app.model.mark_invert() def markNoneTriggered(self): self.app.model.mark_none() def markSelectedTriggered(self): self.app.model.toggle_selected_mark_state() def moveTriggered(self): self.app.model.copy_or_move_marked(False) def openTriggered(self): self.app.model.open_selected() def powerMarkerTriggered(self, state=None): # see deltaTriggered self.resultsModel.power_marker = self.sender().isChecked() self.actionPowerMarker.setChecked(self.resultsModel.power_marker) self.dupesOnlyCheckBox.setChecked(self.resultsModel.power_marker) def preferencesTriggered(self): self.app.show_preferences() def removeMarkedTriggered(self): self.app.model.remove_marked() def removeSelectedTriggered(self): self.app.model.remove_selected() def renameTriggered(self): index = self.resultsView.selectionModel().currentIndex() # Our index is the current row, with column set to 0. Our filename column is 1 and that's # what we want. index = index.sibling(index.row(), 1) self.resultsView.edit(index) def reprioritizeTriggered(self): dlg = PrioritizeDialog(self, self.app) result = dlg.exec() if result == QDialog.Accepted: dlg.model.perform_reprioritization() def revealTriggered(self): self.app.model.reveal_selected() def saveResultsTriggered(self): title = tr("Select a file to save your results to") files = tr("dupeGuru Results (*.dupeguru)") destination, chosen_filter = QFileDialog.getSaveFileName(self, title, '', files) if destination: if not destination.endswith('.dupeguru'): destination = '{}.dupeguru'.format(destination) self.app.model.save_as(destination) self.app.recentResults.insertItem(destination) #--- Events def appWillSavePrefs(self): prefs = self.app.prefs prefs.resultWindowIsMaximized = self.isMaximized() prefs.resultWindowRect = self.geometry() def columnToggled(self, action): index = action.item_index if index == -1: self.app.model.result_table.columns.reset_to_defaults() self._update_column_actions_status() else: visible = self.app.model.result_table.columns.toggle_menu_item(index) action.setChecked(visible) def contextMenuEvent(self, event): self.actionActions.menu().exec_(event.globalPos()) def resultsDoubleClicked(self, modelIndex): self.app.model.open_selected() def resultsSpacePressed(self): self.app.model.toggle_selected_mark_state() def searchChanged(self): self.app.model.apply_filter(self.searchEdit.text())
class Window(QMainWindow): def __init__(self, x=DEFAULT_X, y=DEFAULT_Y, w=DEFAULT_WIDTH, h=DEFAULT_HEIGHT): super(Window, self).__init__() self.setGeometry(x, y, w, h) self.setWindowTitle(WINDOW_NAME) self.setWindowIcon(QIcon(MAIN_ICON)) self.home() def home(self): self.folderLoader = FolderLoader() self.saved = True #Parameters self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.createMainMenu() self.canvas = Canvas(parent=self) self.scrollArea = QScrollArea() self.scrollArea.setWidget(self.canvas) self.scrollArea.setWidgetResizable(True) self.scrollArea.setStyleSheet(STYLE_SHEET) self.labelCoordinates = QLabel('') self.statusBar.addPermanentWidget(self.labelCoordinates) self.toolbar = QToolBar(TOOLBAR_NAME, self) self.toolbar.setStyleSheet(STYLE_SHEET) self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.addToolBar(Qt.LeftToolBarArea, self.toolbar) self.mapper = QSignalMapper() self.createColorComboBox() self.createToolbarActions() self.createFileDock() self.setCentralWidget(self.scrollArea) self.update() self.showMaximized() def createMainMenu(self): #Main Menu mainMenu = self.menuBar() fileMenu = mainMenu.addMenu(FILE_MENU_TEXT) editMenu = mainMenu.addMenu(EDIT_MENU_TEXT) helpMenu = mainMenu.addMenu(HELP_MENU_TEXT) #File Menu Actions openFileAction = self.createAction(OPEN_FILE_TEXT, OPEN_FILE_SHORTCUT, self.openFile) openFolderAction = self.createAction(OPEN_FOLDER_TEXT, OPEN_FOLDER_SHORTCUT, self.openFolder) saveAction = self.createAction(SAVE_TEXT, SAVE_SHORTCUT, self.save) fileMenu.addActions([openFileAction, openFolderAction, saveAction]) #Edit Menu Actions copyAction = self.createAction(COPY_TEXT, COPY_SHORTCUT, self.copy) pasteAction = self.createAction(PASTE_TEXT, PASTE_SHORTCUT, self.paste) editMenu.addActions([copyAction, pasteAction]) #Help Menu Actions howToUseAction = self.createAction(HOW_TO_USE_TEXT, EMPTY, self.howToUse) helpMenu.addActions([howToUseAction]) def createToolbarActions(self): self.toolbar.addSeparator() #Polygons drawPolygonAction = self.createActionWithIcon(DRAW_POLYGON_ICON, DRAW_POLYGON_TEXT, DRAW_POLYGON_SHORTCUT, self.setDrawingState, DRAW_POLYGON_TOOLTIP) deletePolygonAction = self.createActionWithIcon( DELETE_POLYGON_ICON, DELETE_POLYGON_TEXT, DELETE_POLYGON_SHORTCUT, self.canvas.deletePolygon, DELETE_POLYGON_TOOLTIP) self.toolbar.addActions([drawPolygonAction, deletePolygonAction]) self.toolbar.addSeparator() ##Controls addControlAction = self.createActionWithIcon( ADD_CONTROL_ICON, ADD_CONTROL_TEXT, ADD_CONTROL_SHORTCUT, self.canvas.addControlToSelectedPolygon, ADD_CONTROL_TOOLTIP) deleteControlAction = self.createActionWithIcon( DELETE_CONTROL_ICON, DELETE_CONTROL_TEXT, DELETE_CONTROL_SHORTCUT, self.canvas.deleteControlFromSelectedPolygon, DELETE_CONTROL_TOOLTIP) self.toolbar.addActions([addControlAction, deleteControlAction]) self.toolbar.addSeparator() nextImageAction = self.createActionWithIcon(NEXT_IMAGE_ICON, NEXT_IMAGE_TEXT, NEXT_IMAGE_SHORTCUT, self.nextImage, NEXT_IMAGE_TOOLTIP) previousImageAction = self.createActionWithIcon( PREVIOUS_IMAGE_ICON, PREVIOUS_IMAGE_TEXT, PREVIOUS_IMAGE_SHORTCUT, self.previousImage, PREVIOUS_IMAGE_TOOLTIP) self.toolbar.addActions([nextImageAction, previousImageAction]) self.copyPolygonsCheckbox = QCheckBox() self.copyPolygonsCheckbox.setStyleSheet(STYLE_SHEET) self.toolbar.addWidget(self.copyPolygonsCheckbox) copyPolygonsLabel = QLabel(COPY_POLGONS_FOR_NEXT_IMAGE) copyPolygonsLabel.setAlignment(Qt.AlignCenter) self.toolbar.addWidget(copyPolygonsLabel) self.hideControlsCheckBox = QCheckBox() self.hideControlsCheckBox.setStyleSheet(STYLE_SHEET) self.hideControlsCheckBox.stateChanged.connect( self.canvas.changeHideControlsState) self.toolbar.addWidget(self.hideControlsCheckBox) hideControlsLabel = QLabel(HIDE_CONTROLS_TEXT) hideControlsLabel.setAlignment(Qt.AlignCenter) self.toolbar.addWidget(hideControlsLabel) def createColorComboBox(self): colorLabel = QLabel("Polygon Color") colorLabel.setAlignment(Qt.AlignCenter) self.toolbar.addWidget(colorLabel) self.colorComboBox = QComboBox() self.colorComboBox.setStyleSheet(STYLE_SHEET) self.colorComboBox.activated[int].connect(self.changeColor) self.toolbar.addWidget(self.colorComboBox) model = self.colorComboBox.model() for i in range(len(POLY_COLORS_TEXT)): colorText = POLY_COLORS_TEXT[i] colorStyle = POLY_COLORS_STYLE[i] item = QStandardItem(colorText) item.setBackground(QColor(colorStyle)) item.setData(colorStyle) model.appendRow(item) self.customColor = self.createActionWithIcon(CUSTOM_COLOR_ICON, CUSTOM_COLOR_TEXT, EMPTY, self.addCustomColor, CUSTOM_COLOR_TOOLTIP) self.toolbar.addAction(self.customColor) self.changeColor = self.createActionWithIcon( CHANGE_COLOR_ICON, CHANGE_COLOR_TEXT, EMPTY, self.canvas.askForColorChange, CHANGE_COLOR_TOOLTIP) self.toolbar.addAction(self.changeColor) def createFileDock(self): self.fileDock = QDockWidget(FILE_DOCK_TITLE, self) self.fileListWidget = QListWidget() self.fileListWidget.setStyleSheet(STYLE_SHEET) self.fileListWidget.itemDoubleClicked.connect(self.fileItemChanged) fileListLayout = QVBoxLayout() fileListLayout.addWidget(self.fileListWidget) fileListContainter = QWidget() fileListContainter.setLayout(fileListLayout) self.fileDock.setWidget(fileListContainter) self.fileDock.setStyleSheet(STYLE_SHEET) self.fileDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.addDockWidget(Qt.RightDockWidgetArea, self.fileDock) def createAction(self, text, shortcut, triggered=None): action = QAction(text, self) action.setShortcut(shortcut) action.setToolTip(EMPTY) action.triggered.connect(triggered) return action def createActionWithIcon(self, iconPath, text, shortcut, triggered, tooltip=""): action = QAction(QIcon(iconPath), text, self) action.triggered.connect(triggered) action.setToolTip(tooltip) action.setShortcut(shortcut) return action def freeDrawCheckBoxChanged(self): if (self.freeDrawCheckbox.checkState() > 0): self.canvas.setState(FREE_DRAW) else: self.canvas.setState(MOVE_CONTROLS) def fileItemChanged(self): filepath = self.fileListWidget.selectedItems()[0].text() self.canvas.loadImage(filepath) def nextImage(self): if (self.checkContinue()): image = self.folderLoader.getNextImageFilename() if (image is not None): copyPolygons = self.copyPolygonsCheckbox.checkState() > 0 self.canvas.loadImage(image, copyPolygons) self.saved = True fileWidgetItem = self.fileListWidget.item( self.folderLoader.index) if (fileWidgetItem is not None): fileWidgetItem.setSelected(True) def previousImage(self): if (self.checkContinue()): image = self.folderLoader.getPreviousImageFilename() if (image is not None): self.canvas.loadImage(image) self.saved = True fileWidgetItem = self.fileListWidget.item( self.folderLoader.index) if (fileWidgetItem is not None): fileWidgetItem.setSelected(True) def checkContinue(self): if (not self.saved): choice = QMessageBox.question(self, NOT_SAVED_TITLE, NOT_SAVED_TEXT) if (choice == QMessageBox.Yes): return True else: return False else: return True def addColoredPolygon(self, color): self.canvas.addPolygon(color) self.saved = False def addCustomColor(self): color = QColorDialog.getColor() if (QColor.isValid(color)): self.canvas.setColor(color) self.saved = False def calculateCenter(self): self.centerX = self.rect().width() // 2 self.centerY = self.rect().height() // 2 self.center = QPoint(self.centerX, self.centerY) def resizeEvent(self, event): self.calculateCenter() self.canvas.resizedParent() self.canvas.adjustSize() def keyPressEvent(self, event): if (event.key() == Qt.Key_Escape): self.canvas.setState(MOVE_CONTROLS) else: for number in NUMBERS: if (event.text() == number): self.colorComboBox.setCurrentIndex(int(number) - 1) self.colorComboBox.activated.emit(int(number) - 1) def openFile(self): filename, _ = QFileDialog.getOpenFileName(self, OPEN_FILE_DIALOG_TEXT, EMPTY, OPEN_FILE_DIALOG_FILTER) if any(x in filename for x in OPEN_FOLDER_FILTERS): self.folderLoader.loadSingleFile(filename) self.canvas.loadImage(filename) def openFolder(self): folder = QFileDialog.getExistingDirectory(self, OPEN_FOLDER_DIALOG_TEXT) if (folder is not EMPTY): firstImage = self.folderLoader.loadFolder(folder) self.canvas.loadImage(firstImage) for imagePath in self.folderLoader.imagesInFolder: self.fileListWidget.addItem(QListWidgetItem(imagePath)) def save(self): self.saved = True self.canvas.saveImage() def setDrawingState(self): self.canvas.setState(DRAW_POLYGON) def changeColor(self, index): color = QColor(POLY_COLORS_STYLE[index]) self.colorComboBox.setStyleSheet( f'background-color: {POLY_COLORS_STYLE[index]}') self.canvas.setColor(color) def howToUse(self): webbrowser.open(HELP_PAGE_WEBSITE) def copy(self): self.canvas.copyPolygon() def paste(self): self.canvas.pastePolygon()
class Form(QMainWindow): update_form = pyqtSignal() def __init__(self, parent=None): super(Form, self).__init__(parent) self.db_interface = DB_Interface() self.db_interface.new_tracking_item.connect(self.update_tracking) fibre_saturation_Label = QLabel("Fiber Saturation Ratio (%) (from tables)") self.fibre_saturation_spinbox = QDoubleSpinBox() self.fibre_saturation_spinbox.setDecimals(1) self.fibre_saturation_spinbox.setRange(0, 100) self.fibre_saturation_spinbox.setSingleStep(0.1) self.fibre_saturation_spinbox.setValue(18) #self.fibre_saturation_spinbox.valueChanged.connect(self.control.update_EMC_fast_target) temperature_Label = QLabel("Current temperature measurement") #self.temperature_value_label = QLabel("{0}".format(self.control.temperature)) humidity_Label = QLabel("Current humidity measurement") #self.humidity_value_label = QLabel("{0}".format(self.control.humidity)) final_saturation_Label = QLabel("Target wood saturation Ratio (%)") self.final_saturation_spinbox = QDoubleSpinBox() self.final_saturation_spinbox.setDecimals(1) self.final_saturation_spinbox.setRange(0, 100) self.final_saturation_spinbox.setSingleStep(0.1) self.final_saturation_spinbox.setValue(6) #self.final_saturation_spinbox.valueChanged.connect(self.control.update_EMC_slow_target) emc_Label = QLabel("Equilibrium Moisture Content") #self.emc_value_label = QLabel("{0}".format(self.control.equilibrium_moisture_content)) self.temp_deque_len_label = QLabel() #self.temp_deque_len_label.setNum(len(self.control.temp_deque1)) self.dummy_label = QLabel() #self.dummy_label.setNum(self.control.state) mainLayout = QGridLayout() mainLayout.addWidget(fibre_saturation_Label, 0 , 0) mainLayout.addWidget(self.fibre_saturation_spinbox, 1 , 0) mainLayout.addWidget(temperature_Label, 2 , 0) #mainLayout.addWidget(self.temperature_value_label, 3 , 0) mainLayout.addWidget(humidity_Label, 4 , 0) #mainLayout.addWidget(self.humidity_value_label, 5 , 0) mainLayout.addWidget(final_saturation_Label, 0 , 1) mainLayout.addWidget(self.final_saturation_spinbox, 1 , 1) mainLayout.addWidget(emc_Label, 2 , 1) #mainLayout.addWidget(self.emc_value_label, 3 , 1) mainLayout.addWidget(self.temp_deque_len_label, 4 , 1) mainLayout.addWidget(self.dummy_label, 5 , 1) self.fire_icon = QPixmap("burn.png") self.red_icon = QPixmap("circle_red.png") self.green_icon = QPixmap("circle_green.png") self.fire_label1 = QLabel() self.fire_label2 = QLabel() self.fire_label1.setPixmap(self.fire_icon) self.fire_label2.setPixmap(self.fire_icon) self.water_icon = QPixmap("water.png") self.water_label = QLabel() self.water_label.setPixmap(self.water_icon) self.statusBar = QStatusBar() self.statusBar.addPermanentWidget(self.fire_label1) self.statusBar.addPermanentWidget(self.fire_label2) self.statusBar.addPermanentWidget(self.water_label) #self.statusBar.showMessage("{0} - {1} - {2}".format(self.control.state,self.control.states_list[self.control.state],len(self.control.temp_deque1))) centralWidget = QWidget() centralWidget.setLayout(mainLayout) self.setCentralWidget(centralWidget) self.setWindowTitle("Humidity Control V1.0") self.setStatusBar(self.statusBar) #self.control.compressor.updated.emit() #self.control.heater.updated.emit() def update_tracking(self): # Update tracking view because the tracking data valueChanged return '''
class AppWindow(QMainWindow): onRestart = pyqtSignal(name='onRestart') onSystemUIElementCreated = pyqtSignal(str, QWidget, name='onSystemUIElementCreated') onSystemUIElementRemoved = pyqtSignal(str, name='onSystemUIElementRemoved') def __init__(self, dwarf_args, flags=None): super(AppWindow, self).__init__(flags) self.dwarf_args = dwarf_args self.session_manager = SessionManager(self) self.session_manager.sessionCreated.connect(self.session_created) self.session_manager.sessionStopped.connect(self.session_stopped) self.session_manager.sessionClosed.connect(self.session_closed) self._tab_order = [ 'debug', 'modules', 'ranges', 'jvm-inspector', 'jvm-debugger' ] self._is_newer_dwarf = False self.q_settings = QSettings(utils.home_path() + "dwarf_window_pos.ini", QSettings.IniFormat) self.menu = self.menuBar() self.view_menu = None self._initialize_ui_elements() self.setWindowTitle( 'Dwarf - A debugger for reverse engineers, crackers and security analyst' ) # load external assets _app = QApplication.instance() # themes self.prefs = Prefs() utils.set_theme(self.prefs.get('dwarf_ui_theme', 'black'), self.prefs) # load font if os.path.exists(utils.resource_path('assets/Anton.ttf')): QFontDatabase.addApplicationFont( utils.resource_path('assets/Anton.ttf')) else: QFontDatabase.addApplicationFont(':/assets/Anton.ttf') if os.path.exists(utils.resource_path('assets/OpenSans-Regular.ttf')): QFontDatabase.addApplicationFont( utils.resource_path('assets/OpenSans-Regular.ttf')) else: QFontDatabase.addApplicationFont(':/assets/OpenSans-Regular.ttf') if os.path.exists(utils.resource_path('assets/OpenSans-Bold.ttf')): QFontDatabase.addApplicationFont( utils.resource_path('assets/OpenSans-Bold.ttf')) else: QFontDatabase.addApplicationFont(':/assets/OpenSans-Bold.ttf') font = QFont("OpenSans", 9, QFont.Normal) # TODO: add settingsdlg font_size = self.prefs.get('dwarf_ui_font_size', 12) font.setPixelSize(font_size) _app.setFont(font) # mainwindow statusbar self.progressbar = QProgressBar() self.progressbar.setRange(0, 0) self.progressbar.setVisible(False) self.progressbar.setFixedHeight(15) self.progressbar.setFixedWidth(100) self.progressbar.setTextVisible(False) self.progressbar.setValue(30) self.statusbar = QStatusBar(self) self.statusbar.setAutoFillBackground(False) self.statusbar.addPermanentWidget(self.progressbar) self.statusbar.setObjectName("statusbar") self.setStatusBar(self.statusbar) self.main_tabs = QTabWidget(self) self.main_tabs.setMovable(False) self.main_tabs.setTabsClosable(True) self.main_tabs.setAutoFillBackground(True) self.main_tabs.tabCloseRequested.connect(self._on_close_tab) self.setCentralWidget(self.main_tabs) # pluginmanager self.plugin_manager = PluginManager(self) self.plugin_manager.reload_plugins() if dwarf_args.any == '': self.welcome_window = WelcomeDialog(self) self.welcome_window.setModal(True) self.welcome_window.onIsNewerVersion.connect( self._enable_update_menu) self.welcome_window.onUpdateComplete.connect( self._on_dwarf_updated) self.welcome_window.setWindowTitle( 'Welcome to Dwarf - A debugger for reverse engineers, crackers and security analyst' ) self.welcome_window.onSessionSelected.connect(self._start_session) # wait for welcome screen self.hide() self.welcome_window.show() else: print('* Starting new Session') self._start_session(dwarf_args.target) def _initialize_ui_elements(self): # dockwidgets self.watchpoints_dwidget = None self.breakpoint_dwiget = None self.bookmarks_dwiget = None self.registers_dock = None self.console_dock = None self.backtrace_dock = None self.threads_dock = None # panels self.asm_panel = None self.backtrace_panel = None self.bookmarks_panel = None self.console_panel = None self.context_panel = None self.debug_panel = None self.contexts_list_panel = None self.data_panel = None self.ftrace_panel = None self.breakpoints_panel = None self.objc_inspector_panel = None self.java_inspector_panel = None self.java_explorer_panel = None self.java_trace_panel = None self.modules_panel = None self.ranges_panel = None self.search_panel = None self.smali_panel = None self.watchpoints_panel = None self.welcome_window = None self._ui_elems = [] def _setup_main_menu(self): self.menu = self.menuBar() dwarf_menu = QMenu('Dwarf', self) theme = QMenu('Theme', dwarf_menu) theme.addAction('Black') theme.addAction('Dark') theme.addAction('Light') theme.triggered.connect(self._set_theme) dwarf_menu.addMenu(theme) dwarf_menu.addSeparator() if self._is_newer_dwarf: dwarf_menu.addAction('Update', self._update_dwarf) dwarf_menu.addAction('Close', self.close) self.menu.addMenu(dwarf_menu) session = self.session_manager.session if session is not None: session_menu = session.main_menu if isinstance(session_menu, list): for menu in session_menu: self.menu.addMenu(menu) else: self.menu.addMenu(session_menu) # plugins if self.plugin_manager.plugins: self.plugin_menu = QMenu('Plugins', self) for plugin in self.plugin_manager.plugins: plugin_instance = self.plugin_manager.plugins[plugin] plugin_sub_menu = self.plugin_menu.addMenu(plugin_instance.name) try: actions = plugin_instance.__get_top_menu_actions__() for action in actions: plugin_sub_menu.addAction(action) except: pass if not plugin_sub_menu.isEmpty(): plugin_sub_menu.addSeparator() about = plugin_sub_menu.addAction('About') about.triggered.connect( lambda x, item=plugin: self._show_plugin_about(item)) if not self.plugin_menu.isEmpty(): self.menu.addMenu(self.plugin_menu) self.view_menu = QMenu('View', self) self.panels_menu = QMenu('Panels', self.view_menu) self.panels_menu.addAction( 'Search', lambda: self.show_main_tab('search'), shortcut=QKeySequence(Qt.CTRL + Qt.Key_F3)) self.panels_menu.addAction( 'Modules', lambda: self.show_main_tab('modules') ) self.panels_menu.addAction( 'Ranges', lambda: self.show_main_tab('ranges') ) self.view_menu.addMenu(self.panels_menu) self.debug_view_menu = self.view_menu.addMenu('Debug') self.view_menu.addSeparator() self.view_menu.addAction('Hide all', self._hide_all_widgets, shortcut=QKeySequence(Qt.CTRL + Qt.Key_F1)) self.view_menu.addAction('Show all', self._show_all_widgets, shortcut=QKeySequence(Qt.CTRL + Qt.Key_F2)) self.view_menu.addSeparator() self.menu.addMenu(self.view_menu) if self.dwarf_args.debug_script: debug_menu = QMenu('Debug', self) debug_menu.addAction('Reload core', self._menu_reload_core) debug_menu.addAction('Debug dwarf js core', self._menu_debug_dwarf_js) self.menu.addMenu(debug_menu) # tools _tools = self.prefs.get('tools') if _tools: tools_menu = QMenu('Tools', self) for _tool in _tools: if _tool and _tool['name']: if _tool['name'] == 'sep': tools_menu.addSeparator() continue _cmd = _tool['cmd'] tools_menu.addAction(_tool['name']) if not tools_menu.isEmpty(): tools_menu.triggered.connect(self._execute_tool) self.menu.addMenu(tools_menu) about_menu = QMenu('About', self) about_menu.addAction('Dwarf on GitHub', self._menu_github) about_menu.addAction('Documention', self._menu_documentation) about_menu.addAction('Api', self._menu_api) about_menu.addAction('Slack', self._menu_slack) about_menu.addSeparator() about_menu.addAction('Info', self._show_about_dlg) self.menu.addMenu(about_menu) def _show_plugin_about(self, plugin): plugin = self.plugin_manager.plugins[plugin] if plugin: info = plugin.__get_plugin_info__() version = utils.safe_read_map(info, 'version', '') description = utils.safe_read_map(info, 'description', '') author = utils.safe_read_map(info, 'author', '') homepage = utils.safe_read_map(info, 'homepage', '') license_ = utils.safe_read_map(info, 'license', '') utils.show_message_box( 'Name: {0}\nVersion: {1}\nDescription: {2}\nAuthor: {3}\nHomepage: {4}\nLicense: {5}'. format(plugin.name, version, description, author, homepage, license_)) def _enable_update_menu(self): self._is_newer_dwarf = True def _update_dwarf(self): if self.welcome_window: self.welcome_window._update_dwarf() def _on_close_tab(self, index): tab_text = self.main_tabs.tabText(index) if tab_text: tab_text = tab_text.lower().replace(' ', '-') try: self._ui_elems.remove(tab_text) except ValueError: # recheck ValueError: list.remove(x): x not in list pass self.main_tabs.removeTab(index) self.onSystemUIElementRemoved.emit(tab_text) def _on_dwarf_updated(self): self.onRestart.emit() def _execute_tool(self, qaction): if qaction: _tools = self.prefs.get('tools') if _tools: for _tool in _tools: if _tool and _tool['name'] and _tool['name'] != 'sep': if qaction.text() == _tool['name']: try: import subprocess subprocess.Popen(_tool['cmd'], creationflags=subprocess.CREATE_NEW_CONSOLE) except: pass break def _set_theme(self, qaction): if qaction: utils.set_theme(qaction.text(), self.prefs) def _hide_all_widgets(self): self.watchpoints_dwidget.hide() self.breakpoint_dwiget.hide() self.bookmarks_dwiget.hide() self.registers_dock.hide() self.console_dock.hide() self.backtrace_dock.hide() self.threads_dock.hide() def _show_all_widgets(self): self.watchpoints_dwidget.show() self.breakpoint_dwiget.show() self.bookmarks_dwiget.show() self.registers_dock.show() self.console_dock.show() self.backtrace_dock.show() self.threads_dock.show() def _menu_reload_core(self): self.dwarf.script.exports.reload() def _menu_debug_dwarf_js(self): you_know_what_to_do = json.loads( self.dwarf.script.exports.debugdwarfjs()) return you_know_what_to_do def show_main_tab(self, name): name = name.lower() # elem doesnt exists? create it if name not in self._ui_elems: self._create_ui_elem(name) index = 0 name = name.join(name.split()).lower() if name == 'ranges': index = self.main_tabs.indexOf(self.ranges_panel) elif name == 'search': index = self.main_tabs.indexOf(self.search_panel) elif name == 'modules': index = self.main_tabs.indexOf(self.modules_panel) elif name == 'data': index = self.main_tabs.indexOf(self.data_panel) elif name == 'jvm-tracer': index = self.main_tabs.indexOf(self.java_trace_panel) elif name == 'jvm-inspector': index = self.main_tabs.indexOf(self.java_inspector_panel) elif name == 'jvm-debugger': index = self.main_tabs.indexOf(self.java_explorer_panel) elif name == 'objc-inspector': index = self.main_tabs.indexOf(self.objc_inspector_panel) elif name == 'smali': index = self.main_tabs.indexOf(self.smali_panel) self.main_tabs.setCurrentIndex(index) def jump_to_address(self, ptr, view=0, show_panel=True): if show_panel: self.show_main_tab('debug') self.debug_panel.jump_to_address(ptr, view=view) @pyqtSlot(name='mainMenuGitHub') def _menu_github(self): QDesktopServices.openUrl(QUrl('https://github.com/iGio90/Dwarf')) @pyqtSlot(name='mainMenuApi') def _menu_api(self): QDesktopServices.openUrl(QUrl('https://igio90.github.io/Dwarf/')) @pyqtSlot(name='mainMenuDocumentation') def _menu_documentation(self): QDesktopServices.openUrl(QUrl('http://www.giovanni-rocca.com/dwarf/')) @pyqtSlot(name='mainMenuSlack') def _menu_slack(self): QDesktopServices.openUrl( QUrl('https://join.slack.com/t/resecret/shared_invite' '/enQtMzc1NTg4MzE3NjA1LTlkNzYxNTIwYTc2ZTYyOWY1MT' 'Q1NzBiN2ZhYjQwYmY0ZmRhODQ0NDE3NmRmZjFiMmE1MDYwN' 'WJlNDVjZDcwNGE')) def _show_about_dlg(self): about_dlg = AboutDialog(self) about_dlg.show() def _create_ui_elem(self, elem): elem = elem.lower() if not isinstance(elem, str): return if elem not in self._ui_elems: self._ui_elems.append(elem) elem_wiget = None if elem == 'watchpoints': from dwarf_debugger.ui.session_widgets.watchpoints import WatchpointsWidget self.watchpoints_dwidget = QDockWidget('Watchpoints', self) self.watchpoints_panel = WatchpointsWidget(self) # dont respond to dblclick mem cant be shown # self.watchpoints_panel.onItemDoubleClicked.connect( # self._on_watchpoint_clicked) self.watchpoints_panel.onItemRemoved.connect( self._on_watchpoint_removeditem) self.watchpoints_panel.onItemAdded.connect(self._on_watchpoint_added) self.watchpoints_dwidget.setWidget(self.watchpoints_panel) self.watchpoints_dwidget.setObjectName('WatchpointsWidget') self.addDockWidget(Qt.LeftDockWidgetArea, self.watchpoints_dwidget) self.view_menu.addAction(self.watchpoints_dwidget.toggleViewAction()) elem_wiget = self.watchpoints_panel elif elem == 'breakpoints': from dwarf_debugger.ui.session_widgets.breakpoints import BreakpointsWidget self.breakpoint_dwiget = QDockWidget('breakpoint', self) self.breakpoints_panel = BreakpointsWidget(self) self.breakpoints_panel.onBreakpointRemoved.connect(self._on_breakpoint_removed) self.breakpoint_dwiget.setWidget(self.breakpoints_panel) self.breakpoint_dwiget.setObjectName('breakpointWidget') self.addDockWidget(Qt.LeftDockWidgetArea, self.breakpoint_dwiget) self.view_menu.addAction(self.breakpoint_dwiget.toggleViewAction()) elem_wiget = self.breakpoints_panel elif elem == 'bookmarks': from dwarf_debugger.ui.session_widgets.bookmarks import BookmarksWidget self.bookmarks_dwiget = QDockWidget('Boomarks', self) self.bookmarks_panel = BookmarksWidget(self) self.bookmarks_dwiget.setWidget(self.bookmarks_panel) self.bookmarks_dwiget.setObjectName('BookmarksWidget') self.addDockWidget(Qt.LeftDockWidgetArea, self.bookmarks_dwiget) self.view_menu.addAction(self.bookmarks_dwiget.toggleViewAction()) elem_wiget = self.bookmarks_panel elif elem == 'registers': from dwarf_debugger.ui.session_widgets.context import ContextWidget self.registers_dock = QDockWidget('Context', self) self.context_panel = ContextWidget(self) self.registers_dock.setWidget(self.context_panel) self.registers_dock.setObjectName('ContextWidget') self.addDockWidget(Qt.RightDockWidgetArea, self.registers_dock) self.view_menu.addAction(self.registers_dock.toggleViewAction()) elem_wiget = self.context_panel elif elem == 'debug': from dwarf_debugger.ui.panels.panel_debug import QDebugPanel self.debug_panel = QDebugPanel(self) self.main_tabs.addTab(self.debug_panel, 'Debug') elem_wiget = self.debug_panel elif elem == 'jvm-debugger': from dwarf_debugger.ui.panels.panel_java_explorer import JavaExplorerPanel self.java_explorer_panel = JavaExplorerPanel(self) self.main_tabs.addTab(self.java_explorer_panel, 'JVM debugger') self.main_tabs.tabBar().moveTab( self.main_tabs.indexOf(self.java_explorer_panel), 1) elem_wiget = self.java_explorer_panel elif elem == 'jvm-inspector': from dwarf_debugger.ui.panels.panel_java_inspector import JavaInspector self.java_inspector_panel = JavaInspector(self) self.main_tabs.addTab(self.java_inspector_panel, 'JVM inspector') elem_wiget = self.java_inspector_panel elif elem == 'objc-inspector': from dwarf_debugger.ui.panels.panel_objc_inspector import ObjCInspector self.objc_inspector_panel = ObjCInspector(self) self.main_tabs.addTab(self.objc_inspector_panel, 'ObjC inspector') elem_wiget = self.objc_inspector_panel elif elem == 'console': from dwarf_debugger.ui.session_widgets.console import ConsoleWidget self.console_dock = QDockWidget('Console', self) self.console_panel = ConsoleWidget(self) if self.dwarf_args.script and len(self.dwarf_args.script) > 0 and os.path.exists(self.dwarf_args.script): with open(self.dwarf_args.script, 'r') as f: self.console_panel.get_js_console().script_file = self.dwarf_args.script self.console_panel.get_js_console().function_content = f.read() self.dwarf.onLogToConsole.connect(self._log_js_output) self.dwarf.onLogEvent.connect(self._log_event) self.console_dock.setWidget(self.console_panel) self.console_dock.setObjectName('ConsoleWidget') self.addDockWidget(Qt.BottomDockWidgetArea, self.console_dock) self.view_menu.addAction(self.console_dock.toggleViewAction()) elem_wiget = self.console_panel elif elem == 'backtrace': from dwarf_debugger.ui.session_widgets.backtrace import BacktraceWidget self.backtrace_dock = QDockWidget('Backtrace', self) self.backtrace_panel = BacktraceWidget(self) self.backtrace_dock.setWidget(self.backtrace_panel) self.backtrace_dock.setObjectName('BacktraceWidget') self.backtrace_panel.onShowMemoryRequest.connect(self._on_showmemory_request) self.addDockWidget(Qt.RightDockWidgetArea, self.backtrace_dock) self.view_menu.addAction(self.backtrace_dock.toggleViewAction()) elem_wiget = self.backtrace_panel elif elem == 'threads': from dwarf_debugger.ui.session_widgets.threads import ThreadsWidget self.threads_dock = QDockWidget('Threads', self) self.contexts_list_panel = ThreadsWidget(self) self.dwarf.onThreadResumed.connect( self.contexts_list_panel.resume_tid) self.contexts_list_panel.onItemDoubleClicked.connect( self._manually_apply_context) self.threads_dock.setWidget(self.contexts_list_panel) self.threads_dock.setObjectName('ThreadPanel') self.addDockWidget(Qt.RightDockWidgetArea, self.threads_dock) self.view_menu.addAction(self.threads_dock.toggleViewAction()) elem_wiget = self.contexts_list_panel elif elem == 'modules': from dwarf_debugger.ui.panels.panel_modules import ModulesPanel self.modules_panel = ModulesPanel(self) self.modules_panel.onModuleSelected.connect( self._on_module_dblclicked) self.modules_panel.onModuleFuncSelected.connect( self._on_modulefunc_dblclicked) self.modules_panel.onAddBreakpoint.connect(self._on_addmodule_breakpoint) self.modules_panel.onDumpBinary.connect(self._on_dump_module) self.main_tabs.addTab(self.modules_panel, 'Modules') elem_wiget = self.modules_panel elif elem == 'ranges': from dwarf_debugger.ui.panels.panel_ranges import RangesPanel self.ranges_panel = RangesPanel(self) self.ranges_panel.onItemDoubleClicked.connect( self._range_dblclicked) self.ranges_panel.onDumpBinary.connect(self._on_dump_module) # connect to watchpointpanel func self.ranges_panel.onAddWatchpoint.connect( self.watchpoints_panel.do_addwatchpoint_dlg) self.main_tabs.addTab(self.ranges_panel, 'Ranges') elem_wiget = self.ranges_panel elif elem == 'search': from dwarf_debugger.ui.panels.panel_search import SearchPanel self.search_panel = SearchPanel(self) self.main_tabs.addTab(self.search_panel, 'Search') elem_wiget = self.search_panel elif elem == 'data': from dwarf_debugger.ui.panels.panel_data import DataPanel self.data_panel = DataPanel(self) self.main_tabs.addTab(self.data_panel, 'Data') elem_wiget = self.data_panel elif elem == 'jvm-tracer': from dwarf_debugger.ui.panels.panel_java_trace import JavaTracePanel self.java_trace_panel = JavaTracePanel(self) self.main_tabs.addTab(self.java_trace_panel, 'JVM tracer') elem_wiget = self.java_trace_panel elif elem == 'smali': from dwarf_debugger.ui.panels.panel_smali import SmaliPanel self.smali_panel = SmaliPanel() self.main_tabs.addTab(self.smali_panel, 'Smali') elem_wiget = self.smali_panel else: print('no handler for elem: ' + elem) if elem_wiget is not None: self.onSystemUIElementCreated.emit(elem, elem_wiget) # TODO: remove add @2x for item in self.findChildren(QDockWidget): if item: if 'darwin' in sys.platform: item.setStyleSheet( 'QDockWidget::title { padding-left:-30px; }' ) def set_status_text(self, txt): self.statusbar.showMessage(txt) # ************************************************************************ # **************************** Properties ******************************** # ************************************************************************ @property def disassembly(self): return self.asm_panel @property def backtrace(self): return self.backtrace_panel @property def console(self): return self.console_panel @property def context(self): return self.context_panel @property def threads(self): return self.contexts_list_panel @property def ftrace(self): return self.ftrace_panel @property def breakpoint(self): return self.breakpoints_panel @property def java_inspector(self): return self.java_inspector_panel @property def objc_inspector(self): return self.objc_inspector_panel @property def java_explorer(self): return self.java_explorer_panel @property def modules(self): return self.modules_panel @property def ranges(self): return self.ranges_panel @property def watchpoints(self): return self.watchpoints_panel @property def dwarf(self): if self.session_manager.session is not None: return self.session_manager.session.dwarf else: return None @property def ui_elements(self): return self._ui_elems # ************************************************************************ # **************************** Handlers ********************************** # ************************************************************************ # session handlers def _start_session(self, session_type, session_data=None): if self.welcome_window is not None: self.welcome_window.close() try: self.session_manager.create_session( session_type, session_data=session_data) except Exception as e: if self.welcome_window: utils.show_message_box(str(e)) def _restore_session(self, session_data): if 'session' in session_data: session_type = session_data['session'] self.dwarf_args.any = session_data['package'] self._start_session(session_type, session_data=session_data) def session_created(self): # session init done create ui for it session = self.session_manager.session self._setup_main_menu() for ui_elem in session.session_ui_sections: ui_elem = ui_elem.join(ui_elem.split()).lower() self._create_ui_elem(ui_elem) self.dwarf.onProcessAttached.connect(self._on_attached) self.dwarf.onProcessDetached.connect(self._on_detached) self.dwarf.onScriptLoaded.connect(self._on_script_loaded) self.dwarf.onSetRanges.connect(self._on_setranges) self.dwarf.onSetModules.connect(self._on_setmodules) self.dwarf.onAddNativeBreakpoint.connect(self._on_add_breakpoint) self.dwarf.onApplyContext.connect(self._apply_context) self.dwarf.onThreadResumed.connect(self.on_tid_resumed) self.dwarf.onHitModuleInitializationBreakpoint.connect(self._on_hit_module_initialization_breakpoint) self.dwarf.onSetData.connect(self._on_set_data) self.session_manager.start_session(self.dwarf_args) ui_state = self.q_settings.value('dwarf_ui_state') if ui_state: self.restoreGeometry(ui_state) window_state = self.q_settings.value('dwarf_ui_window', self.saveState()) if window_state: self.restoreState(window_state) self.showMaximized() def session_stopped(self): self.menu.clear() self.main_tabs.clear() # actually we need to kill this. needs a refactor if self.java_trace_panel is not None: self.java_trace_panel = None for elem in self._ui_elems: if elem == 'watchpoints': self.watchpoints_panel.clear_list() self.watchpoints_panel.close() self.watchpoints_panel = None self.removeDockWidget(self.watchpoints_dwidget) self.watchpoints_dwidget = None elif elem == 'breakpoints': self.breakpoints_panel.close() self.breakpoints_panel = None self.removeDockWidget(self.breakpoint_dwiget) self.breakpoint_dwiget = None elif elem == 'registers': self.context_panel.close() self.context_panel = None self.removeDockWidget(self.registers_dock) self.registers_dock = None elif elem == 'debug': self.debug_panel.close() self.debug_panel = None self.main_tabs.removeTab(0) # self.main_tabs elif elem == 'jvm-debugger': self.java_explorer_panel.close() self.java_explorer_panel = None self.removeDockWidget(self.watchpoints_dwidget) elif elem == 'console': self.console_panel.close() self.console_panel = None self.removeDockWidget(self.console_dock) self.console_dock = None elif elem == 'backtrace': self.backtrace_panel.close() self.backtrace_panel = None self.removeDockWidget(self.backtrace_dock) elif elem == 'threads': self.contexts_list_panel.close() self.contexts_list_panel = None self.removeDockWidget(self.threads_dock) self.threads_dock = None elif elem == 'bookmarks': self.bookmarks_panel.close() self.bookmarks_panel = None self.removeDockWidget(self.bookmarks_dwiget) self.bookmarks_dwiget = None self._initialize_ui_elements() def session_closed(self): self._initialize_ui_elements() self.hide() if self.welcome_window is not None: self.welcome_window.exec() # close if it was a commandline session if self.welcome_window is None: if self.dwarf_args.any != '': self.close() # ui handler def closeEvent(self, event): """ Window closed save stuff or whatever at exit detaches dwarf """ if self.session_manager.session: self.session_manager.session.stop() # save windowstuff self.q_settings.setValue('dwarf_ui_state', self.saveGeometry()) self.q_settings.setValue('dwarf_ui_window', self.saveState()) if self.dwarf: try: self.dwarf.detach() except: pass super().closeEvent(event) def _on_watchpoint_clicked(self, ptr): """ Address in Watchpoint/Breakpointpanel was clicked show Memory """ if '.' in ptr: # java_breakpoint file_path = ptr.replace('.', os.path.sep) else: self.jump_to_address(ptr) def _on_watchpoint_added(self, ptr): """ Watchpoint Entry was added """ try: # set highlight self.debug_panel.memory_panel.add_highlight( HighLight('watchpoint', ptr, self.dwarf.pointer_size)) except HighlightExistsError: pass def _on_watchpoint_removeditem(self, ptr): """ Watchpoint Entry was removed remove highlight too """ self.debug_panel.memory_panel.remove_highlight(ptr) def _on_module_dblclicked(self, data): """ Module in ModulePanel was doubleclicked """ addr, size = data addr = utils.parse_ptr(addr) self.jump_to_address(addr) def _on_modulefunc_dblclicked(self, ptr): """ Function in ModulePanel was doubleclicked """ ptr = utils.parse_ptr(ptr) self.jump_to_address(ptr) def _on_dump_module(self, data): """ DumpBinary MenuItem in ModulePanel was selected """ ptr, size = data ptr = utils.parse_ptr(ptr) size = int(size, 10) self.dwarf.dump_memory(ptr=ptr, length=size) def _range_dblclicked(self, ptr): """ Range in RangesPanel was doubleclicked """ ptr = utils.parse_ptr(ptr) self.jump_to_address(ptr) # dwarf handlers def _log_js_output(self, output): if self.console_panel is not None: time_prefix = True if len(output.split('\n')) > 1 or len(output.split('<br />')) > 1: time_prefix = False self.console_panel.get_js_console().log(output, time_prefix=time_prefix) def _log_event(self, output): if self.console_panel is not None: self.console_panel.get_events_console().log(output) def _on_setranges(self, ranges): """ Dwarf wants to set Ranges only breakpointed up to switch tab or create ui its connected in panel after creation """ if self.ranges_panel is None: self.show_main_tab('ranges') # forward only now to panel it connects after creation self.ranges_panel.set_ranges(ranges) else: self.show_main_tab('ranges') def _on_setmodules(self, modules): """ Dwarf wants to set Modules only breakpointed up to switch tab or create ui its connected in panel after creation """ if self.modules_panel is None: self._create_ui_elem('modules') self.modules_panel.set_modules(modules) else: self.show_main_tab('modules') def _manually_apply_context(self, context): """ perform additional operation if the context has been manually applied from the context list """ self._apply_context(context, manual=True) def _on_hit_module_initialization_breakpoint(self, data): if self.debug_panel.memory_panel.number_of_lines() == 0: data = data[1] module_base = int(data['moduleBase'], 16) self.jump_to_address(module_base) def _apply_context(self, context, manual=False): # update current context tid # this should be on top as any further api from js needs to be executed on that thread reason = context['reason'] is_initial_setup = reason == -1 if manual or (self.dwarf.context_tid and not is_initial_setup): self.dwarf.context_tid = context['tid'] if is_initial_setup: self.debug_panel.on_context_setup() if 'context' in context: if not manual: self.threads.add_context(context) is_java = context['is_java'] if is_java: if self.java_explorer_panel is None: self._create_ui_elem('jvm-debugger') self.context_panel.set_context(context['ptr'], 1, context['context']) self.java_explorer_panel.init() self.show_main_tab('jvm-debugger') else: self.context_panel.set_context(context['ptr'], 0, context['context']) if reason == 0: if 'pc' in context['context']: if self.debug_panel.disassembly_panel.number_of_lines() == 0 or manual: self.jump_to_address(context['context']['pc']['value'], view=1) elif reason == 3: # step # we make the frontend believe we are in the real step pc instead of the frida space context['context']['pc'] = context['ptr'] if 'rip' in context['context']: context['context']['rip'] = context['ptr'] self.jump_to_address(context['ptr'], view=1) if 'backtrace' in context: self.backtrace_panel.set_backtrace(context['backtrace']) def _on_add_breakpoint(self, breakpoint): try: # set highlight ptr = breakpoint.get_target() ptr = utils.parse_ptr(ptr) self.debug_panel.memory_panel.add_highlight( HighLight('breakpoint', ptr, self.dwarf.pointer_size)) except HighlightExistsError: pass def _on_breakpoint_removed(self, ptr): ptr = utils.parse_ptr(ptr) self.debug_panel.memory_panel.remove_highlight(ptr) def _on_addmodule_breakpoint(self, data): ptr, name = data self.dwarf.breakpoint_native(input_=ptr) def on_tid_resumed(self, tid): if self.dwarf: if self.dwarf.context_tid == tid: # clear backtrace if 'backtrace' in self._ui_elems: if self.backtrace_panel is not None: self.backtrace_panel.clear() # remove thread if 'threads' in self._ui_elems: if self.contexts_list_panel is not None: self.contexts_list_panel.resume_tid(tid) # clear registers if 'registers' in self._ui_elems: if self.context_panel is not None: self.context_panel.clear() # clear jvm explorer if 'jvm-debugger' in self._ui_elems: if self.java_explorer_panel is not None: self.java_explorer_panel.clear_panel() # invalidate dwarf context tid self.dwarf.context_tid = 0 def _on_set_data(self, data): if not isinstance(data, list): return if self.data_panel is None: self.show_main_tab('data') if self.data_panel is not None: self.data_panel.append_data(data[0], data[1], data[2]) def show_progress(self, text): self.progressbar.setVisible(True) self.set_status_text(text) def hide_progress(self): self.progressbar.setVisible(False) self.set_status_text('') def _on_attached(self, data): self.setWindowTitle('Dwarf - Attached to %s (%s)' % (data[1], data[0])) def _on_detached(self, data): reason = data[1] if reason == 'application-requested': if self.session_manager.session: self.session_manager.session.stop() return 0 if self.dwarf is not None: ret = QDialogDetached.show_dialog(self.dwarf, data[0], data[1], data[2]) if ret == 0: self.dwarf.restart_proc() elif ret == 1: self.session_manager.session.stop() return 0 def _on_script_loaded(self): # restore the loaded session if any self.session_manager.restore_session() def on_add_bookmark(self, ptr): """ provide ptr as int """ if self.bookmarks_panel is not None: self.bookmarks_panel._create_bookmark(ptr=hex(ptr)) def _on_showmemory_request(self, ptr): # its simple ptr show in memorypanel if isinstance(ptr, str): ptr = utils.parse_ptr(ptr) self.jump_to_address(ptr, 0) elif isinstance(ptr, list): # TODO: extend caller, ptr = ptr ptr = utils.parse_ptr(ptr) if caller == 'backtrace' or caller == 'bt': # jumpto in disasm self.jump_to_address(ptr, 1)
class MainWindow(QMainWindow): # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-statements def __init__(self, app, mapLayers, mapLayersCategory): QMainWindow.__init__(self) self.app = app self.mapLayers = mapLayers self.mapLayersCategory = mapLayersCategory self.resize(shared.windowWidth, shared.windowHeight) self.setWindowTitle(shared.progName + ": " + shared.progVer) # Set up the map canvas self.canvas = QgsMapCanvas() self.setCentralWidget(self.canvas) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setCachingEnabled(True) #self.canvas.setMapUpdateInterval(1000) self.canvas.setParallelRenderingEnabled(True) self.canvas.enableMapTileRendering(True) self.canvas.setLayers(self.mapLayers) self.canvas.setExtent(shared.extentRect) self.canvas.setMagnificationFactor(shared.windowMagnification) #mapSet = self.canvas.mapSettings() #print(mapSet.flags()) # Create some actions #self.actionExit = QAction(QIcon('exit.png'), '&Exit', self) self.actionExit = QAction("&Exit", self) self.actionExit.setShortcut("Ctrl+Q") self.actionExit.setStatusTip("Exit " + shared.progName) self.actionZoomIn = QAction("Zoom in", self) self.actionZoomIn.setCheckable(True) #self.actionExit.setShortcut("Ctrl++") self.actionZoomIn.setStatusTip("Show more detail") self.actionZoomOut = QAction("Zoom out", self) self.actionZoomOut.setCheckable(True) #self.actionExit.setShortcut("Ctrl+-") self.actionZoomOut.setStatusTip("Show less detail") self.actionPan = QAction("Pan", self) self.actionPan.setCheckable(True) self.actionPan.setStatusTip("Move the map laterally") self.actionChangeBackground = QAction("Change background", self) self.actionChangeBackground.setStatusTip( "Change the raster background") if not shared.haveRasterBackground: self.actionChangeBackground.setEnabled(False) self.actionCoords = QAction("Show coordinates", self) self.actionCoords.setCheckable(True) self.actionCoords.setStatusTip("Click to show coordinates") self.actionRun = QAction("Simulate", self) self.actionRun.setStatusTip("Route flow") # Connect the actions self.actionExit.triggered.connect(app.quit) self.actionZoomIn.triggered.connect(self.zoomIn) self.actionZoomOut.triggered.connect(self.zoomOut) self.actionPan.triggered.connect(self.pan) self.actionChangeBackground.triggered.connect(self.changeBackground) self.actionCoords.triggered.connect(self.showCoords) self.actionRun.triggered.connect(self.doRun) # Create a menu bar and add menus self.menubar = self.menuBar() self.fileMenu = self.menubar.addMenu("&File") self.fileMenu.addAction(self.actionExit) self.editMenu = self.menubar.addMenu("&Edit") #self.editMenu.addAction(self.actionExit) self.viewMenu = self.menubar.addMenu("&View") self.viewMenu.addAction(self.actionZoomIn) self.viewMenu.addAction(self.actionZoomOut) self.viewMenu.addAction(self.actionPan) self.viewMenu.addAction(self.actionChangeBackground) self.viewMenu.addAction(self.actionCoords) self.runMenu = self.menubar.addMenu("&Run") self.runMenu.addAction(self.actionRun) # Create a tool bar and add some actions self.toolbar = self.addToolBar("Default") self.toolbar.setFloatable(True) self.toolbar.addAction(self.actionRun) self.toolbar.addAction(self.actionZoomIn) self.toolbar.addAction(self.actionZoomOut) self.toolbar.addAction(self.actionPan) self.toolbar.addAction(self.actionCoords) # Create some map tools self.toolPan = QgsMapToolPan(self.canvas) self.toolPan.setAction(self.actionPan) self.toolZoomIn = QgsMapToolZoom(self.canvas, False) # False = in self.toolZoomIn.setAction(self.actionZoomIn) self.toolZoomOut = QgsMapToolZoom(self.canvas, True) # True = out self.toolZoomOut.setAction(self.actionZoomOut) self.toolCoords = PointTool(self.canvas) self.toolCoords.setAction(self.actionCoords) # Put into panning mode self.pan() # Add a status bar self.statusBar = QStatusBar(self.canvas) self.setStatusBar(self.statusBar) # And put a progress indicator on the status bar self.statusBar.progress = QProgressBar(self) self.statusBar.progress.setRange(0, 100) self.statusBar.progress.setMaximumWidth(500) self.statusBar.progress.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.statusBar.addPermanentWidget(self.statusBar.progress) self.myThread = None return #====================================================================================================================== #====================================================================================================================== def doRun(self): # Delete all output features (in case we have some from a previous run) listIDs = [ feat.id() for feat in shared.outFlowMarkerPointLayer.getFeatures() ] prov = shared.outFlowMarkerPointLayer.dataProvider() prov.deleteFeatures([featID for featID in listIDs]) shared.outFlowMarkerPointLayer.updateExtents() shared.outFlowMarkerPointLayer.triggerRepaint() listIDs = [feat.id() for feat in shared.outFlowLineLayer.getFeatures()] prov = shared.outFlowLineLayer.dataProvider() prov.deleteFeatures([featID for featID in listIDs]) shared.outFlowLineLayer.updateExtents() shared.outFlowLineLayer.triggerRepaint() self.canvas.repaint() self.statusBar.progress.setValue(0) self.actionRun.setEnabled(False) # All is now ready, so run the simulation as a separate thread self.myThread = SimulationThread(self.app, self) self.myThread.refresh.connect(self.doRefresh) self.myThread.runDone.connect(self.runDone) self.canvas.freeze(True) #self.canvas.refreshAllLayers() #self.app.processEvents() self.myThread.start() print("\nThread started") return #====================================================================================================================== #====================================================================================================================== def doRefresh(self): self.canvas.freeze(False) if not self.canvas.isDrawing(): shared.outFlowMarkerPointLayer.triggerRepaint() shared.outFlowLineLayer.triggerRepaint() self.canvas.repaint() self.canvas.freeze(True) if not isinstance(shared.flowStartPoints, int): doneSoFar = (float(shared.thisStartPoint) / float(len(shared.flowStartPoints) + 1)) * 100.0 #shared.fpOut.write(doneSoFar) self.statusBar.progress.setValue(doneSoFar) return #====================================================================================================================== #====================================================================================================================== def zoomIn(self): self.canvas.freeze(False) self.canvas.setMapTool(self.toolZoomIn) return #====================================================================================================================== #====================================================================================================================== def zoomOut(self): self.canvas.freeze(False) self.canvas.setMapTool(self.toolZoomOut) return #====================================================================================================================== #====================================================================================================================== def pan(self): self.canvas.freeze(False) self.canvas.setMapTool(self.toolPan) return #====================================================================================================================== #====================================================================================================================== def showCoords(self): self.canvas.setMapTool(self.toolCoords) return #====================================================================================================================== #====================================================================================================================== def close(self): if self.myThread: self.myThread.quit() self.myThread = None return #====================================================================================================================== #====================================================================================================================== def runDone(self): self.canvas.freeze(False) shared.outFlowMarkerPointLayer.triggerRepaint() shared.outFlowLineLayer.triggerRepaint() self.canvas.repaint() print("Thread done") self.myThread.quit() #self.myThread = None self.statusBar.progress.setValue(100) #QMessageBox.information(self, "End of run", shared.progName + ": flow routed") self.statusBar.showMessage("End of run: flow routed", shared.defaultMessageDisplayTime) # To prevent subsequent re-runs # self.actionRun.setEnabled(False) return #====================================================================================================================== #====================================================================================================================== def changeBackground(self): for n in range(len(shared.rasterInputLayersCategory)): if shared.rasterInputLayersCategory[n] == INPUT_RASTER_BACKGROUND: oldOpacity = shared.rasterInputLayers[n].renderer().opacity() if oldOpacity == 0: newOpacity = shared.rasterFileOpacity[n] else: newOpacity = 0 shared.rasterInputLayers[n].renderer().setOpacity(newOpacity) #layerID = shared.rasterInputLayers[n].id() #layerTreeNode = QgsProject.instance().layerTreeRoot().findLayer(layerID) #print(layerTreeNode.dump()) #layerTreeNode.setItemVisibilityChecked(not layerTreeNode.itemVisibilityChecked()) #print(layerTreeNode.dump()) #print("*****************") #for n in range(len(self.mapLayers)): #if self.mapLayersCategory[n] == INPUT_RASTER_BACKGROUND: #self.mapLayers[n].setVisible(not self.mapLayers[n].isVisible()) #self.canvas.setLayers(self.mapLayers) self.doRefresh() return
class ResultWindow(QMainWindow): def __init__(self, parent, app, **kwargs): super().__init__(parent, **kwargs) self.app = app self._setupUi() if app.model.app_mode == AppMode.Picture: MODEL_CLASS = ResultsModelPicture elif app.model.app_mode == AppMode.Music: MODEL_CLASS = ResultsModelMusic else: MODEL_CLASS = ResultsModelStandard self.resultsModel = MODEL_CLASS(self.app, self.resultsView) self.stats = StatsLabel(app.model.stats_label, self.statusLabel) self._update_column_actions_status() self.menuColumns.triggered.connect(self.columnToggled) self.resultsView.doubleClicked.connect(self.resultsDoubleClicked) self.resultsView.spacePressed.connect(self.resultsSpacePressed) self.detailsButton.clicked.connect(self.actionDetails.triggered) self.dupesOnlyCheckBox.stateChanged.connect(self.powerMarkerTriggered) self.deltaValuesCheckBox.stateChanged.connect(self.deltaTriggered) self.searchEdit.searchChanged.connect(self.searchChanged) self.app.willSavePrefs.connect(self.appWillSavePrefs) def _setupActions(self): # (name, shortcut, icon, desc, func) ACTIONS = [ ("actionDetails", "Ctrl+I", "", tr("Details"), self.detailsTriggered), ("actionActions", "", "", tr("Actions"), self.actionsTriggered), ( "actionPowerMarker", "Ctrl+1", "", tr("Show Dupes Only"), self.powerMarkerTriggered, ), ("actionDelta", "Ctrl+2", "", tr("Show Delta Values"), self.deltaTriggered), ( "actionDeleteMarked", "Ctrl+D", "", tr("Send Marked to Recycle Bin..."), self.deleteTriggered, ), ( "actionMoveMarked", "Ctrl+M", "", tr("Move Marked to..."), self.moveTriggered, ), ( "actionCopyMarked", "Ctrl+Shift+M", "", tr("Copy Marked to..."), self.copyTriggered, ), ( "actionRemoveMarked", "Ctrl+R", "", tr("Remove Marked from Results"), self.removeMarkedTriggered, ), ( "actionReprioritize", "", "", tr("Re-Prioritize Results..."), self.reprioritizeTriggered, ), ( "actionRemoveSelected", "Ctrl+Del", "", tr("Remove Selected from Results"), self.removeSelectedTriggered, ), ( "actionIgnoreSelected", "Ctrl+Shift+Del", "", tr("Add Selected to Ignore List"), self.addToIgnoreListTriggered, ), ( "actionMakeSelectedReference", "Ctrl+Space", "", tr("Make Selected into Reference"), self.app.model.make_selected_reference, ), ( "actionOpenSelected", "Ctrl+O", "", tr("Open Selected with Default Application"), self.openTriggered, ), ( "actionRevealSelected", "Ctrl+Shift+O", "", tr("Open Containing Folder of Selected"), self.revealTriggered, ), ( "actionRenameSelected", "F2", "", tr("Rename Selected"), self.renameTriggered, ), ("actionMarkAll", "Ctrl+A", "", tr("Mark All"), self.markAllTriggered), ( "actionMarkNone", "Ctrl+Shift+A", "", tr("Mark None"), self.markNoneTriggered, ), ( "actionInvertMarking", "Ctrl+Alt+A", "", tr("Invert Marking"), self.markInvertTriggered, ), ( "actionMarkSelected", Qt.Key_Space, "", tr("Mark Selected"), self.markSelectedTriggered, ), ( "actionExportToHTML", "", "", tr("Export To HTML"), self.app.model.export_to_xhtml, ), ( "actionExportToCSV", "", "", tr("Export To CSV"), self.app.model.export_to_csv, ), ( "actionSaveResults", "Ctrl+S", "", tr("Save Results..."), self.saveResultsTriggered, ), ( "actionInvokeCustomCommand", "Ctrl+Alt+I", "", tr("Invoke Custom Command"), self.app.invokeCustomCommand, ), ] createActions(ACTIONS, self) self.actionDelta.setCheckable(True) self.actionPowerMarker.setCheckable(True) def _setupMenu(self): self.menubar = QMenuBar() self.menubar.setGeometry(QRect(0, 0, 630, 22)) self.menuFile = QMenu(self.menubar) self.menuFile.setTitle(tr("File")) self.menuMark = QMenu(self.menubar) self.menuMark.setTitle(tr("Mark")) self.menuActions = QMenu(self.menubar) self.menuActions.setTitle(tr("Actions")) self.menuColumns = QMenu(self.menubar) self.menuColumns.setTitle(tr("Columns")) self.menuView = QMenu(self.menubar) self.menuView.setTitle(tr("View")) self.menuHelp = QMenu(self.menubar) self.menuHelp.setTitle(tr("Help")) self.setMenuBar(self.menubar) self.menuActions.addAction(self.actionDeleteMarked) self.menuActions.addAction(self.actionMoveMarked) self.menuActions.addAction(self.actionCopyMarked) self.menuActions.addAction(self.actionRemoveMarked) self.menuActions.addAction(self.actionReprioritize) self.menuActions.addSeparator() self.menuActions.addAction(self.actionRemoveSelected) self.menuActions.addAction(self.actionIgnoreSelected) self.menuActions.addAction(self.actionMakeSelectedReference) self.menuActions.addSeparator() self.menuActions.addAction(self.actionOpenSelected) self.menuActions.addAction(self.actionRevealSelected) self.menuActions.addAction(self.actionInvokeCustomCommand) self.menuActions.addAction(self.actionRenameSelected) self.menuMark.addAction(self.actionMarkAll) self.menuMark.addAction(self.actionMarkNone) self.menuMark.addAction(self.actionInvertMarking) self.menuMark.addAction(self.actionMarkSelected) self.menuView.addAction(self.actionPowerMarker) self.menuView.addAction(self.actionDelta) self.menuView.addSeparator() self.menuView.addAction(self.actionDetails) self.menuView.addAction(self.app.actionIgnoreList) self.menuView.addAction(self.app.actionPreferences) self.menuHelp.addAction(self.app.actionShowHelp) self.menuHelp.addAction(self.app.actionOpenDebugLog) self.menuHelp.addAction(self.app.actionAbout) self.menuFile.addAction(self.actionSaveResults) self.menuFile.addAction(self.actionExportToHTML) self.menuFile.addAction(self.actionExportToCSV) self.menuFile.addSeparator() self.menuFile.addAction(self.app.actionQuit) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuMark.menuAction()) self.menubar.addAction(self.menuActions.menuAction()) self.menubar.addAction(self.menuColumns.menuAction()) self.menubar.addAction(self.menuView.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) # Columns menu menu = self.menuColumns self._column_actions = [] for index, (display, visible) in enumerate( self.app.model.result_table.columns.menu_items() ): action = menu.addAction(display) action.setCheckable(True) action.setChecked(visible) action.item_index = index self._column_actions.append(action) menu.addSeparator() action = menu.addAction(tr("Reset to Defaults")) action.item_index = -1 # Action menu actionMenu = QMenu(tr("Actions"), self.menubar) actionMenu.addAction(self.actionDeleteMarked) actionMenu.addAction(self.actionMoveMarked) actionMenu.addAction(self.actionCopyMarked) actionMenu.addAction(self.actionRemoveMarked) actionMenu.addSeparator() actionMenu.addAction(self.actionRemoveSelected) actionMenu.addAction(self.actionIgnoreSelected) actionMenu.addAction(self.actionMakeSelectedReference) actionMenu.addSeparator() actionMenu.addAction(self.actionOpenSelected) actionMenu.addAction(self.actionRevealSelected) actionMenu.addAction(self.actionInvokeCustomCommand) actionMenu.addAction(self.actionRenameSelected) self.actionActions.setMenu(actionMenu) self.actionsButton.setMenu(self.actionActions.menu()) def _setupUi(self): self.setWindowTitle(tr("{} Results").format(self.app.NAME)) self.resize(630, 514) self.centralwidget = QWidget(self) self.verticalLayout = QVBoxLayout(self.centralwidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setSpacing(0) self.actionsButton = QPushButton(tr("Actions")) self.detailsButton = QPushButton(tr("Details")) self.dupesOnlyCheckBox = QCheckBox(tr("Dupes Only")) self.deltaValuesCheckBox = QCheckBox(tr("Delta Values")) self.searchEdit = SearchEdit() self.searchEdit.setMaximumWidth(300) self.horizontalLayout = horizontalWrap( [ self.actionsButton, self.detailsButton, self.dupesOnlyCheckBox, self.deltaValuesCheckBox, None, self.searchEdit, 8, ] ) self.horizontalLayout.setSpacing(8) self.verticalLayout.addLayout(self.horizontalLayout) self.resultsView = ResultsView(self.centralwidget) self.resultsView.setSelectionMode(QAbstractItemView.ExtendedSelection) self.resultsView.setSelectionBehavior(QAbstractItemView.SelectRows) self.resultsView.setSortingEnabled(True) self.resultsView.setWordWrap(False) self.resultsView.verticalHeader().setVisible(False) h = self.resultsView.horizontalHeader() h.setHighlightSections(False) h.setSectionsMovable(True) h.setStretchLastSection(False) h.setDefaultAlignment(Qt.AlignLeft) self.verticalLayout.addWidget(self.resultsView) self.setCentralWidget(self.centralwidget) self._setupActions() self._setupMenu() self.statusbar = QStatusBar(self) self.statusbar.setSizeGripEnabled(True) self.setStatusBar(self.statusbar) self.statusLabel = QLabel(self) self.statusbar.addPermanentWidget(self.statusLabel, 1) if self.app.prefs.resultWindowIsMaximized: self.setWindowState(self.windowState() | Qt.WindowMaximized) else: if self.app.prefs.resultWindowRect is not None: self.setGeometry(self.app.prefs.resultWindowRect) # if not on any screen move to center of default screen # moves to center of closest screen if partially off screen frame = self.frameGeometry() if QDesktopWidget().screenNumber(self) == -1: moveToScreenCenter(self) elif QDesktopWidget().availableGeometry(self).contains(frame) is False: frame.moveCenter(QDesktopWidget().availableGeometry(self).center()) self.move(frame.topLeft()) else: moveToScreenCenter(self) # --- Private def _update_column_actions_status(self): # Update menu checked state menu_items = self.app.model.result_table.columns.menu_items() for action, (display, visible) in zip(self._column_actions, menu_items): action.setChecked(visible) # --- Actions def actionsTriggered(self): self.actionsButton.showMenu() def addToIgnoreListTriggered(self): self.app.model.add_selected_to_ignore_list() def copyTriggered(self): self.app.model.copy_or_move_marked(True) def deleteTriggered(self): self.app.model.delete_marked() def deltaTriggered(self, state=None): # The sender can be either the action or the checkbox, but both have a isChecked() method. self.resultsModel.delta_values = self.sender().isChecked() self.actionDelta.setChecked(self.resultsModel.delta_values) self.deltaValuesCheckBox.setChecked(self.resultsModel.delta_values) def detailsTriggered(self): self.app.show_details() def markAllTriggered(self): self.app.model.mark_all() def markInvertTriggered(self): self.app.model.mark_invert() def markNoneTriggered(self): self.app.model.mark_none() def markSelectedTriggered(self): self.app.model.toggle_selected_mark_state() def moveTriggered(self): self.app.model.copy_or_move_marked(False) def openTriggered(self): self.app.model.open_selected() def powerMarkerTriggered(self, state=None): # see deltaTriggered self.resultsModel.power_marker = self.sender().isChecked() self.actionPowerMarker.setChecked(self.resultsModel.power_marker) self.dupesOnlyCheckBox.setChecked(self.resultsModel.power_marker) def preferencesTriggered(self): self.app.show_preferences() def removeMarkedTriggered(self): self.app.model.remove_marked() def removeSelectedTriggered(self): self.app.model.remove_selected() def renameTriggered(self): index = self.resultsView.selectionModel().currentIndex() # Our index is the current row, with column set to 0. Our filename column is 1 and that's # what we want. index = index.sibling(index.row(), 1) self.resultsView.edit(index) def reprioritizeTriggered(self): dlg = PrioritizeDialog(self, self.app) result = dlg.exec() if result == QDialog.Accepted: dlg.model.perform_reprioritization() def revealTriggered(self): self.app.model.reveal_selected() def saveResultsTriggered(self): title = tr("Select a file to save your results to") files = tr("dupeGuru Results (*.dupeguru)") destination, chosen_filter = QFileDialog.getSaveFileName(self, title, "", files) if destination: if not destination.endswith(".dupeguru"): destination = "{}.dupeguru".format(destination) self.app.model.save_as(destination) self.app.recentResults.insertItem(destination) # --- Events def appWillSavePrefs(self): prefs = self.app.prefs prefs.resultWindowIsMaximized = self.isMaximized() prefs.resultWindowRect = self.geometry() def columnToggled(self, action): index = action.item_index if index == -1: self.app.model.result_table.columns.reset_to_defaults() self._update_column_actions_status() else: visible = self.app.model.result_table.columns.toggle_menu_item(index) action.setChecked(visible) def contextMenuEvent(self, event): self.actionActions.menu().exec_(event.globalPos()) def resultsDoubleClicked(self, modelIndex): self.app.model.open_selected() def resultsSpacePressed(self): self.app.model.toggle_selected_mark_state() def searchChanged(self): self.app.model.apply_filter(self.searchEdit.text()) def closeEvent(self, event): # this saves the location of the results window when it is closed self.appWillSavePrefs()
class MainWindow(QMainWindow): labelsChanged = pyqtSignal(list, name='labelsChanged') def __init__(self): QMainWindow.__init__(self) self.view = QGraphicsView() self.scene = LabelingScene() self.view.setScene(self.scene) self.setCentralWidget(self.view) self.previousImageIdx = 0 self.currentImageIdx = 0 self.setupToolBar() self.setupDockWidgets() self.setupStatusBar() self.showMaximized() self.scene.labelsChanged.connect(self.updateLabels) self.labelsChanged.connect(self.scene.setLabels) self.scene.nextImage.connect(self.nextImage) self.scene.previousImage.connect(self.previousImage) self.scene.copyLabelsFromPrevious.connect( self.copyLabelsFromPreviousImage) def setupToolBar(self): self.toolbar = QToolBar() self.toolbar.addAction(QIcon.fromTheme("document-new"), "Create a new label file", self.newFile) self.toolbar.addAction(QIcon.fromTheme("document-open"), "Open a label file", self.openFile) saveAction = self.toolbar.addAction(QIcon.fromTheme("document-save"), "Save", self.saveFile) saveAction.setShortcut(QKeySequence(QKeySequence.Save)) self.toolbar.addSeparator() self.toolbar.addAction(QIcon.fromTheme("insert-image"), "Add images to dataset", self.addImages) self.toolbar.addSeparator() self.toolbar.addAction(QIcon.fromTheme("go-previous"), "Next image", self.nextImage) self.toolbar.addAction(QIcon.fromTheme("edit-copy"), "Copy labels from previous image", self.copyLabelsFromPreviousImage) self.toolbar.addAction(QIcon.fromTheme("go-next"), "Previous image", self.previousImage) self.addToolBar(self.toolbar) def setupDockWidgets(self): self.fileListWidget = QListView() self.leftDockWidget = QDockWidget() self.leftDockWidget.setWidget(self.fileListWidget) self.fileListModel = QStringListModel(self.fileListWidget) self.fileListWidget.setModel(self.fileListModel) self.fileListWidget.setEditTriggers(QAbstractItemView.NoEditTriggers) self.fileListWidget.doubleClicked.connect( lambda index: self.loadImageAtIndex(index.row())) self.addDockWidget(Qt.LeftDockWidgetArea, self.leftDockWidget) def setupStatusBar(self): self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.currentImageLabel = QLabel() self.statusBar.addPermanentWidget(self.currentImageLabel) self.scene.mouseMoved.connect(lambda p: self.statusBar.showMessage( "Mouse at scene pos {}, {}".format(p.x(), p.y()))) #Here we assume that the image files are stored in the same folder as the labels file. #This is usual practice, maybe in the future we could put images and labels in the same file (HDF5) def newFile(self): imageFileNames = self.normalizeFileNames( QFileDialog.getOpenFileNames( caption="Select image files to label")[0]) self.labelsFileName = QFileDialog.getSaveFileName( caption="Select labels file to save")[0] self.labelsFolder = QFileInfo(self.labelsFileName).absolutePath() print("Creating new labels file with {} images to be labeled".format( len(imageFileNames))) self.labeledImages = [] for imageFileName in imageFileNames: self.labeledImages.append(LabeledImage(imageFileName, [])) self.loadImageAtIndex(0) self.previousImageIdx = 0 self.fileListModel.setStringList(imageFileNames) def normalizeFileNames(self, fileNames): return [QFileInfo(f).fileName() for f in fileNames] def loadImageAtIndex(self, index): if (index < 0) or (index >= len(self.labeledImages)): return self.previousImageIdx = self.currentImageIdx self.currentImageIdx = index self.scene.displayLabeledImage( self.labeledImages[self.currentImageIdx], self.labelsFolder) self.fileListWidget.setCurrentIndex( self.fileListModel.index(self.currentImageIdx, 0)) msg = "{} ({}/{})".format( self.labeledImages[self.currentImageIdx].fileName, self.currentImageIdx + 1, len(self.labeledImages)) self.currentImageLabel.setText(msg) def updateLabels(self, newLabels): self.labeledImages[self.currentImageIdx].labels = newLabels def openFile(self): labelsFileName = QFileDialog.getOpenFileName( caption="Select labels file to load")[0] if labelsFileName == "" or len(labelsFileName) == 0: return self.labelsFileName = labelsFileName self.labelsFolder = QFileInfo(self.labelsFileName).absolutePath() self.labeledImages = readXML(self.labelsFileName) self.fileListModel.setStringList( [s.fileName for s in self.labeledImages]) self.loadImageAtIndex(0) self.previousImageIdx = 0 self.scene.labelsCache = self.allLabelNames() def saveFile(self): writeXML(self.labelsFileName, self.labeledImages) self.statusBar.showMessage("Saved!") def nextImage(self): self.loadImageAtIndex(self.currentImageIdx + 1) def previousImage(self): self.loadImageAtIndex(self.currentImageIdx - 1) def copyLabelsFromPreviousImage(self): self.labeledImages[self.currentImageIdx].labels = self.labeledImages[ self.previousImageIdx].labels self.labelsChanged.emit( self.labeledImages[self.currentImageIdx].labels) def allLabelNames(self): labelNames = [] for labeledImage in self.labeledImages: for label in labeledImage.labels: if label.classLabel not in labelNames: labelNames.append(label.classLabel) return labelNames def addImages(self): imageFileNames = QFileDialog.getOpenFileNames( caption="Select image files to label") if not imageFileNames[0] or len(imageFileNames[0]) == 0: return imageFileNames = imageFileNames[0] labelsDir = QFileInfo(self.labelsFileName).absoluteDir() originDir = QFileInfo(imageFileNames[0]).absoluteDir() #Copy image files to the labels folder if originDir.absolutePath() != labelsDir.absolutePath(): progDialog = QProgressDialog( "Copying image files to the labels folder", "Cancel", 0, len(imageFileNames), self) i = 0 for imageFileName in imageFileNames: progDialog.setValue(i) oldName = QFileInfo(imageFileName).fileName() newPath = labelsDir.absoluteFilePath(oldName) print("Copying {} to {}".format(imageFileName, newPath)) ok = QFile.copy(imageFileName, newPath) QApplication.processEvents() if not ok: print("Error copying {} to {}".format(imageFileName, newPath)) i += 1 progDialog.setValue(len(imageFileNames)) progDialog.close() currentImageFileNames = [s.fileName for s in self.labeledImages] newImgIdx = len(self.labeledImages) for imageFileName in imageFileNames: normalizedFileName = QFileInfo(imageFileName).fileName() if normalizedFileName in currentImageFileNames: print("File {} already in dataset, skipping".format( normalizedFileName)) continue self.labeledImages.append(LabeledImage(normalizedFileName, [])) self.fileListModel.setStringList( [s.fileName for s in self.labeledImages]) self.loadImageAtIndex(newImgIdx) print("Added {} images to dataset".format(len(imageFileNames))) print("New length of labeledImages array {}".format( len(self.labeledImages)))
class View(QMainWindow): def __init__(self, model, controller): super().__init__() self._model = model self._controller = controller self.segmentcursor = False self.togglecolors = {"#1f77b4": "m", "m": "#1f77b4"} ################################################################# # define GUI layout and connect input widgets to external slots # ################################################################# self.setWindowTitle("biopeaks") self.setGeometry(50, 50, 1750, 750) self.setWindowIcon(QIcon(":/python_icon.png")) # figure0 for signal self.figure0 = Figure() self.canvas0 = FigureCanvas(self.figure0) self.ax00 = self.figure0.add_subplot(1, 1, 1) self.ax00.set_frame_on(False) self.figure0.subplots_adjust(left=0.04, right=0.98, bottom=0.25) self.line00 = None self.scat = None self.segmentspan = None # figure1 for marker self.figure1 = Figure() self.canvas1 = FigureCanvas(self.figure1) self.ax10 = self.figure1.add_subplot(1, 1, 1, sharex=self.ax00) self.ax10.get_xaxis().set_visible(False) self.ax10.set_frame_on(False) self.figure1.subplots_adjust(left=0.04, right=0.98) self.line10 = None # figure2 for statistics self.figure2 = Figure() self.canvas2 = FigureCanvas(self.figure2) self.ax20 = self.figure2.add_subplot(3, 1, 1, sharex=self.ax00) self.ax20.get_xaxis().set_visible(False) self.ax20.set_frame_on(False) self.line20 = None self.ax21 = self.figure2.add_subplot(3, 1, 2, sharex=self.ax00) self.ax21.get_xaxis().set_visible(False) self.ax21.set_frame_on(False) self.line21 = None self.ax22 = self.figure2.add_subplot(3, 1, 3, sharex=self.ax00) self.ax22.get_xaxis().set_visible(False) self.ax22.set_frame_on(False) self.line22 = None self.figure2.subplots_adjust(left=0.04, right=0.98) # navigation bar self.navitools = CustomNavigationToolbar(self.canvas0, self) # peak editing self.editcheckbox = QCheckBox("editable", self) self.editcheckbox.stateChanged.connect(self._model.set_peakseditable) # peak saving batch self.savecheckbox = QCheckBox("save during batch processing", self) self.savecheckbox.stateChanged.connect(self._model.set_savebatchpeaks) # peak auto-correction batch self.correctcheckbox = QCheckBox("correct during batch processing", self) self.correctcheckbox.stateChanged.connect( self._model.set_correctbatchpeaks) # selecting stats for saving self.periodcheckbox = QCheckBox("period", self) self.periodcheckbox.stateChanged.connect( lambda: self.select_stats("period")) self.ratecheckbox = QCheckBox("rate", self) self.ratecheckbox.stateChanged.connect( lambda: self.select_stats("rate")) self.tidalampcheckbox = QCheckBox("tidal amplitude", self) self.tidalampcheckbox.stateChanged.connect( lambda: self.select_stats("tidalamp")) # channel selection self.sigchanmenulabel = QLabel("biosignal") self.sigchanmenu = QComboBox(self) self.sigchanmenu.addItem("A1") self.sigchanmenu.addItem("A2") self.sigchanmenu.addItem("A3") self.sigchanmenu.addItem("A4") self.sigchanmenu.addItem("A5") self.sigchanmenu.addItem("A6") self.sigchanmenu.currentTextChanged.connect(self._model.set_signalchan) # initialize with default value self._model.set_signalchan(self.sigchanmenu.currentText()) self.markerchanmenulabel = QLabel("marker") self.markerchanmenu = QComboBox(self) self.markerchanmenu.addItem("none") self.markerchanmenu.addItem("I1") self.markerchanmenu.addItem("I2") self.markerchanmenu.addItem("A1") self.markerchanmenu.addItem("A2") self.markerchanmenu.addItem("A3") self.markerchanmenu.addItem("A4") self.markerchanmenu.addItem("A5") self.markerchanmenu.addItem("A6") self.markerchanmenu.currentTextChanged.connect( self._model.set_markerchan) # initialize with default value self._model.set_markerchan(self.markerchanmenu.currentText()) # processing mode (batch or single file) self.batchmenulabel = QLabel("mode") self.batchmenu = QComboBox(self) self.batchmenu.addItem("single file") self.batchmenu.addItem("multiple files") self.batchmenu.currentTextChanged.connect(self._model.set_batchmode) self.batchmenu.currentTextChanged.connect(self.toggle_options) # initialize with default value self._model.set_batchmode(self.batchmenu.currentText()) self.toggle_options(self.batchmenu.currentText()) # modality selection self.modmenulabel = QLabel("modality") self.modmenu = QComboBox(self) self.modmenu.addItem("ECG") self.modmenu.addItem("PPG") self.modmenu.addItem("RESP") self.modmenu.currentTextChanged.connect(self._model.set_modality) self.modmenu.currentTextChanged.connect(self.toggle_options) # initialize with default value self._model.set_modality(self.modmenu.currentText()) self.toggle_options(self.modmenu.currentText()) # segment selection; this widget can be openend / set visible from # the menu and closed from within itself (see mapping of segmentermap); # it provides utilities to select a segment from the signal self.segmentermap = QSignalMapper(self) self.segmenter = QDockWidget("select a segment", self) # disable closing such that widget can only be closed by confirming # selection or custom button self.segmenter.setFeatures(QDockWidget.NoDockWidgetFeatures) # Limit number of decimals to four. regex = QRegExp("[0-9]*\.?[0-9]{4}") validator = QRegExpValidator(regex) self.startlabel = QLabel("start") self.startedit = QLineEdit() self.startedit.setValidator(validator) self.endlabel = QLabel("end") self.endedit = QLineEdit() self.endedit.setValidator(validator) segmentfromcursor = QAction(QIcon(":/mouse_icon.png"), "select with mouse", self) segmentfromcursor.triggered.connect(self.enable_segmentedit) self.startedit.addAction(segmentfromcursor, 1) self.endedit.addAction(segmentfromcursor, 1) self.previewedit = QPushButton("preview segment") lambdafn = lambda: self._model.set_segment( [self.startedit.text(), self.endedit.text()]) self.previewedit.clicked.connect(lambdafn) self.confirmedit = QPushButton("confirm segment") self.confirmedit.clicked.connect(self._controller.segment_signal) self.confirmedit.clicked.connect(self.segmentermap.map) self.segmentermap.setMapping(self.confirmedit, 0) self.abortedit = QPushButton("abort segmentation") self.abortedit.clicked.connect(self.segmentermap.map) # reset the segment to None self.segmentermap.setMapping(self.abortedit, 2) self.segmenterlayout = QFormLayout() self.segmenterlayout.addRow(self.startlabel, self.startedit) self.segmenterlayout.addRow(self.endlabel, self.endedit) self.segmenterlayout.addRow(self.previewedit) self.segmenterlayout.addRow(self.confirmedit) self.segmenterlayout.addRow(self.abortedit) self.segmenterwidget = QWidget() self.segmenterwidget.setLayout(self.segmenterlayout) self.segmenter.setWidget(self.segmenterwidget) self.segmenter.setVisible(False) self.segmenter.setAllowedAreas(Qt.RightDockWidgetArea) self.addDockWidget(Qt.RightDockWidgetArea, self.segmenter) # set up menubar menubar = self.menuBar() # signal menu signalmenu = menubar.addMenu("biosignal") openSignal = QAction("load", self) openSignal.triggered.connect(self._controller.get_fpaths) signalmenu.addAction(openSignal) segmentSignal = QAction("select segment", self) segmentSignal.triggered.connect(self.segmentermap.map) self.segmentermap.setMapping(segmentSignal, 1) signalmenu.addAction(segmentSignal) self.segmentermap.mapped.connect(self.toggle_segmenter) saveSignal = QAction("save", self) saveSignal.triggered.connect(self._controller.get_wpathsignal) signalmenu.addAction(saveSignal) # peak menu peakmenu = menubar.addMenu("peaks") findPeaks = QAction("find", self) findPeaks.triggered.connect(self._controller.find_peaks) peakmenu.addAction(findPeaks) autocorrectPeaks = QAction("autocorrect", self) autocorrectPeaks.triggered.connect(self._controller.autocorrect_peaks) peakmenu.addAction(autocorrectPeaks) savePeaks = QAction("save", self) savePeaks.triggered.connect(self._controller.get_wpathpeaks) peakmenu.addAction(savePeaks) loadPeaks = QAction("load", self) loadPeaks.triggered.connect(self._controller.get_rpathpeaks) peakmenu.addAction(loadPeaks) # stats menu statsmenu = menubar.addMenu("statistics") calculateStats = QAction("calculate", self) calculateStats.triggered.connect(self._controller.calculate_stats) statsmenu.addAction(calculateStats) saveStats = QAction("save", self) saveStats.triggered.connect(self._controller.get_wpathstats) statsmenu.addAction(saveStats) # set up status bar to display error messages and current file path self.statusBar = QStatusBar() self.setStatusBar(self.statusBar) self.progressBar = QProgressBar(self) self.progressBar.setRange(0, 1) self.statusBar.addPermanentWidget(self.progressBar) self.currentFile = QLabel() self.statusBar.addPermanentWidget(self.currentFile) # set up the central widget containing the plot and navigationtoolbar self.centwidget = QWidget() self.setCentralWidget(self.centwidget) # connect canvas0 to keyboard and mouse input for peak editing; # only widgets (e.g. canvas) that currently have focus capture # keyboard input: "You must enable keyboard focus for a widget if # it processes keyboard events." self.canvas0.setFocusPolicy(Qt.ClickFocus) self.canvas0.setFocus() self.canvas0.mpl_connect("key_press_event", self._controller.edit_peaks) self.canvas0.mpl_connect("button_press_event", self.get_xcursor) # arrange the three figure canvases in splitter object self.splitter = QSplitter(Qt.Vertical) # setting opaque resizing to false is important, since resizing gets # very slow otherwise once axes are populated self.splitter.setOpaqueResize(False) self.splitter.addWidget(self.canvas0) self.splitter.addWidget(self.canvas1) self.splitter.addWidget(self.canvas2) # define GUI layout self.vlayout0 = QVBoxLayout(self.centwidget) self.vlayout1 = QVBoxLayout() self.vlayoutA = QFormLayout() self.vlayoutB = QFormLayout() self.vlayoutC = QVBoxLayout() self.vlayoutD = QVBoxLayout() self.hlayout0 = QHBoxLayout() self.hlayout1 = QHBoxLayout() self.optionsgroupA = QGroupBox("processing options") self.vlayoutA.addRow(self.modmenulabel, self.modmenu) self.vlayoutA.addRow(self.batchmenulabel, self.batchmenu) self.optionsgroupA.setLayout(self.vlayoutA) self.optionsgroupB = QGroupBox("channels") self.vlayoutB.addRow(self.sigchanmenulabel, self.sigchanmenu) self.vlayoutB.addRow(self.markerchanmenulabel, self.markerchanmenu) self.optionsgroupB.setLayout(self.vlayoutB) self.optionsgroupC = QGroupBox("peak options") self.vlayoutC.addWidget(self.editcheckbox) self.vlayoutC.addWidget(self.savecheckbox) self.vlayoutC.addWidget(self.correctcheckbox) self.optionsgroupC.setLayout(self.vlayoutC) self.optionsgroupD = QGroupBox("select statistics for saving") self.vlayoutD.addWidget(self.periodcheckbox) self.vlayoutD.addWidget(self.ratecheckbox) self.vlayoutD.addWidget(self.tidalampcheckbox) self.optionsgroupD.setLayout(self.vlayoutD) self.vlayout1.addWidget(self.optionsgroupA) self.vlayout1.addWidget(self.optionsgroupB) self.vlayout1.addWidget(self.optionsgroupC) self.vlayout1.addWidget(self.optionsgroupD) self.hlayout0.addLayout(self.vlayout1) self.hlayout0.addWidget(self.splitter) self.hlayout0.setStretch(0, 1) self.hlayout0.setStretch(1, 15) self.vlayout0.addLayout(self.hlayout0) self.hlayout1.addWidget(self.navitools) self.vlayout0.addLayout(self.hlayout1) ############################################## # connect output widgets to external signals # ############################################## self._model.signal_changed.connect(self.plot_signal) self._model.marker_changed.connect(self.plot_marker) self._model.peaks_changed.connect(self.plot_peaks) self._model.period_changed.connect(self.plot_period) self._model.rate_changed.connect(self.plot_rate) self._model.tidalamp_changed.connect(self.plot_tidalamp) self._model.path_changed.connect(self.display_path) self._model.segment_changed.connect(self.plot_segment) self._model.status_changed.connect(self.display_status) self._model.progress_changed.connect(self.display_progress) self._model.model_reset.connect(self.reset_plot) ########### # methods # ########### def plot_signal(self, value): self.ax00.clear() self.ax00.relim() # reset navitools history self.navitools.update() self.line00 = self.ax00.plot(self._model.sec, value, zorder=1) self.ax00.set_xlabel("seconds", fontsize="large", fontweight="heavy") self.canvas0.draw() # print("plot_signal listening") # print(self.ax0.collections, self.ax0.patches, self.ax0.artists) def plot_peaks(self, value): # self.scat is listed in ax.collections if self.ax00.collections: self.ax00.collections[0].remove() self.scat = self.ax00.scatter(self._model.sec[value], self._model.signal[value], c="m", zorder=2) self.canvas0.draw() # print("plot_peaks listening") # print(self.ax0.collections, self.ax0.patches, self.ax0.artists) def plot_segment(self, value): # If an invalid signal has been selected reset the segmenter interface. if value is None: self.toggle_segmenter(1) return if self.ax00.patches: # self.segementspan is listed in ax.patches self.ax00.patches[0].remove() self.segmentspan = self.ax00.axvspan(value[0], value[1], color="m", alpha=0.25) self.canvas0.draw() self.confirmedit.setEnabled(True) # print(self.ax0.collections, self.ax0.patches, self.ax0.artists) def plot_marker(self, value): self.ax10.clear() self.ax10.relim() self.line10 = self.ax10.plot(value[0], value[1]) self.canvas1.draw() # print("plot_marker listening") def plot_period(self, value): self.ax20.clear() self.ax20.relim() self.navitools.home() if self._model.savestats["period"]: self.line20 = self.ax20.plot(self._model.sec, value, c="m") else: self.line20 = self.ax20.plot(self._model.sec, value) self.ax20.set_ylim(bottom=min(value), top=max(value)) self.ax20.set_title("period", pad=0, fontweight="heavy") self.ax20.grid(True, axis="y") self.navitools.update() self.canvas2.draw() # print("plot_period listening") def plot_rate(self, value): self.ax21.clear() self.ax21.relim() self.navitools.home() if self._model.savestats["rate"]: self.line21 = self.ax21.plot(self._model.sec, value, c="m") else: self.line21 = self.ax21.plot(self._model.sec, value) self.ax21.set_ylim(bottom=min(value), top=max(value)) self.ax21.set_title("rate", pad=0, fontweight="heavy") self.ax21.grid(True, axis="y") self.navitools.update() self.canvas2.draw() # print("plot_rate listening") def plot_tidalamp(self, value): self.ax22.clear() self.ax22.relim() self.navitools.home() if self._model.savestats["tidalamp"]: self.line22 = self.ax22.plot(self._model.sec, value, c="m") else: self.line22 = self.ax22.plot(self._model.sec, value) self.ax22.set_ylim(bottom=min(value), top=max(value)) self.ax22.set_title("amplitude", pad=0, fontweight="heavy") self.ax22.grid(True, axis="y") self.navitools.update() self.canvas2.draw() # print("plot_tidalamp listening") def display_path(self, value): self.currentFile.setText(value) def display_status(self, status): # display status until new status is set self.statusBar.showMessage(status) def display_progress(self, value): # if value is 0, the progressbar indicates a busy state self.progressBar.setRange(0, value) def toggle_segmenter(self, value): if self._model.loaded: # Open segmenter when called from signalmenu or clear segmenter # upon selection of invalid segment. if value == 1: self.segmenter.setVisible(True) self.confirmedit.setEnabled(False) self.startedit.clear() self.endedit.clear() if self.ax00.patches: self.ax00.patches[0].remove() self.canvas0.draw() # Close segmenter after segment has been confirmed. elif value == 0: self.segmenter.setVisible(False) if self.ax00.patches: self.ax00.patches[0].remove() self.canvas0.draw() # Close segmenter after segmentation has been aborted (reset # segment). elif value == 2: self._model.set_segment( [0, 0]) # This will reset the model to None self.segmenter.setVisible(False) if self.ax00.patches: self.ax00.patches[0].remove() self.canvas0.draw() def enable_segmentedit(self): # disable peak editing to avoid interference self.editcheckbox.setCheckState(0) if self.startedit.hasFocus(): self.segmentcursor = "start" elif self.endedit.hasFocus(): self.segmentcursor = "end" def get_xcursor(self, event): # event.button 1 corresponds to left mouse button if event.button == 1: # limit number of decimal places to two if self.segmentcursor == "start": self.startedit.selectAll() self.startedit.insert("{:.2f}".format(event.xdata)) elif self.segmentcursor == "end": self.endedit.selectAll() self.endedit.insert("{:.2f}".format(event.xdata)) # disable segment cursor again after value has been set self.segmentcursor = False def select_stats(self, event): """ select or deselect statistics to be saved; toggle boolean with xor operator ^=, toggle color with dictionary """ self._model.savestats[event] ^= True line = None if event == "period": if self.line20: line = self.line20[0] elif event == "rate": if self.line21: line = self.line21[0] elif event == "tidalamp": if self.line22: line = self.line22[0] if line: line.set_color(self.togglecolors[line.get_color()]) self.canvas2.draw() def toggle_options(self, event): if event in ["ECG", "PPG"]: self.tidalampcheckbox.setEnabled(False) self.tidalampcheckbox.setChecked(False) self.ax22.set_visible(False) self.canvas2.draw() elif event == "RESP": self.tidalampcheckbox.setEnabled(True) self.ax22.set_visible(True) self.canvas2.draw() elif event == "multiple files": self.editcheckbox.setEnabled(False) self.editcheckbox.setChecked(False) self.savecheckbox.setEnabled(True) self.correctcheckbox.setEnabled(True) self.markerchanmenu.setEnabled(False) elif event == "single file": self.editcheckbox.setEnabled(True) self.markerchanmenu.setEnabled(True) self.savecheckbox.setEnabled(False) self.savecheckbox.setChecked(False) self.correctcheckbox.setEnabled(False) self.correctcheckbox.setChecked(False) def reset_plot(self): self.ax00.clear() self.ax00.relim() self.line00 = None self.scat = None self.segmentspan = None self.ax10.clear() self.ax10.relim() self.line10 = None self.ax20.clear() self.ax20.relim() self.line20 = None self.ax21.clear() self.ax21.relim() self.line21 = None self.ax22.clear() self.ax22.relim() self.line22 = None self.canvas0.draw() self.canvas1.draw() self.canvas2.draw() self.navitools.update() self.currentFile.clear()
class MainWindow(QMainWindow): initialized = pyqtSignal() centralwidgetresized = pyqtSignal() def __init__(self, media_player, stylesheet, flags=None): QMainWindow.__init__(self, flags) self._window_state = None self.qapp = QApplication.instance() initialize_style(self.qapp, stylesheet) self.media_player = media_player self.setDockNestingEnabled(True) self.create_interface() self.create_status_bar() self.create_playback_components() self.create_other_components() self.create_gui_layout() self.create_window_shortcuts() self.initialized.emit() def load_media(self, paths): self.playlist_widget.add_media(paths) def create_status_bar(self): self.status_bar = QStatusBar(parent=self) self.connect_status_label = ConnectStatusLabel(parent=self.status_bar, socket=self.socket) self.fullscreen_status_label = FullscreenStatusLabel( parent=self.status_bar, fullscreen_mngr=self.fullscreen_mngr) self.orientation_status_label = OrientationStatusLabel( viewpoint_mngr=self.viewpoint_mngr, parent=self.status_bar) self.status_bar.addPermanentWidget(self.fullscreen_status_label) self.status_bar.addPermanentWidget(self.connect_status_label) self.status_bar.addPermanentWidget(self.orientation_status_label) self.setStatusBar(self.status_bar) def create_interface(self): self.socket = AutoReconnectSocket() self.io_ctrlr = IOController(socket=self.socket) self.viewpoint_mngr = ViewpointManager(io_ctrlr=self.io_ctrlr, media_player=self.media_player) self.loop_mode_mngr = LoopModeManager(parent=self) self.listplayer = MediaListPlayer( viewpoint_mngr=self.viewpoint_mngr, loop_mode_mngr=self.loop_mode_mngr, media_player=self.media_player, ) self.listplayer.newframe.connect(self.viewpoint_mngr.on_newframe) self.frame_size_mngr = FrameSizeManager( main_win=self, viewpoint_mngr=self.viewpoint_mngr, listplayer=self.listplayer, ) self.media_player_content_frame = MediaPlayerContentFrame( main_win=self, frame_size_mngr=self.frame_size_mngr, media_player=self.media_player, ) self.setCentralWidget(self.media_player_content_frame) self.zoom_ctrl_mngr = ZoomControlManager( main_win=self, frame_size_mngr=self.frame_size_mngr, media_player=self.media_player, ) self.fullscreen_mngr = FullscreenManager( main_win=self, main_content_frame=self.media_player_content_frame, viewpoint_mngr=self.viewpoint_mngr, ) def create_playback_components(self): self.playback_ctrls_slider = FrameResolutionTimeSlider( parent=self, listplayer=self.listplayer, media_player=self.media_player) self.vol_mngr = VolumeManager(parent=self, listplayer=self.listplayer, media_player=self.media_player) self.play_actions = PlayActions(parent=self, listplayer=self.listplayer, media_player=self.media_player) self.playlist_widget = PlaylistWidget( listplayer=self.listplayer, play_ctrls=self.play_actions, parent=self, ) self.dockable_playlist = DockablePlaylist( parent=self, playlist_widget=self.playlist_widget) self.toggle_playlist_act = self.dockable_playlist.toggleViewAction() self.playback_mode_act = PlaybackModeAction( parent=self, loop_mode_mngr=self.loop_mode_mngr) self.always_on_top_act = AlwaysOnTopAction(main_win=self) self.zoom_in_act = ZoomInAction(parent=self, zoom_ctrl_mngr=self.zoom_ctrl_mngr) self.zoom_out_act = ZoomOutAction(parent=self, zoom_ctrl_mngr=self.zoom_ctrl_mngr) self.open_settings_act = OpenClientSettingsDialogAction(main_win=self) self.open_adjustments_act = OpenMediaPlayerAdjustmentsWindowAction( main_win=self, media_player=self.media_player) self.open_player_prefs_act = OpenMediaPlayerPreferencesWindowAction( main_win=self, media_player=self.media_player) def create_other_components(self): self.open_media_menu = OpenMediaMenu( parent=self, playlist_widget=self.playlist_widget) self.frame_scale_menu = FrameZoomMenu( main_win=self, zoom_ctrl_mngr=self.zoom_ctrl_mngr, listplayer=self.listplayer, media_player=self.media_player, ) self.fullscreen_menu = FullscreenMenu( main_win=self, fullscreen_mngr=self.fullscreen_mngr) self.vol_popup_bttn = VolumePopupButton(parent=self, vol_mngr=self.vol_mngr) self.connect_wide_button_builder = ConnectWideButtonBuilder( parent=self, socket=self.socket) def create_gui_layout(self): # self.setDockOptions(DockOption.AllowNestedDocks | DockOption.AllowTabbedDocks) self.setDockNestingEnabled(True) # self.setUnifiedTitleAndToolBarOnMac(False) # self.setTabbedDock(True) self.media_toolbar = ToolBar( title="Media", objects=[ self.open_media_menu, ToolBar.Separator, self.toggle_playlist_act ], parent=self, collapsible=True, icon_size=32, ) self.view_toolbar = ToolBar( title="View", objects=[ self.frame_scale_menu, self.always_on_top_act, self.fullscreen_menu, ], parent=self, collapsible=True, icon_size=32, ) self.connect_toolbar = ToolBar( title="Connect", objects=[self.connect_wide_button_builder, self.open_settings_act], parent=self, collapsible=True, icon_size=32, ) self.connect_toolbar.setObjectName("borderedbuttons") self.button_bar_widget = QWidget(self) self.button_bar_widget.setContentsMargins(0, 0, 0, 0) self.button_bar_widget.setLayout(QGridLayout()) self.button_bar_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.button_bar_widget.layout().addWidget(self.view_toolbar, 0, 0, 1, 1, Qt.AlignLeft) self.button_bar_widget.layout().addWidget(self.connect_toolbar, 0, 1, 1, 1, Qt.AlignCenter) self.button_bar_widget.layout().addWidget(self.media_toolbar, 0, 2, 1, 1, Qt.AlignRight) self.addToolBar( Qt.TopToolBarArea, ToolBar("Toolbar", parent=self, objects=[self.button_bar_widget]), ) self.playback_slider_widget = QWidget(self) self.playback_slider_widget.setContentsMargins(0, 0, 0, 0) self.playback_slider_widget.setLayout(QGridLayout()) self.playback_slider_widget.layout().addWidget( self.playback_ctrls_slider, 0, 0, 1, -1, Qt.AlignTop) self.playback_bttns_left = ToolBar( title="Left Control", objects=[self.open_player_prefs_act, self.open_adjustments_act], collapsible=False, parent=self, icon_size=32, ) self.playback_bttns_middle = ToolBar( title="Playback Controls", objects=self.play_actions.actions(), parent=self, collapsible=False, icon_size=60, ) self.playback_bttns_right = ToolBar( title="Right Controls", objects=[self.playback_mode_act, self.vol_popup_bttn], collapsible=False, parent=self, icon_size=32, ) self.playback_ctrls_widget = QWidget(self) self.playback_ctrls_widget.setContentsMargins(0, 0, 0, 0) self.playback_ctrls_widget.setLayout( QGridLayout(self.playback_ctrls_widget)) self.playback_ctrls_widget.layout().addWidget( self.playback_slider_widget, 0, 0, 1, -1, Qt.AlignTop) self.playback_ctrls_widget.layout().addWidget( self.playback_bttns_left, 1, 0, 1, 1, Qt.AlignHCenter | Qt.AlignVCenter) self.playback_ctrls_widget.layout().addWidget( self.playback_bttns_middle, 1, 1, 1, 1, Qt.AlignHCenter | Qt.AlignVCenter) self.playback_ctrls_widget.layout().addWidget( self.playback_bttns_right, 1, 2, 1, 1, Qt.AlignJustify | Qt.AlignVCenter) self.playback_ctrls_dock_widget = DockableWidget( title="Playback", parent=self, widget=self.playback_ctrls_widget, w_titlebar=False, ) self.addDockWidget(Qt.RightDockWidgetArea, self.dockable_playlist) self.addDockWidget(Qt.BottomDockWidgetArea, self.playback_ctrls_dock_widget) def create_window_shortcuts(self): # Close window self.shortcut_exit = QtWidgets.QShortcut(QtGui.QKeySequence.Close, self, self.close) # Zoom in self.shortcut_zoom_in = QShortcut(QtGui.QKeySequence.ZoomIn, self, self.zoom_ctrl_mngr.zoom_in) # Zoom out self.shortcut_zoom_out = QShortcut(QtGui.QKeySequence.ZoomOut, self, self.zoom_ctrl_mngr.zoom_out) # Exit fullscreen self.ctrl_w = QtWidgets.QShortcut(QtGui.QKeySequence.Cancel, self, self.fullscreen_mngr.stop) # Play media self.shortcut_play = QtWidgets.QShortcut( QtGui.QKeySequence(Qt.Key_Space), self, self.play_actions.play_pause.trigger) def _screen_size_threshold_filter(self, target_width, target_height): main_win_geo = self.geometry() screen = self.qapp.screenAt(main_win_geo.center()) screen_geo = screen.geometry() screen_w = screen_geo.width() screen_h = screen_geo.height() w = target_width if target_width < screen_w else screen_w h = target_height if target_height < screen_h else screen_h return w, h def _get_win_size(self, media_w, media_h, scale) -> Tuple[int, int]: """Calculate total window resize values from current compoment displacement""" layout_h = self.layout().totalSizeHint().height() return media_w * scale, media_h * scale + layout_h def resize_to_media(self, media_w, media_h, scale): playlist_is_visible = self.dockable_playlist.isVisible() if playlist_is_visible: self.dockable_playlist.setVisible(False) win_w, win_h = self._get_win_size(media_w, media_h, scale) self.resize(win_w, win_h) if playlist_is_visible: self.dockable_playlist.setVisible(True) def showEvent(self, e): scale = self.frame_size_mngr.get_media_scale() media_w, media_h = self.frame_size_mngr.get_media_size() self.resize_to_media(media_w, media_h, scale) return super().showEvent(e) def sizeHint(self): try: return self._size_hint except AttributeError: scale = self.frame_size_mngr.get_media_scale() media_w, media_h = self.frame_size_mngr.get_media_size() self._size_hint = QSize( *self._get_win_size(media_w, media_h, scale)) finally: return self._size_hint def closeEvent(self, e): self.fullscreen_mngr.stop()
class UIMainWindow(QMainWindow): '''UI Frame''' open_file = pyqtSignal() reload_file = pyqtSignal() json_sl_filler = pyqtSignal() json_tl_filler = pyqtSignal() json_sl_refiller = pyqtSignal() json_tl_refiller = pyqtSignal() load_next_version = pyqtSignal() write_to_json = pyqtSignal() def __init__(self, parent=None): super(UIMainWindow, self).__init__(parent) currentDir = os.getcwd() dataDir = os.path.join(currentDir, "app_data") workFileDir = os.path.join(dataDir, "workfiles") self._outPutDir = os.path.join(currentDir, "savedfiles") self._interface_lang_file = os.path.join( workFileDir, 'interface_language_setting.txt') self._interface_lang_dict = os.path.join( workFileDir, 'interface_language_dict.json') self.fc_lg, self.fc_dict = self.set_lang() self._prompt_frame = QGroupBox( self.fc_dict["frame_prompt"][self.fc_lg]) self._prompt_frame.setAlignment(Qt.AlignCenter) self.initial_prompt = self.fc_dict["pmt_1_start"][ self.fc_lg] + "\n" + self.fc_dict["pmt_1_a"][ self.fc_lg] + "\n" + self.fc_dict["pmt_1_b"][self.fc_lg] self._prompt_2 = self.fc_dict["pmt_2_start"][ self.fc_lg] + "\n " + self.fc_dict["pmt_2_a"][ self.fc_lg] + "\n " + self.fc_dict["pmt_2_b"][self.fc_lg] self._prompt_3 = self.fc_dict["pmt_3_start"][ self.fc_lg] + "\n " + self.fc_dict["pmt_3_a"][self.fc_lg] self._prompt_5 = self.fc_dict["pmt_5"][self.fc_lg] self._prompt_frame_layout = QHBoxLayout() self._promptBox = QLabel() self._promptBox.setText(self.initial_prompt) self._promptBox.setFixedHeight(80) self._promptBox.setWordWrap(True) self._prompt_frame_layout.addWidget(self._promptBox) self._prompt_frame.setLayout(self._prompt_frame_layout) self._fileloader_frame = QGroupBox( self.fc_dict["frame_load"][self.fc_lg]) self._fileloader_frame.setAlignment(Qt.AlignCenter) self._fileloader_src_layout = QHBoxLayout() self._file_openBox = QLineEdit() self._file_openBox.setFixedWidth(500) self._file_openBox.setReadOnly(True) self._file_openButton = QPushButton() self._file_openButton.setText(self.fc_dict["open_s"][self.fc_lg]) self._file_openButton.setFixedWidth(80) self._file_openButton.clicked[bool].connect(self.open_file) self._file_reloadButton = QPushButton( self.fc_dict["r_load"][self.fc_lg]) self._file_reloadButton.setFixedWidth(80) self._file_reloadButton.clicked[bool].connect(self.reload_file) self._fileloader_src_layout.addWidget(self._file_openBox) self._fileloader_src_layout.addWidget(self._file_openButton) self._fileloader_src_layout.addWidget(self._file_reloadButton) self._fileloader_opt_layout = QGridLayout() self._file_type_label = QLabel(self.fc_dict["f_type"][self.fc_lg]) self._file_type_label.setFixedWidth(60) self._file_type_box = QComboBox() self._file_type_box.setFixedWidth(100) self._file_type_box.addItem('txt') self._file_type_box.addItem('docx') self._file_type_box.addItem('xlsx') self._file_bind_label = QLabel(self.fc_dict["bi_loc"][self.fc_lg]) self._file_bind_label.setFixedWidth(80) self._file_bind_box = QComboBox() self._file_bind_box.setFixedWidth(120) self._file_bind_box.addItem(self.fc_dict["bind_sig"][self.fc_lg]) self._file_bind_box.addItem(self.fc_dict["bind_mul"][self.fc_lg]) self._file_num_label = QLabel(self.fc_dict["f_num"][self.fc_lg]) self._file_num_label.setFixedWidth(80) self._file_num_box = QDoubleSpinBox() self._file_num_box.setFixedWidth(80) self._file_num_box.setMinimum(1) self._file_num_box.setDecimals(0) self._file_num_box.setDisabled(True) self._file_portion_label = QLabel(self.fc_dict["bi_rate"][self.fc_lg]) self._file_portion_label.setFixedWidth(80) self._file_portion_label.setStatusTip( self.fc_dict["tip_portion"][self.fc_lg]) self._file_portion_box = QDoubleSpinBox() self._file_portion_box.setDisabled(True) self._file_portion_box.setFixedWidth(80) self._file_portion_box.setMinimum(0) self._file_portion_box.setDecimals(0) self._file_portion_box.setPrefix("1:") self._file_portion_box.setValue(1) self._file_pos_label = QLabel(self.fc_dict["bi_pos"][self.fc_lg]) self._file_pos_label.setFixedWidth(80) self._file_pos_box = QComboBox() self._file_pos_box.setDisabled(True) self._file_pos_box.setFixedWidth(120) self._file_pos_box.addItem(self.fc_dict["u_d"][self.fc_lg]) self._file_pos_box.addItem(self.fc_dict["l_r"][self.fc_lg]) self._file_pos_box.addItem(self.fc_dict["bi-sep"][self.fc_lg]) self._fileloader_mark_layout = QGridLayout() self._fileloader_mark_label = QLabel( self.fc_dict["conc_mk"][self.fc_lg]) self._fileloader_mark_label.setFixedWidth(80) self._file_num_mark_box = QCheckBox(self.fc_dict["l_num"][self.fc_lg]) self._file_num_mark_box.setFixedWidth(80) self._file_num_mark_box.setStatusTip( self.fc_dict["tip_num"][self.fc_lg]) self._file_num_mark_box.clicked[bool].connect(self.mark_num) self._file_num_mark_box.setDisabled(True) self._file_chapt_num_box = QCheckBox( self.fc_dict["title_ch"][self.fc_lg]) self._file_chapt_num_box.setFixedWidth(100) self._file_chapt_num_box.setStatusTip( self.fc_dict["tip_format"][self.fc_lg]) self._file_chapt_num_box.clicked[bool].connect(self.mark_chapter) self._file_chapt_num_box.setDisabled(True) self._file_tab_mark_box = QCheckBox(self.fc_dict["mk_tab"][self.fc_lg]) self._file_tab_mark_box.setFixedWidth(100) self._file_tab_mark_box.setStatusTip( self.fc_dict["tip_tab"][self.fc_lg]) self._file_tab_mark_box.clicked[bool].connect(self.mark_tab) self._file_tab_mark_box.setDisabled(True) self._file_cuc_mark_box = QCheckBox(self.fc_dict["mk_seg"][self.fc_lg]) self._file_cuc_mark_box.setFixedWidth(100) self._file_cuc_mark_box.setStatusTip( self.fc_dict["tip_seg"][self.fc_lg]) self._file_cuc_mark_box.clicked[bool].connect(self.mark_cuc) self._file_cuc_mark_box.setDisabled(True) self._file_table_mark_box = QCheckBox( self.fc_dict["mk_table"][self.fc_lg]) self._file_table_mark_box.setFixedWidth(100) self._file_table_mark_box.setStatusTip( self.fc_dict["tip_table"][self.fc_lg]) self._file_table_mark_box.clicked[bool].connect(self.mark_table) self._file_table_mark_box.setDisabled(True) self._fileloader_mark_layout.addWidget(self._fileloader_mark_label, 0, 0) self._fileloader_mark_layout.addWidget(self._file_num_mark_box, 0, 1) self._fileloader_mark_layout.addWidget(self._file_chapt_num_box, 0, 2) self._fileloader_mark_layout.addWidget(self._file_tab_mark_box, 0, 3) self._fileloader_mark_layout.addWidget(self._file_cuc_mark_box, 0, 4) self._fileloader_mark_layout.addWidget(self._file_table_mark_box, 0, 5) self._fileloader_opt_layout.addWidget(self._file_type_label, 0, 0) self._fileloader_opt_layout.addWidget(self._file_type_box, 0, 1) self._fileloader_opt_layout.addWidget(self._file_bind_label, 0, 2) self._fileloader_opt_layout.addWidget(self._file_bind_box, 0, 3) self._fileloader_opt_layout.addWidget(self._file_pos_label, 0, 4) self._fileloader_opt_layout.addWidget(self._file_pos_box, 0, 5) self._fileloader_opt_layout.addWidget(self._file_num_label, 0, 6) self._fileloader_opt_layout.addWidget(self._file_num_box, 0, 7) self._fileloader_opt_layout.addLayout(self._fileloader_mark_layout, 1, 0, 1, 6) self._fileloader_opt_layout.addWidget(self._file_portion_label, 1, 6) self._fileloader_opt_layout.addWidget(self._file_portion_box, 1, 7) self._fileloader_frame_layout = QVBoxLayout() self._fileloader_frame_layout.addLayout(self._fileloader_opt_layout) self._fileloader_frame_layout.addLayout(self._fileloader_mark_layout) self._fileloader_frame_layout.addLayout(self._fileloader_src_layout) self._fileloader_frame_layout.setAlignment(Qt.AlignCenter) self._fileloader_frame.setLayout(self._fileloader_frame_layout) self._fileloader_frame_layout.setAlignment(Qt.AlignCenter) self._generator_frame = QGroupBox( self.fc_dict["frame_profile"][self.fc_lg]) self._generator_frame.setAlignment(Qt.AlignCenter) self._ss_book_frame = QGroupBox(self.fc_dict["win_sl"][self.fc_lg]) self._ss_book_frame.setAlignment(Qt.AlignCenter) self._ss_book_frame_layout = QGridLayout() self._ss_book_title = QLabel(self.fc_dict["title_book"][self.fc_lg]) self._ss_book_title.setFixedWidth(80) self._ss_book_title.setStatusTip( self.fc_dict["tip_fill_title"][self.fc_lg]) self._ss_book_titleBox = QLineEdit() self._ss_book_version = QLabel(self.fc_dict["vn_num"][self.fc_lg]) self._ss_book_version.setFixedWidth(80) self._ss_book_versionBox = QLineEdit() self._ss_book_versionBox.setFixedWidth(120) self._ss_book_versionBox.setText('s0') self._ss_book_versionBox.setReadOnly(True) self._ss_book_versionBox.setEnabled(False) self._ss_book_language = QLabel(self.fc_dict["corp_lang"][self.fc_lg]) self._ss_book_language.setFixedWidth(80) self._ss_book_languageBox = QLineEdit() self._ss_book_languageBox.setFixedWidth(120) self._ss_book_languageBox.setText('en') self._ss_book_author = QLabel(self.fc_dict["ar_id"][self.fc_lg]) self._ss_book_author.setFixedWidth(80) self._ss_book_author.setStatusTip( self.fc_dict["tip_fill_author"][self.fc_lg]) self._ss_book_authorBox = QLineEdit() self._ss_book_authorBox.setFixedWidth(120) self._ss_book_translator = QLabel(self.fc_dict["tr_id"][self.fc_lg]) self._ss_book_translator.setFixedWidth(80) self._ss_book_translatorBox = QLineEdit() self._ss_book_translatorBox.setFixedWidth(120) self._ss_book_translatorBox.setEnabled(False) self._ss_book_date = QLabel(self.fc_dict["issue_date"][self.fc_lg]) self._ss_book_date.setFixedWidth(80) self._ss_book_date.setStatusTip( self.fc_dict["tip_fill_date"][self.fc_lg]) self._ss_book_dateBox = QLineEdit() self._ss_book_dateBox.setFixedWidth(120) self._ss_book_genre = QLabel(self.fc_dict["issue_genre"][self.fc_lg]) self._ss_book_genre.setFixedWidth(80) self._ss_book_genre.setStatusTip( self.fc_dict["tip_fill_genre"][self.fc_lg]) self._ss_book_genreBox = QLineEdit() self._ss_book_genreBox.setFixedWidth(120) self._ss_book_contents = QLabel( self.fc_dict["win_preview"][self.fc_lg]) self._ss_book_contents.setFixedWidth(120) self._ss_book_contentsBox = QTextEdit() self._ss_book_contentsBox.setReadOnly(True) self._ss_book_buttonLayout = QHBoxLayout() self._ss_book_redoButton = QPushButton( self.fc_dict["btn_refill"][self.fc_lg]) self._ss_book_redoButton.setFixedWidth(80) self._ss_book_redoButton.setEnabled(False) self._ss_book_redoButton.clicked[bool].connect(self.json_sl_refiller) self._ss_book_uploadButton = QPushButton( self.fc_dict["btn_submit"][self.fc_lg]) self._ss_book_uploadButton.setFixedWidth(80) self._ss_book_uploadButton.clicked[bool].connect(self.json_sl_filler) self._ss_book_buttonLayout.addWidget(self._ss_book_redoButton) self._ss_book_buttonLayout.addWidget(self._ss_book_uploadButton) self._ss_book_frame_layout.addWidget(self._ss_book_title, 0, 0) self._ss_book_frame_layout.addWidget(self._ss_book_titleBox, 0, 1, 1, 3) self._ss_book_frame_layout.addWidget(self._ss_book_version, 1, 0) self._ss_book_frame_layout.addWidget(self._ss_book_versionBox, 1, 1) self._ss_book_frame_layout.addWidget(self._ss_book_language, 1, 2) self._ss_book_frame_layout.addWidget(self._ss_book_languageBox, 1, 3) self._ss_book_frame_layout.addWidget(self._ss_book_author, 2, 0) self._ss_book_frame_layout.addWidget(self._ss_book_authorBox, 2, 1) self._ss_book_frame_layout.addWidget(self._ss_book_translator, 2, 2) self._ss_book_frame_layout.addWidget(self._ss_book_translatorBox, 2, 3) self._ss_book_frame_layout.addWidget(self._ss_book_date, 3, 0) self._ss_book_frame_layout.addWidget(self._ss_book_dateBox, 3, 1) self._ss_book_frame_layout.addWidget(self._ss_book_genre, 3, 2) self._ss_book_frame_layout.addWidget(self._ss_book_genreBox, 3, 3) self._ss_book_frame_layout.addWidget(self._ss_book_contents, 4, 0, 1, 2) self._ss_book_frame_layout.addWidget(self._ss_book_contentsBox, 5, 0, 8, 4) self._ss_book_frame_layout.addLayout(self._ss_book_buttonLayout, 15, 0, 1, 4) self._ss_book_frame.setLayout(self._ss_book_frame_layout) self._tt_book_frame = QGroupBox(self.fc_dict["win_tl"][self.fc_lg]) self._tt_book_frame.setAlignment(Qt.AlignCenter) self._tt_book_frame_layout = QGridLayout() self._tt_book_title = QLabel(self.fc_dict["title_book"][self.fc_lg]) self._tt_book_title.setFixedWidth(80) self._tt_book_title.setStatusTip( self.fc_dict["tip_fill_title_tl"][self.fc_lg]) self._tt_book_titleBox = QLineEdit() self._tt_book_version = QLabel(self.fc_dict["vn_num"][self.fc_lg]) self._tt_book_version.setFixedWidth(80) self._tt_book_version.setStatusTip( self.fc_dict["tip_fill_vn"][self.fc_lg]) self._tt_book_versionBox = QLineEdit() self._tt_book_versionBox.setFixedWidth(120) self._tt_book_versionBox.setText('t1') self._tt_book_language = QLabel(self.fc_dict["corp_lang"][self.fc_lg]) self._tt_book_language.setFixedWidth(80) self._tt_book_languageBox = QLineEdit() self._tt_book_languageBox.setFixedWidth(120) self._tt_book_languageBox.setText('zh') self._tt_book_author = QLabel(self.fc_dict["ar_id"][self.fc_lg]) self._tt_book_author.setFixedWidth(80) self._tt_book_author.setStatusTip( self.fc_dict["tip_fill_author_tl"][self.fc_lg]) self._tt_book_authorBox = QLineEdit() self._tt_book_authorBox.setFixedWidth(120) self._tt_book_translator = QLabel(self.fc_dict["tr_id"][self.fc_lg]) self._tt_book_translator.setFixedWidth(80) self._tt_book_translator.setStatusTip( self.fc_dict["tip_fill_trans"][self.fc_lg]) self._tt_book_translatorBox = QLineEdit() self._tt_book_translatorBox.setFixedWidth(120) self._tt_book_date = QLabel(self.fc_dict["issue_date"][self.fc_lg]) self._tt_book_date.setFixedWidth(80) self._tt_book_date.setStatusTip( self.fc_dict["tip_fill_date_tl"][self.fc_lg]) self._tt_book_dateBox = QLineEdit() self._tt_book_dateBox.setFixedWidth(120) self._tt_book_genre = QLabel(self.fc_dict["issue_genre"][self.fc_lg]) self._tt_book_genre.setFixedWidth(80) self._tt_book_genre.setStatusTip( self.fc_dict["tip_fill_genre_tl"][self.fc_lg]) self._tt_book_genreBox = QLineEdit() self._tt_book_genreBox.setFixedWidth(120) self._tt_book_contents = QLabel( self.fc_dict["win_preview"][self.fc_lg]) self._tt_book_contents.setFixedWidth(120) self._tt_book_contentsBox = QTextEdit() self._tt_book_contentsBox.setReadOnly(True) self._tt_book_buttonLayout = QHBoxLayout() self._tt_book_redoButton = QPushButton( self.fc_dict["btn_refill"][self.fc_lg]) self._tt_book_redoButton.setEnabled(False) self._tt_book_redoButton.setFixedWidth(80) self._tt_book_redoButton.clicked[bool].connect(self.json_tl_refiller) self._tt_book_uploadButton = QPushButton( self.fc_dict["btn_submit"][self.fc_lg]) self._tt_book_uploadButton.setFixedWidth(80) self._tt_book_uploadButton.clicked[bool].connect(self.json_tl_filler) self._tt_book_uploadButton.setEnabled(False) self._tt_book_nextButton = QPushButton( self.fc_dict["btn_next"][self.fc_lg]) self._tt_book_nextButton.setFixedWidth(80) self._tt_book_nextButton.setEnabled(False) self._tt_book_nextButton.clicked[bool].connect(self.load_next_version) self._tt_book_buttonLayout.addWidget(self._tt_book_redoButton) self._tt_book_buttonLayout.addWidget(self._tt_book_nextButton) self._tt_book_buttonLayout.addWidget(self._tt_book_uploadButton) self._tt_book_frame_layout.addWidget(self._tt_book_title, 0, 0) self._tt_book_frame_layout.addWidget(self._tt_book_titleBox, 0, 1, 1, 3) self._tt_book_frame_layout.addWidget(self._tt_book_version, 1, 0) self._tt_book_frame_layout.addWidget(self._tt_book_versionBox, 1, 1) self._tt_book_frame_layout.addWidget(self._tt_book_language, 1, 2) self._tt_book_frame_layout.addWidget(self._tt_book_languageBox, 1, 3) self._tt_book_frame_layout.addWidget(self._tt_book_author, 2, 0) self._tt_book_frame_layout.addWidget(self._tt_book_authorBox, 2, 1) self._tt_book_frame_layout.addWidget(self._tt_book_translator, 2, 2) self._tt_book_frame_layout.addWidget(self._tt_book_translatorBox, 2, 3) self._tt_book_frame_layout.addWidget(self._tt_book_date, 3, 0) self._tt_book_frame_layout.addWidget(self._tt_book_dateBox, 3, 1) self._tt_book_frame_layout.addWidget(self._tt_book_genre, 3, 2) self._tt_book_frame_layout.addWidget(self._tt_book_genreBox, 3, 3) self._tt_book_frame_layout.addWidget(self._tt_book_contents, 4, 0, 1, 2) self._tt_book_frame_layout.addWidget(self._tt_book_contentsBox, 5, 0, 8, 4) self._tt_book_frame_layout.addLayout(self._tt_book_buttonLayout, 15, 0, 1, 4) self._tt_book_frame.setLayout(self._tt_book_frame_layout) self._generator_frame_layout = QHBoxLayout() self._generator_frame_layout.addWidget(self._ss_book_frame) self._generator_frame_layout.addWidget(self._tt_book_frame) self._generator_frame.setLayout(self._generator_frame_layout) self._convert_layout = QHBoxLayout() self._bi_book_convertButton = QPushButton( self.fc_dict["btn_conv"][self.fc_lg]) self._bi_book_convertButton.clicked[bool].connect(self.write_to_json) self._bi_book_convertButton.setFixedWidth(120) self._bi_book_convertButton.setStyleSheet("font:bold") self._convert_layout.addWidget(self._bi_book_convertButton) self._convert_layout.setAlignment(Qt.AlignCenter) mainWidget = QWidget() mainLayout = QVBoxLayout(mainWidget) mainLayout.setSpacing(2) mainLayout.addWidget(self._prompt_frame, 0) mainLayout.addWidget(self._fileloader_frame, 0) mainLayout.addWidget(self._generator_frame, 9) mainLayout.addLayout(self._convert_layout, 1) self.setCentralWidget(mainWidget) #----------创建主窗口状态栏---------- self._statusBar = QStatusBar() self._statusBar.showMessage(self.fc_dict["greeting"][self.fc_lg]) self._copyRightLabel = QLabel(self.fc_dict["copyright"][self.fc_lg]) self._statusBar.addPermanentWidget(self._copyRightLabel) self.setStatusBar(self._statusBar) #----------设置页面尺寸及标题等---------- self.setGeometry(200, 50, 800, 600) self.setObjectName("MainWindow") currentDir = os.getcwd() self.setWindowTitle(self.fc_dict["soft_title"][self.fc_lg]) self.setWindowIcon(QIcon(currentDir + "/app_data/workfiles/myIcon.png")) self.setIconSize(QSize(100, 40)) self._file_type_box.activated[str].connect(self._type_index_info) self._file_bind_box.activated[str].connect(self._bind_index_info) self._file_pos_box.activated[str].connect(self._pos_index_info) self._file_type_box.currentIndexChanged.connect( self._type_index_sender) self._file_bind_box.currentIndexChanged.connect( self._bind_index_sender) self._file_pos_box.currentIndexChanged.connect(self._pos_index_sender) def set_lang(self): with open(self._interface_lang_file, mode='r', encoding='utf-8-sig') as f: default_lg = f.read().strip() with open(self._interface_lang_dict, mode='r', encoding='utf-8-sig') as f: lg_dict = json.loads(f.read()) return default_lg, lg_dict # hardware_group def mark_num(self): if self._file_num_mark_box.isChecked(): self._file_tab_mark_box.setChecked(True) self._file_cuc_mark_box.setChecked(False) else: pass # hardware_group def mark_chapter(self): if self._file_chapt_num_box.isChecked(): pass else: pass # hardware_group def mark_tab(self): if self._file_tab_mark_box.isChecked(): self._file_cuc_mark_box.setChecked(False) self._file_table_mark_box.setChecked(False) if self._file_type_box.currentIndex() != 0: self._file_type_box.setCurrentIndex(0) else: pass elif self._file_tab_mark_box.isChecked() == False: self._file_num_mark_box.setChecked(False) self._file_chapt_num_box.setChecked(False) else: pass #hardware_group def mark_cuc(self): if self._file_cuc_mark_box.isChecked(): self._file_num_mark_box.setChecked(True) self._file_chapt_num_box.setChecked(False) self._file_tab_mark_box.setChecked(False) self._file_table_mark_box.setChecked(False) self._file_type_box.setCurrentIndex(0) if self._file_pos_box.currentIndex() in [0, 2]: pass else: self._file_pos_box.setCurrentIndex(0) else: pass #hardware_group def mark_table(self): if self._file_table_mark_box.isChecked(): self._file_cuc_mark_box.setChecked(False) self._file_tab_mark_box.setChecked(False) if self._file_type_box.currentIndex() != 0: pass else: self._file_type_box.setCurrentIndex(2) elif self._file_table_mark_box.isChecked() == False: if self._file_type_box.currentIndex() == 0: pass else: self._file_type_box.setCurrentIndex(0) else: pass #hardware_group def _bind_index_info(self, text): if text == self.fc_dict["bind_sig"][self.fc_lg]: if self._file_portion_box.value() == 1: pass else: self._file_portion_box.setValue(1) self._file_num_box.setEnabled(True) self._file_num_box.setMinimum(1) self._file_num_box.setValue(1) self._file_num_box.setEnabled(False) self._file_pos_box.setCurrentIndex(0) if self._file_openButton.text() == self.fc_dict["open_s"][ self.fc_lg]: pass else: self._file_openButton.setText( self.fc_dict["open_s"][self.fc_lg]) if text == self.fc_dict["bind_mul"][self.fc_lg]: self._file_portion_box.setValue(0) self._file_num_box.setEnabled(True) self._file_num_box.setMinimum(2) self._file_pos_box.setCurrentIndex(2) self._file_portion_box.setValue(0) if self._file_openButton.text() == self.fc_dict["open_m"][ self.fc_lg]: pass else: self._file_openButton.setText( self.fc_dict["open_m"][self.fc_lg]) else: pass #hardware_group def _bind_index_sender(self, i): if self._file_bind_box.currentText() == self.fc_dict["bind_sig"][ self.fc_lg]: #self._file_portion_box.setValue(1) if self._file_openButton.text() == self.fc_dict["open_s"][ self.fc_lg]: pass else: self._file_openButton.setText( self.fc_dict["open_s"][self.fc_lg]) elif self._file_bind_box.currentText() == self.fc_dict["bind_mul"][ self.fc_lg]: #self._file_portion_box.setValue(0) if self._file_openButton.text() == self.fc_dict["open_m"][ self.fc_lg]: pass else: self._file_openButton.setText( self.fc_dict["open_m"][self.fc_lg]) else: pass #hardware_group def _pos_index_info(self, text): if text == self.fc_dict["bi-sep"][self.fc_lg]: self._file_portion_box.setValue(0) if self._file_bind_box.currentText() != self.fc_dict["bind_mul"][ self.fc_lg]: self._file_bind_box.setCurrentIndex(1) self._file_num_box.setEnabled(True) self._file_num_box.setMinimum(2) else: pass else: self._file_portion_box.setValue(1) if text == self.fc_dict["u_d"][self.fc_lg]: self._file_bind_box.setCurrentIndex(0) self._file_num_box.setEnabled(False) elif text == self.fc_dict["l_r"][self.fc_lg]: self._file_bind_box.setCurrentIndex(0) self._file_num_box.setEnabled(False) self._file_cuc_mark_box.setChecked(False) if self._file_type_box.currentIndex() == 0: self._file_tab_mark_box.setChecked(True) else: pass else: pass #hardware_group def _pos_index_sender(self, text): if text == self.fc_dict["u_d"][self.fc_lg]: self._file_bind_box.setCurrentIndex(0) self._file_num_box.setEnabled(False) elif text == self.fc_dict["l_r"][self.fc_lg]: self._file_bind_box.setCurrentIndex(0) self._file_num_box.setEnabled(False) self._file_tab_mark_box.setChecked(True) self._file_cuc_mark_box.setChecked(False) elif text == self.fc_dict["bi-sep"][self.fc_lg]: #self._file_portion_box.setValue(0) if self._file_bind_box.currentText() != self.fc_dict["bind_mul"][ self.fc_lg]: self._file_bind_box.setCurrentIndex(1) self._file_num_box.setEnabled(True) self._file_num_box.setMinimum(2) else: pass else: pass #hardware_group def _type_index_info(self, text): file_suffix = text if file_suffix == "xlsx": self._file_num_mark_box.setChecked(True) self._file_pos_box.setCurrentIndex(1) self._file_table_mark_box.setChecked(True) self._file_tab_mark_box.setChecked(True) elif file_suffix == 'txt': self._file_table_mark_box.setChecked(False) elif file_suffix == 'docx': self._file_pos_box.setCurrentIndex(0) self._file_tab_mark_box.setChecked(False) self._file_cuc_mark_box.setChecked(False) else: pass #hardware_group def _type_index_sender(self, i): file_suffix = self._file_type_box.currentText() if file_suffix == "xlsx": self._file_table_mark_box.setChecked(True) else: pass #prompt_group def _set_status_text(self, text): self._statusBar.showMessage(text, 10000)
class Window(QMainWindow): def __init__(self): super().__init__() self.setGeometry(50, 50, 1920, 1080) self.setWindowTitle("Ground Truthing") # self.setWindowIcon(QtGui.QIcon('pythonlogo.png')) self.frame_counter = self.images_handler() # self.statusbar_init() LOGGER.info("initialised status bar") # menubar_init() vboxlayout = QVBoxLayout() hboxlayout = QHBoxLayout() # vboxlayout.addStretch(2) # vboxlayout.setStretch(1,2) self.topwid = ImageWindow() self.topwid.resize(self.topwid.sizeHint()) self.botwid = ButtonWindow() self.botwid.resize(self.botwid.sizeHint()) self.printer = DataDisplayWindow() self.topwid.image(self.frame_counter, self.printer) self.botwid.gridstruct(self.frame_counter, self.printer) self.printer.show_data(self.frame_counter) self.wid = QWidget(self) extractAction = QAction("Exit", self) extractAction.setShortcut("Ctrl+Q") extractAction.setStatusTip('Leave The App') extractAction.triggered.connect(self.close_application) saveFile = QAction("Save", self) saveFile.setShortcut("Ctrl+S") saveFile.setStatusTip('Save To Location') saveFile.triggered.connect(self.save_application) LOGGER.debug("frame Length = " + str(len(self.frame_counter.display_all()))) extractNextImage = QAction("Next Frame", self) # extractNextImage.setShortcut("Alt+n") extractNextImage.setShortcut("Right") extractNextImage.setStatusTip("Next Frame...") extractNextImage.triggered.connect(lambda: self.topwid.changeimage("n", self.frame_counter, self.printer)) extractPrevImage = QAction("Previous Frame", self) # extractPrevImage.setShortcut("Alt+b") extractPrevImage.setShortcut("Left") extractPrevImage.setStatusTip("Previous Frame...") extractPrevImage.triggered.connect(lambda: self.topwid.changeimage("b", self.frame_counter, self.printer)) getshortcuts = QAction("Shortcuts", self) getshortcuts.setShortcut("Ctrl+K") getshortcuts.setStatusTip("Shortcuts List") getshortcuts.triggered.connect(lambda: self.short()) reportBugs = QAction("Report", self) reportBugs.setShortcut("Ctrl+R") reportBugs.setStatusTip("Please report bugs") reportBugs.triggered.connect(lambda: self.bugreport()) author = QLabel("Prajwal Rao\[email protected]") author.setStyleSheet("color : grey") self.statusBar = QStatusBar() self.statusBar.addPermanentWidget(author) self.setStatusBar(self.statusBar) mainMenu = self.menuBar() fileMenu = mainMenu.addMenu('&File') helpMenu = mainMenu.addMenu('&Help') fileMenu.addAction(extractNextImage) fileMenu.addAction(extractPrevImage) fileMenu.addAction(saveFile) fileMenu.addAction(extractAction) helpMenu.addAction(getshortcuts) helpMenu.addAction(reportBugs) self.setCentralWidget(self.wid) # vboxlayout.setAlignment(QtCore.Qt.AlignCenter) hboxlayout.addWidget(self.topwid) hboxlayout.addWidget(self.printer) vboxlayout.addLayout(hboxlayout) # vboxlayout.addWidget(self.topwid) # print("vbox size hint: ",vboxlayout.sizeHint()) vboxlayout.addWidget(self.botwid.groupbox) self.wid.setLayout(vboxlayout) LOGGER.info("initialised menubar") # self.home() self.show() # def get_frame(self, images): # imgs = sorted(images, key=lambda x: int(x[6])) def images_handler(self): image_path = QFileDialog.getExistingDirectory(self, "Select Image Directory") # image_path = input("Enter Image Path:") imag = os.listdir(image_path) images = [os.path.join(image_path, t) for t in imag] # pprint(images) # images = self.get_frame(images) self.frame_counter = count() # images = sorted(images, key=lambda x: int(x[6])) for image in images: self.frame_counter.set(image) self.frame_counter.set_target_as_zero() # self.frame_counter.sort_dict() # pprint(self.frame_counter.display_all()) return self.frame_counter def bugreport(self): reporttext = 'Please report all bugs to <a href="mailto:[email protected]">[email protected]</a>' \ + ' or <a href="mailto:[email protected]">[email protected]</a>' QMessageBox.about(QWidget(), "Report", reporttext) # reportmessage.setIcon(QMessageBox.Information) # reportmessage.setText('Please report all bugs to <a href="mailto:[email protected]">[email protected]</a>' # + ' or <a href="mailto:[email protected]">[email protected]</a>') def short(self): self.key_bindings = "Ctrl+S\t\t\tSave File as JSON\n" \ + "Ctrl+Q\t\t\tQuit\n" \ + "Right Arrow\t\t\tNext Frame\n" \ + "Left Arrow\t\t\tPrevious Frame\n" \ + "1\t\t\tAdd Small Car\n" \ + "Shift+1\t\t\tRemove Small Car\n" \ + "2\t\t\tAdd Big Car\n" \ + "Shift+2\t\t\tRemove Big Car\n" \ + "3\t\t\tAdd Bus\n" \ + "Shift+3\t\t\tRemove Bus\n" \ + "4\t\t\tAdd Two Wheeler\n" \ + "Shift+4\t\t\tRemove Two Wheeler\n" \ + "Q\t\t\tAdd Three Wheeler\n" \ + "Shift+Q\t\t\tRemove Three Wheeler\n" \ + "W\t\t\tAdd LCV\n" \ + "Shift+W\t\t\tRemove LCV\n" \ + "E\t\t\tAdd Truck\n" \ + "Shift+E\t\t\tRemove Truck\n" \ + "R\t\t\tAdd Bicycle\n" \ + "Shift+R\t\t\tRemove Bicycle\n\n" \ + "Ctrl+K\t\t\tShow Key Bindings\n" \ + "Ctrl+R\t\t\tReport Bugs\n" QMessageBox.about(QWidget(), "Shortcuts", self.key_bindings) def save_application(self): save_location = QFileDialog.getSaveFileName(self, "Save File") LOGGER.info(save_location) if not save_location[0].endswith(".json"): save_location[0]+=".json" with open(save_location[0], "w+") as file: writedata = self.frame_counter.display_all() json.dump(writedata, file) def close_application(self): choice = QMessageBox.question(self, 'Extract!', "Do you really want to quit?", QMessageBox.Yes | QMessageBox.No) LOGGER.info("Quit") sys.exit()
class Main(QMainWindow): def __init__(self, parent=None): super().__init__() self.screen = QApplication.primaryScreen() self.menu = Menu(self) self.startInterfaceLogin() self.setSettings() self.menu.setMenusPrincipal() def setSettings(self): '''Configura a aparencia da Janela principal''' self.setWindowTitle("SISTEMA DE GESTÃO DE ESTOQUE E VENCIMENTO") self.setMinimumSize(self.screen.geometry().width() - 50, self.screen.geometry().height() - 50) self.setWindowState(Qt.WindowMaximized) self.setWindowIcon(QIcon("logo.png")) self.status_bar = QStatusBar(self) self.setStatusBar(self.status_bar) self.status_bar.addWidget(QLabel("Bem Vindo")) self.status_bar.addPermanentWidget(QLabel("Versão 1.0")) self.show() def startInterfaceLogin(self): '''Configura o Widget central da Janela principal e Inicia as Interfaces necessarias para a tela inicial''' self.central_widget = QStackedWidget() self.setCentralWidget(self.central_widget) self.login = Login(self) #Instancia a classe Login com a interface self.central_widget.addWidget( self.login) #Adiciona a insterface no centralWidget self.central_widget.setCurrentWidget( self.login) #Torna a interface Principal self.login.btn_entrar.clicked.connect( self.conectar) #Função botão Entrar def showSobre(self): '''Exibe uma Dialog com a versão e nome do software''' msg_sobre = QMessageBox() msg_sobre.setWindowIcon(QIcon("logo.png")) msg_sobre.setWindowTitle("Sobre") msg_sobre.setText("Sistema de Gestão de Estoque e Vencimento") msg_sobre.setInformativeText("Versão 2.0") msg_sobre.setDefaultButton(QMessageBox.Ok) msg_sobre.exec_() def conectar(self): '''Ação do botão entrar da tela de login''' self.usuario = Usuario(self.formataCpf(self.login.edit_cpf.text()), self.login.edit_password.text()) if (self.usuario.autenticaUsuario()): if self.usuario.id_conta == 1: pass elif self.usuario.id_conta == 2: from controller.ControllerGerente import ControllerGerente self.controller = ControllerGerente(self) self.menu.setMenusGerente() elif self.usuario.id_conta == 3: from controller.ControllerEstoquista import ControllerEstoquista self.controller = ControllerEstoquista(self) self.menu.setMenusEstoquista() else: QMessageBox.warning(self, "Conta", "Conta do usuário não cadastrada", QMessageBox.Ok) self.mdi_area = QMdiArea() self.setCentralWidget(self.mdi_area) del self.central_widget #Deleta o centralWidget atual para inicialização da MDIArea del self.login #Deleta a instancia da classe Login else: QMessageBox.warning(self, "Cliente", "Usuário não cadastrado", QMessageBox.Ok) def formataCpf(self, cpf): '''Retorna o CPF formatado(somente Numeros) parametros: cpf - Não formatado ex: 111.222.333-44 retorno: cpf - Formatado ex: 11122233344''' cpf_formatado = "" for digito in str(cpf): if digito.isdigit(): cpf_formatado += str(digito) return cpf_formatado