Esempio n. 1
0
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())
Esempio n. 2
0
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()
Esempio n. 3
0
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
  '''
Esempio n. 4
0
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)
Esempio n. 5
0
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
Esempio n. 6
0
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()
Esempio n. 7
0
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)))
Esempio n. 8
0
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()
Esempio n. 9
0
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()
Esempio n. 10
0
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)
Esempio n. 11
0
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()
Esempio n. 12
0
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