Ejemplo n.º 1
0
    def setup_toolbars(self):
        source_toolbar = self.addToolBar('SourceToolbar')

        self.user_interface.tbrActionToggleSourceView = QAction('C/C++', self)
        self.user_interface.tbrActionToggleSourceView.triggered.connect(
            self.toggle_source_view)
        self.user_interface.tbrActionToggleSourceView.setToolTip(
            "Toggle source code view")
        self.user_interface.tbrActionToggleSourceView.setCheckable(True)
        self.user_interface.tbrActionToggleSourceView.setChecked(True)

        source_toolbar.addAction(self.user_interface.tbrActionToggleSourceView)

        search_toolbar = self.addToolBar("SearchToolbar")
        search_toolbar.setAllowedAreas(Qt.TopToolBarArea
                                       | Qt.BottomToolBarArea)
        self.ledSearchBox = QLineEdit()
        self.ledSearchBox.textChanged.connect(self.invalidate_search_criteria)
        self.ledSearchBox.keyPressEvent = self.search_box_key_pressed

        search_toolbar.addWidget(self.ledSearchBox)

        tbrActionPrevSearchMatch = QAction('<<', self)
        tbrActionPrevSearchMatch.triggered.connect(
            functools.partial(self.select_search_match, False))
        tbrActionPrevSearchMatch.setToolTip("Go to previous search match")

        tbrActionNextSearchMatch = QAction('>>', self)
        tbrActionNextSearchMatch.triggered.connect(
            functools.partial(self.select_search_match, True))
        tbrActionNextSearchMatch.setToolTip("Go to next search match")

        tbrActionIgnoreCase = QAction('Ignore Case', self)
        tbrActionIgnoreCase.setCheckable(True)
        tbrActionIgnoreCase.setChecked(True)
        tbrActionIgnoreCase.triggered.connect(self.set_search_case_sensitivity,
                                              tbrActionIgnoreCase.isChecked())
        tbrActionIgnoreCase.setToolTip("Ignore case")

        tbrActionWrapSearch = QAction('Wrap Search', self)
        tbrActionWrapSearch.setCheckable(True)
        tbrActionWrapSearch.setChecked(True)
        tbrActionWrapSearch.triggered.connect(self.set_search_wrap,
                                              tbrActionWrapSearch.isChecked())
        tbrActionWrapSearch.setToolTip("Wrap Search")

        tbrActionMatchWholeWord = QAction('Match Whole Word', self)
        tbrActionMatchWholeWord.setCheckable(True)
        tbrActionMatchWholeWord.setChecked(False)
        tbrActionMatchWholeWord.triggered.connect(
            self.set_match_whole_word, tbrActionMatchWholeWord.isChecked())
        tbrActionMatchWholeWord.setToolTip("Match Whole Word")

        search_toolbar.addAction(tbrActionPrevSearchMatch)
        search_toolbar.addAction(tbrActionNextSearchMatch)
        search_toolbar.addAction(tbrActionIgnoreCase)
        search_toolbar.addAction(tbrActionMatchWholeWord)
        search_toolbar.addAction(tbrActionWrapSearch)
class NewLayersToTheTop:
    def __init__(self, iface):
        self.iface = iface
        self.settings = QSettings()

    def initGui(self):
        icon = QIcon()
        icon.addFile(":/plugins/NewLayersToTheTop/default.png",
                     state=QIcon.Off)
        icon.addFile(":/plugins/NewLayersToTheTop/toTheTop.png",
                     state=QIcon.On)
        self.action = QAction(icon, u"", self.iface.mainWindow())
        self.action.toggled.connect(self.run)

        self.action.setCheckable(True)
        checked = self.settings.value("/NewLayersToTheTop/checked",
                                      True,
                                      type=bool)
        self.action.setChecked(checked)

        self.iface.addToolBarIcon(self.action)
        self.iface.addPluginToMenu(u"New layers to the &top", self.action)

    def unload(self):
        self.iface.removePluginMenu(u"New layers to the &top", self.action)
        self.iface.removeToolBarIcon(self.action)
        if self.action.isChecked():
            QgsMapLayerRegistry.instance().layersAdded.disconnect(
                self.changeLayerAdditionMode)

    def run(self):
        checked = self.action.isChecked()
        if checked:
            self.action.setText(
                u"Click to make new layers to be added to the selected group")
            QgsMapLayerRegistry.instance().layersAdded.connect(
                self.changeLayerAdditionMode)
            self.settings.setValue("/NewLayersToTheTop/checked", True)
            #self.iface.messageBar().pushMessage( "'New layers to the top' (plugin)", u'From now on, new layers will be added to the top of the tree,', 0, 5 )
        else:
            self.action.setText(
                u"Click to make new layers to be added to the top of the tree")
            QgsMapLayerRegistry.instance().layersAdded.disconnect(
                self.changeLayerAdditionMode)
            self.settings.setValue("/NewLayersToTheTop/checked", False)
            #self.iface.messageBar().pushMessage( "'New layers to the top' (plugin)", u'From now on, new layers will be added to the selected group.', 0, 5 )

    def changeLayerAdditionMode(self, layers):
        QgsProject.instance().layerTreeRegistryBridge().setLayerInsertionPoint(
            QgsProject.instance().layerTreeRoot(), 0)
Ejemplo n.º 3
0
    def setup_toolbars(self):
        source_toolbar = self.addToolBar('SourceToolbar')
        
        self.user_interface.tbrActionToggleSourceView = QAction('C/C++', self)
        self.user_interface.tbrActionToggleSourceView.triggered.connect(self.toggle_source_view)
        self.user_interface.tbrActionToggleSourceView.setToolTip("Toggle source code view")
        self.user_interface.tbrActionToggleSourceView.setCheckable(True)
        self.user_interface.tbrActionToggleSourceView.setChecked(True)
        
        source_toolbar.addAction(self.user_interface.tbrActionToggleSourceView)
        
        search_toolbar = self.addToolBar("SearchToolbar")
        search_toolbar.setAllowedAreas(Qt.TopToolBarArea | Qt.BottomToolBarArea)
        self.ledSearchBox = QLineEdit()
        self.ledSearchBox.textChanged.connect(self.invalidate_search_criteria)
        self.ledSearchBox.keyPressEvent = self.search_box_key_pressed

        search_toolbar.addWidget(self.ledSearchBox)
        
        tbrActionPrevSearchMatch = QAction('<<', self)                               
        tbrActionPrevSearchMatch.triggered.connect(functools.partial(self.select_search_match, False))
        tbrActionPrevSearchMatch.setToolTip("Go to previous search match")                  

        tbrActionNextSearchMatch = QAction('>>', self)                               
        tbrActionNextSearchMatch.triggered.connect(functools.partial(self.select_search_match, True))             
        tbrActionNextSearchMatch.setToolTip("Go to next search match")                  

        tbrActionIgnoreCase = QAction('Ignore Case', self)                               
        tbrActionIgnoreCase.setCheckable(True)
        tbrActionIgnoreCase.setChecked(True)
        tbrActionIgnoreCase.triggered.connect(self.set_search_case_sensitivity, tbrActionIgnoreCase.isChecked())            
        tbrActionIgnoreCase.setToolTip("Ignore case") 
        
        tbrActionWrapSearch = QAction('Wrap Search', self)                               
        tbrActionWrapSearch.setCheckable(True)
        tbrActionWrapSearch.setChecked(True)
        tbrActionWrapSearch.triggered.connect(self.set_search_wrap, tbrActionWrapSearch.isChecked())             
        tbrActionWrapSearch.setToolTip("Wrap Search") 
        
        tbrActionMatchWholeWord = QAction('Match Whole Word', self)                               
        tbrActionMatchWholeWord.setCheckable(True)
        tbrActionMatchWholeWord.setChecked(False)
        tbrActionMatchWholeWord.triggered.connect(self.set_match_whole_word, tbrActionMatchWholeWord.isChecked())             
        tbrActionMatchWholeWord.setToolTip("Match Whole Word") 
                                               
        search_toolbar.addAction(tbrActionPrevSearchMatch)
        search_toolbar.addAction(tbrActionNextSearchMatch)
        search_toolbar.addAction(tbrActionIgnoreCase)
        search_toolbar.addAction(tbrActionMatchWholeWord)
        search_toolbar.addAction(tbrActionWrapSearch)
Ejemplo n.º 4
0
class MiTraceView(QWidget):
    def __init__(self, do, parent):
        QWidget.__init__(self, parent)

        self.ui = Ui_MiTraceView()
        self.ui.setupUi(self)

        self.__do = do

        self.ui.commandEdit.lineEdit().returnPressed.connect(self.executeMiCommand)

        self.__do.gdb_connector.commandExecuted.connect(self.appendCommand)
        self.__do.gdb_connector.reader.asyncRecordReceived.connect(self.appendAsync)

        self.__timeAction = QAction(Icons.time, "Show Elapsed Time", self)
        self.__timeAction.setCheckable(True)
        self.__timeAction.setChecked(True)
        parent.titleBarWidget().addAction(self.__timeAction)

        parent.addClearAction()
        parent.clearRequested.connect(self.ui.traceView.clear)

    def appendCommand(self, cmd, rec, time):
        timestr = "[<i>%.3f</i>] " % time if self.__timeAction.isChecked() else ""
        self.ui.traceView.append("%s<b>%s</b>" % (timestr, cmd))
        color = 'color="#ff3333"' if rec.class_ == GdbOutput.ERROR else ""
        self.ui.traceView.append("<font %s>%s</font>" % (color, rec.raw))

    def appendAsync(self, rec):
        self.ui.traceView.append('<font color="#777777">%s</font>' % rec.raw)

    def executeMiCommand(self):
        cmd = str(self.ui.commandEdit.lineEdit().text())
        self.ui.commandEdit.lineEdit().setText("")
        self.__do.gdb_connector.execute(cmd)
Ejemplo n.º 5
0
    def _update(self, action: QAction, initialize: bool):
        """updates the internal values from the given action."""
        if not self._action:
            return
        self._disconnectAction()
        self.changed.disconnect(self._updateToolTipWithKeySequence)
        if initialize:
            self.setSeparator(action.isSeparator())
            self.setMenuRole(action.menuRole())

        if self.hasAttribute(ProxyActionAttribute.UpdateIcon) or initialize:
            self.setIcon(action.icon())
            self.setIconText(action.iconText())
            self.setIconVisibleInMenu(action.isIconVisibleInMenu())

        if self.hasAttribute(ProxyActionAttribute.UpdateText) or initialize:
            self.setText(action.text())
            self._toolTip = action.toolTip()
            self._updateToolTipWithKeySequence()
            self.setStatusTip(action.statusTip())
            self.setWhatsThis(action.whatsThis())

        self.setCheckable(action.isCheckable())

        if not initialize:
            self.setChecked(action.isChecked())
            self.setEnabled(action.isEnabled())
            self.setVisible(action.isVisible())

        self._connectAction()
        self.changed.connect(self._updateToolTipWithKeySequence)
Ejemplo n.º 6
0
class MiTraceView(QWidget):
    def __init__(self, do, parent):
        QWidget.__init__(self, parent)

        self.ui = Ui_MiTraceView()
        self.ui.setupUi(self)

        self.__do = do

        self.ui.commandEdit.lineEdit().returnPressed.connect(
            self.executeMiCommand)

        self.__do.gdb_connector.commandExecuted.connect(self.appendCommand)
        self.__do.gdb_connector.reader.asyncRecordReceived.connect(
            self.appendAsync)

        self.__timeAction = QAction(Icons.time, "Show Elapsed Time", self)
        self.__timeAction.setCheckable(True)
        self.__timeAction.setChecked(True)
        parent.titleBarWidget().addAction(self.__timeAction)

        parent.addClearAction()
        parent.clearRequested.connect(self.ui.traceView.clear)

    def appendCommand(self, cmd, rec, time):
        timestr = "[<i>%.3f</i>] " % time if self.__timeAction.isChecked(
        ) else ""
        self.ui.traceView.append("%s<b>%s</b>" % (timestr, cmd))
        color = 'color="#ff3333"' if rec.class_ == GdbOutput.ERROR else ""
        self.ui.traceView.append("<font %s>%s</font>" % (color, rec.raw))

    def appendAsync(self, rec):
        self.ui.traceView.append('<font color="#777777">%s</font>' % rec.raw)

    def executeMiCommand(self):
        cmd = str(self.ui.commandEdit.lineEdit().text())
        self.ui.commandEdit.lineEdit().setText("")
        self.__do.gdb_connector.execute(cmd)
Ejemplo n.º 7
0
class SimpleRichText(QTextEdit):
    def __init__(self, focusin, focusout):
        QTextEdit.__init__(self)
        self.focusin = focusin
        self.focusout = focusout
        self.createActions()

        #self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)

    def focusOutEvent ( self, event ):
        #print "focus out"
        self.focusout()

    def focusInEvent ( self, event ):
        self.focusin()


    def closeEvent(self, event):
        event.accept()

    def createActions(self):
        self.boldAct = QAction(self.tr("&Bold"), self)
        self.boldAct.setCheckable(True)
        self.boldAct.setShortcut(self.tr("Ctrl+B"))
        self.boldAct.setStatusTip(self.tr("Make the text bold"))
        self.connect(self.boldAct, SIGNAL("triggered()"), self.setBold)
        self.addAction(self.boldAct)

        boldFont = self.boldAct.font()
        boldFont.setBold(True)
        self.boldAct.setFont(boldFont)

        self.italicAct = QAction(self.tr("&Italic"), self)
        self.italicAct.setCheckable(True)
        self.italicAct.setShortcut(self.tr("Ctrl+I"))
        self.italicAct.setStatusTip(self.tr("Make the text italic"))
        self.connect(self.italicAct, SIGNAL("triggered()"), self.setItalic)
        self.addAction(self.italicAct)

    def setBold(self):
        format = QTextCharFormat()
        if self.boldAct.isChecked():
            weight = QFont.Bold
        else:
            weight = QFont.Normal
        format.setFontWeight(weight)
        self.setFormat(format)

    def setItalic(self):
        format = QTextCharFormat()
        #format.setFontItalic(self.__italic.isChecked())
        format.setFontItalic(self.italicAct.isChecked())
        self.setFormat(format)

    def setUnderline(self):
        format = QTextCharFormat()
        format.setFontUnderline(self.__underline.isChecked())
        self.setFormat(format)

    def setFormat(self, format):
        self.textCursor().mergeCharFormat(format)
        self.mergeCurrentCharFormat(format)

    def bold(self):
        print("bold")

    def italic(self):
        print("italic")
Ejemplo n.º 8
0
class ViewPhotoDialog(QDialog, Ui_Dialog):
    def __init__(self, path, parent=None):
        super(ViewPhotoDialog, self).__init__(parent)
        self.parent = parent
        self.setupUi(self)

        self.printer = QPrinter()
        self.scaleFactor = 1.0

        self.createActions()
        self.createMenus()

        photo = QPixmap(path)
        self.lblPhoto.setPixmap(photo)
        self.printAct.setEnabled(True)
        self.fitToWindowAct.setEnabled(True)

        self.updateActions()

        if not self.fitToWindowAct.isChecked():
            self.lblPhoto.adjustSize()

        self.fitToWindowAct.setChecked(True)
        self.fitToWindow()

    def print_(self):
        dialog = QPrintDialog(self.printer, self)
        if dialog.exec_():
            painter = QPainter(self.printer)
            rect = painter.viewport()
            size = self.lblPhoto.pixmap().size()
            size.scale(rect.size(), Qt.KeepAspectRatio)
            painter.setViewport(rect.x(), rect.y(), size.width(),
                                size.height())
            painter.setWindow(self.lblPhoto.pixmap().rect())
            painter.drawPixmap(0, 0, self.lblPhoto.pixmap())

    def zoomIn(self):
        self.scaleImage(1.25)

    def zoomOut(self):
        self.scaleImage(0.8)

    def normalSize(self):
        self.lblPhoto.adjustSize()
        self.scaleFactor = 1.0

    def fitToWindow(self):
        fitToWindow = self.fitToWindowAct.isChecked()
        self.scrollArea.setWidgetResizable(fitToWindow)
        if not fitToWindow:
            self.normalSize()

        self.updateActions()

    def createActions(self):
        self.printAct = QAction("&Print...",
                                self,
                                shortcut="Ctrl+P",
                                enabled=False,
                                triggered=self.print_)

        self.exitAct = QAction("E&xit",
                               self,
                               shortcut="Ctrl+Q",
                               triggered=self.close)

        self.zoomInAct = QAction("Zoom &In (25%)",
                                 self,
                                 shortcut="Ctrl++",
                                 enabled=False,
                                 triggered=self.zoomIn)

        self.zoomOutAct = QAction("Zoom &Out (25%)",
                                  self,
                                  shortcut="Ctrl+-",
                                  enabled=False,
                                  triggered=self.zoomOut)

        self.normalSizeAct = QAction("&Normal Size",
                                     self,
                                     shortcut="Ctrl+S",
                                     enabled=False,
                                     triggered=self.normalSize)

        self.fitToWindowAct = QAction("&Fit to Window",
                                      self,
                                      enabled=False,
                                      checkable=True,
                                      shortcut="Ctrl+F",
                                      triggered=self.fitToWindow)

    def createMenus(self):
        self.fileMenu = QMenu("&File", self)
        self.fileMenu.addAction(self.printAct)
        self.fileMenu.addAction(self.exitAct)

        self.viewMenu = QMenu("&View", self)
        self.viewMenu.addAction(self.zoomInAct)
        self.viewMenu.addAction(self.zoomOutAct)
        self.viewMenu.addAction(self.normalSizeAct)
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.fitToWindowAct)

        self.menuBar.addMenu(self.fileMenu)
        self.menuBar.addMenu(self.viewMenu)

    def updateActions(self):
        self.zoomInAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.zoomOutAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.normalSizeAct.setEnabled(not self.fitToWindowAct.isChecked())

    def scaleImage(self, factor):
        self.scaleFactor *= factor
        self.lblPhoto.resize(self.scaleFactor * self.lblPhoto.pixmap().size())

        self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor)
        self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor)

        self.zoomInAct.setEnabled(self.scaleFactor < 3.0)
        self.zoomOutAct.setEnabled(self.scaleFactor > 0.333)

    def adjustScrollBar(self, scrollBar, factor):
        scrollBar.setValue(
            int(factor * scrollBar.value() +
                ((factor - 1) * scrollBar.pageStep() / 2)))
Ejemplo n.º 9
0
class MainWindow(QtGui.QMainWindow):

    """Implements the main window for dame."""

    def __init__(self, parent=None):
        """Initialize the window."""
        QtGui.QMainWindow.__init__(self, parent)
        self.setupUi()

    def setupUi(self):
        """Create the basic UI."""
        self.setWindowTitle("dame")
        # TODO: Set window icon
        self.create_actions()
        self.create_statusbar()

        self.mainview = MainViewer(parent=self)

        # # Connect an action now that mainview is set
        # self.mode_group.triggered.connect(self.mainview.toggleComparison)

        # TODO: This is the start of using tabbed windows
        # self.mdiArea = QtGui.QMdiArea(parent=self)
        # first = self.mdiArea.addSubWindow(self.scrollArea)
        # self.mdiArea.setViewMode(QtGui.QMdiArea.TabbedView)
        # self.mdiArea.setTabsMovable(True)
        # self.setCentralWidget(self.mdiArea)
        # first.setWindowTitle("foo")

        self.setCentralWidget(self.mainview)

        # Create popup windows (for zoomer and panner)
        self.zoom_win = QtGui.QWidget(self, Qt.Window | Qt.Tool)
        self.zoom_win.setSizePolicy(QtGui.QSizePolicy.Fixed,
                                    QtGui.QSizePolicy.Fixed)
        self.zoom_win_im = QLabel()
        self.zoom_win_im.setSizePolicy(QtGui.QSizePolicy.Ignored,
                                       QtGui.QSizePolicy.Ignored)
        # self.zoom_win.resize(150,150)
        # self.zoom_win.show()
        zoomer_layout = QtGui.QGridLayout()
        zoomer_layout.setContentsMargins(0, 0, 0, 0)
        zoomer_layout.addWidget(self.zoom_win_im)
        self.zoom_win.setLayout(zoomer_layout)

        # TODO: panner

        # Create note dock widget
        self.note_widget = QtGui.QDockWidget("Notes", parent=self)
        self.note_text = QtGui.QTextEdit(parent=self.note_widget)
        self.note_widget.setWidget(self.note_text)
        self.note_widget.setFeatures(
            QtGui.QDockWidget.DockWidgetClosable |
            QtGui.QDockWidget.DockWidgetMovable |
            QtGui.QDockWidget.DockWidgetFloatable |
            QtGui.QDockWidget.DockWidgetVerticalTitleBar)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.note_widget)
        self.note_widget.close()
        self.note_action = self.note_widget.toggleViewAction()
        self.note_action.setText("Display notes")
        self.note_action.setStatusTip("Show notes about the SIR image")

        # Create the menus
        self.create_menus()

    def create_statusbar(self):
        """Create the statusbar."""
        self.statusBar().showMessage("Ready")

        # The individual info
        self.status_sing_pixinfo = QLabel()
        self.status_sing_coord = QLabel()
        self.status_left_pixinfo = QLabel()
        self.status_right_pixinfo = QLabel()
        self.status_comp_coord = QLabel()

        # The groups
        self.status_sing_layout = QtGui.QHBoxLayout()
        self.status_sing_layout.addWidget(self.status_sing_coord, 0,
                                          Qt.AlignRight)
        self.status_sing_layout.addWidget(self.status_sing_pixinfo, 1,
                                          Qt.AlignRight)
        self.status_comp_layout = QtGui.QHBoxLayout()
        self.status_comp_layout.addWidget(self.status_left_pixinfo, 0)
        self.status_comp_layout.addWidget(self.status_comp_coord, 1)
        self.status_comp_layout.addWidget(self.status_right_pixinfo, 0)

        self.status_sing_layout.setContentsMargins(0, 0, 0, 0)
        self.status_comp_layout.setContentsMargins(0, 0, 0, 0)

        self.status_sing = QtGui.QWidget()
        self.status_sing.setLayout(self.status_sing_layout)
        self.status_comp = QtGui.QWidget()
        self.status_comp.setLayout(self.status_comp_layout)

        # The stacked widget (to alternate between single and comparison modes)
        self.status_stacked = QtGui.QStackedWidget()
        self.status_stacked.addWidget(self.status_sing)
        self.status_stacked.addWidget(self.status_comp)
        self.status_stacked.setCurrentIndex(0)

        self.statusBar().addWidget(self.status_stacked)

    def create_actions(self):
        """Define the actions."""
        self.about_action = QAction("&About", self)
        self.about_action.setStatusTip("About dame")
        self.about_action.setMenuRole(QAction.AboutRole)
        self.about_action.triggered.connect(self.show_about)

        self.open_action = QAction("&Open", self)
        self.open_action.setStatusTip("Open a SIR file")
        self.open_action.setShortcut(QtGui.QKeySequence.Open)
        self.open_action.triggered.connect(self.open_file)

        self.close_action = QAction("&Close", self)
        self.close_action.setStatusTip("Close current SIR file")
        self.close_action.setShortcut(QtGui.QKeySequence.Close)
        self.close_action.triggered.connect(self.close_file)

        self.exit_action = QAction("E&xit", self)
        self.exit_action.setMenuRole(QAction.QuitRole)
        self.exit_action.setStatusTip("Exit dame")
        self.exit_action.setShortcut(QtGui.QKeySequence("Ctrl+Q"))
        self.exit_action.triggered.connect(self.close)

        self.prop_action = QAction("SIR header", self)
        self.prop_action.setStatusTip("Display SIR header information")
        self.prop_action.triggered.connect(self.print_header)

        self.range_action = QAction("Image range", self)
        self.range_action.setStatusTip("Set image display range")
        self.range_action.triggered.connect(self.show_range)

        self.zoomer_action = QAction("Enable zoomer window", self)
        self.zoomer_action.setStatusTip(("Show zoomer window for "
                                         "magnified viewing"))
        self.zoomer_action.setCheckable(True)
        self.zoomer_action.triggered.connect(self.update_zoomer_opts)

        self.zoom_factor_label_action = QAction("Zoom factor", self)
        self.zoom_factor_label_action.setEnabled(False)

        self.zoom_factor_1_action = QAction("2x zoom", self)
        self.zoom_factor_2_action = QAction("4x zoom", self)
        self.zoom_factor_3_action = QAction("8x zoom", self)
        self.zoom_factor_4_action = QAction("16x zoom", self)
        self.zoom_factor_1_action.setStatusTip("Magnify zoom region by 2x")
        self.zoom_factor_2_action.setStatusTip("Magnify zoom region by 4x")
        self.zoom_factor_3_action.setStatusTip("Magnify zoom region by 8x")
        self.zoom_factor_4_action.setStatusTip("Magnify zoom region by 16x")
        self.zoom_factor_1_action.setCheckable(True)
        self.zoom_factor_2_action.setCheckable(True)
        self.zoom_factor_3_action.setCheckable(True)
        self.zoom_factor_4_action.setCheckable(True)

        self.zoom_size_label_action = QAction("Zoom region size", self)
        self.zoom_size_label_action.setEnabled(False)

        self.zoom_size_1_action = QAction("9x9 window", self)
        self.zoom_size_2_action = QAction("17x17 window", self)
        self.zoom_size_3_action = QAction("29x29 window", self)
        self.zoom_size_4_action = QAction("45x45 window", self)
        self.zoom_size_5_action = QAction("65x65 window", self)
        self.zoom_size_1_action.setStatusTip("Set zoom region to 9x9 pixels")
        self.zoom_size_2_action.setStatusTip("Set zoom region to 17x17 pixels")
        self.zoom_size_3_action.setStatusTip("Set zoom region to 29x29 pixels")
        self.zoom_size_4_action.setStatusTip("Set zoom region to 45x45 pixels")
        self.zoom_size_5_action.setStatusTip("Set zoom region to 65x65 pixels")
        self.zoom_size_1_action.setCheckable(True)
        self.zoom_size_2_action.setCheckable(True)
        self.zoom_size_3_action.setCheckable(True)
        self.zoom_size_4_action.setCheckable(True)
        self.zoom_size_5_action.setCheckable(True)

        # Group zoomer actions and connect slots
        self.zoom_factor_group = QtGui.QActionGroup(self)
        self.zoom_factor_group.addAction(self.zoom_factor_1_action)
        self.zoom_factor_group.addAction(self.zoom_factor_2_action)
        self.zoom_factor_group.addAction(self.zoom_factor_3_action)
        self.zoom_factor_group.addAction(self.zoom_factor_4_action)
        self.zoom_factor_group.triggered.connect(self.update_zoomer_opts)

        self.zoom_size_group = QtGui.QActionGroup(self)
        self.zoom_size_group.addAction(self.zoom_size_1_action)
        self.zoom_size_group.addAction(self.zoom_size_2_action)
        self.zoom_size_group.addAction(self.zoom_size_3_action)
        self.zoom_size_group.addAction(self.zoom_size_4_action)
        self.zoom_size_group.addAction(self.zoom_size_5_action)
        self.zoom_size_group.triggered.connect(self.update_zoomer_opts)

        # # Mode actions
        # self.mode_group = QtGui.QActionGroup(self)
        # self.mode_single_action = QAction("Single image", self.mode_group)
        # self.mode_dual_action = QAction("Two images", self.mode_group)
        # self.mode_single_action.setCheckable(True)
        # self.mode_dual_action.setCheckable(True)
        # self.mode_single_action.setStatusTip("Display a single image")
        # self.mode_dual_action.setStatusTip("Display two images for comparison")
        # self.mode_single_action.setChecked(True)
        # #self.mode_group.triggered.connect(self.mainview.toggleComparison) # Moved later

        # http://stackoverflow.com/questions/11643221/are-there-default-icons-in-pyqt-pyside
        # TODO: Add icons in a better way. See how Picard does it.
        QIcon.setThemeName("gnome")  # TODO: temporary
        self.open_action.setIcon(QIcon.fromTheme("document-open"))
        self.close_action.setIcon(QIcon.fromTheme("window-close"))
        self.exit_action.setIcon(QIcon.fromTheme("application-exit"))
        self.about_action.setIcon(QIcon.fromTheme("help-about"))

    def create_menus(self):
        """Setup the menus."""
        menu = self.menuBar().addMenu("&File")
        menu.addAction(self.open_action)
        menu.addAction(self.close_action)
        menu.addSeparator()
        # menu.addAction(self.mode_single_action)
        # menu.addAction(self.mode_dual_action)
        # menu.addSeparator()
        menu.addAction(self.exit_action)
        menu = self.menuBar().addMenu("Image")
        menu.addAction(self.prop_action)
        menu.addAction(self.range_action)
        menu.addAction(self.note_action)
        # submenu = menu.addMenu("Mode")
        # submenu.addAction(self.mode_single_action)
        # submenu.addAction(self.mode_split_action)
        # submenu.addAction(self.mode_fade_action)
        menu = self.menuBar().addMenu("Zoomer")
        menu.addAction(self.zoomer_action)
        menu.addSeparator()
        menu.addAction(self.zoom_factor_label_action)
        menu.addAction(self.zoom_factor_1_action)
        menu.addAction(self.zoom_factor_2_action)
        menu.addAction(self.zoom_factor_3_action)
        menu.addAction(self.zoom_factor_4_action)
        menu.addSeparator()
        menu.addAction(self.zoom_size_label_action)
        menu.addAction(self.zoom_size_1_action)
        menu.addAction(self.zoom_size_2_action)
        menu.addAction(self.zoom_size_3_action)
        menu.addAction(self.zoom_size_4_action)
        menu.addAction(self.zoom_size_5_action)
        menu = self.menuBar().addMenu("&Help")
        menu.addAction(self.about_action)

        # Deactivate menus by default
        self.range_action.setEnabled(False)
        self.prop_action.setEnabled(False)
        self.close_action.setEnabled(False)

    @QtCore.Slot()
    def open_file(self):
        """Display open file dialog."""
        filename = QtGui.QFileDialog.getOpenFileName(self,
                                                     "Open SIR file",
                                                     QtCore.QDir.homePath(),
                                                     ("SIR files (*.sir *.ave)"
                                                      ";;Any file (*)")
                                                     )
        if py_binding == 'PySide':
            filename = filename[0]
        if filename:
            self.load_sir(filename)

    def load_sir(self, filename):
        """Load in the SIR file."""
        if os.access(filename, os.F_OK | os.R_OK):
            self.statusBar().showMessage("Loading")
            self.mainview.load_sir(filename)
            self.statusBar().showMessage("Loaded", 2000)

            # Activate menus
            self.range_action.setEnabled(True)
            self.prop_action.setEnabled(True)
            self.close_action.setEnabled(True)
        else:
            logging.warning("Can't open {}".format(filename))
            # TODO: Alert the user via GUI

    @QtCore.Slot()
    def close_file(self):
        """Close file."""
        logging.info("Closing SIR file")
        self.mainview.close_file()
        self.statusBar().showMessage("SIR closed", 2000)

        # That was the last file, so disable stuff
        if len(self.mainview.sir_files) == 0:
            self.status_stacked.setVisible(False)
            self.zoom_win.hide()

            # Deactivate menus
            self.range_action.setEnabled(False)
            self.prop_action.setEnabled(False)
            self.close_action.setEnabled(False)

    @QtCore.Slot()
    def show_about(self):
        """Display about popup."""
        about_text = """
                Dame {}
                Copyright 2014 Richard Lindsley
                Dame is a SIR file viewer""".format(version_string)
        QMessageBox.about(self, "About", dedent(about_text))

    @QtCore.Slot()
    def show_range(self):
        """Display image range popup."""
        win = RangeWindow()
        win.min_text.setText(str(
            self.mainview.sir_files[self.mainview.cur_tab]['vmin']))
        win.max_text.setText(str(
            self.mainview.sir_files[self.mainview.cur_tab]['vmax']))
        if win.exec_() == QtGui.QDialog.Accepted:
            win_range = win.getRange()
            self.mainview.sir_files[self.mainview.cur_tab]['vmin'] = \
                win_range[0]
            self.mainview.sir_files[self.mainview.cur_tab]['vmax'] = \
                win_range[1]
            self.mainview.update_image(self.mainview.cur_tab)
            self.mainview.update_view()

    @QtCore.Slot()
    def print_header(self):
        """Display SIR header info."""
        sir_head = libsir.print_sir_head(
            self.mainview.sir_files[self.mainview.cur_tab]['header'])
        # TODO: Maybe make this a modeless dialog instead of modal? Use a dock
        # widget?
        box = QMessageBox()
        box.setText(dedent(sir_head))
        box.setIcon(QMessageBox.Information)
        box.exec_()

    def update_zoomer(self):
        """Update the zoomer, both the image as well as the popup."""
        cur_tab = self.mainview.cur_tab
        if 'pix_loc' not in self.mainview.sir_files[cur_tab]:
            return
        try:
            loc = self.mainview.sir_files[cur_tab]['pix_loc']
            rect_w = self.mainview.sir_files[cur_tab]['zoomer_size']
            winsize = rect_w * \
                self.mainview.sir_files[cur_tab]['zoomer_factor']
            if cur_tab == "split":
                pixmaps = (self.mainview.sir_files['left']['pixmap'].copy(),
                           self.mainview.sir_files['right']['pixmap'].copy())
            else:
                pixmaps = \
                    (self.mainview.sir_files[cur_tab]['pixmap'].copy(),)

            for pixmap_i, pixmap in enumerate(pixmaps):
                # Upper left corner
                if loc.x() < rect_w/2:
                    rect_x = -0.5
                elif loc.x() > pixmap.width() - rect_w/2:
                    rect_x = pixmap.width() - rect_w - 0.5
                else:
                    rect_x = loc.x() - rect_w/2
                if loc.y() < rect_w/2:
                    rect_y = -0.5
                elif loc.y() > pixmap.height() - rect_w/2:
                    rect_y = pixmap.height() - rect_w - 0.5
                else:
                    rect_y = loc.y() - rect_w/2

                rect_x += 1
                rect_y += 1

                # Draw the image with the zoomer region outlined
                p = QtGui.QPainter()
                p.begin(pixmap)
                p.setPen(QtGui.QColor("#FFFFFF"))  # White stroke
                p.drawRect(rect_x, rect_y, rect_w, rect_w)
                p.end()
                if cur_tab in ("left", "right", "cross"):
                    self.mainview.single_image.image.setPixmap(pixmap)
                elif cur_tab in ("split", ):
                    if pixmap_i == 0:
                        self.mainview.left_image.image.setPixmap(pixmap)
                    elif pixmap_i == 1:
                        self.mainview.right_image.image.setPixmap(pixmap)
                    else:
                        logging.warning("pixmap_i is {}".format(pixmap_i))

            # Update the zoomer window
            if cur_tab == "split":
                pixmaps = (self.mainview.sir_files['left']['pixmap'],
                           self.mainview.sir_files['right']['pixmap'])
            else:
                pixmaps = (self.mainview.sir_files[cur_tab]['pixmap'],)

            if len(pixmaps) == 2:
                zoom_pixmap = QPixmap(2*winsize, winsize)

            for pixmap_i, pixmap_src in enumerate(pixmaps):
                # extract the zoomer region
                pixmap = pixmap_src.copy(rect_x, rect_y, rect_w, rect_w)
                # scale it
                pixmap = pixmap.scaled(winsize, winsize,
                                       Qt.KeepAspectRatioByExpanding)

                # Add crosshair to zoomer window; note that the crosshair
                # won't be centered if the region is at the edges
                p = QtGui.QPainter()
                p.begin(pixmap)
                # Highlight selected pixel
                # p.setPen(QtGui.QColor("#000000"))  # Black stroke
                p.setPen(QtGui.QColor("#FFFFFF"))  # White stroke
                zoom_fac = self.mainview.sir_files[cur_tab]['zoomer_factor']
                # Top left of magnified pixel
                mag_pix = (zoom_fac * (loc.x() - rect_x + 1) - zoom_fac/2,
                           zoom_fac * (loc.y() - rect_y + 1) - zoom_fac/2)
                # Center of magnified pixel
                mag_pix_cen = (zoom_fac * (loc.x() - rect_x + 1),
                               zoom_fac * (loc.y() - rect_y + 1))
                p.drawRect(mag_pix[0], mag_pix[1], zoom_fac, zoom_fac)
                # Draw crosshairs
                p.setPen(QtGui.QColor("#FFFFFF"))  # White stroke
                # vertical line, top
                p.drawLine(mag_pix_cen[0], 0, mag_pix_cen[0], mag_pix[1]-1)
                # vertical line, bottom
                p.drawLine(mag_pix_cen[0], mag_pix[1]+zoom_fac,
                           mag_pix_cen[0], winsize-0)
                # horizontal line, left
                p.drawLine(0, mag_pix_cen[1], mag_pix[0]-1, mag_pix_cen[1])
                # horizontal line, right
                p.drawLine(mag_pix[0]+zoom_fac, mag_pix_cen[1],
                           winsize-0, mag_pix_cen[1])
                p.end()

                if len(pixmaps) == 1:
                    self.zoom_win_im.setPixmap(pixmap)
                else:
                    p = QtGui.QPainter(zoom_pixmap)
                    p.drawPixmap(pixmap_i * winsize, 0, pixmap)
                    self.zoom_win_im.setPixmap(zoom_pixmap)

            self.zoom_win_im.setHidden(False)
            self.zoom_win_im.adjustSize()

        except KeyError as err:
            logging.warning("Can't find {}".format(err))

    def update_statusbar(self):
        """Update the status bar."""
        if self.mainview.cur_tab in ("left", "right"):
            vmin = self.mainview.sir_files[self.mainview.cur_tab]['vmin']
            vmax = self.mainview.sir_files[self.mainview.cur_tab]['vmax']
            self.status_stacked.setVisible(True)
            self.status_stacked.setCurrentIndex(0)
            self.status_sing_pixinfo.setText(
                "min: {}, max: {}".format(vmin, vmax))
            self.status_sing_coord.setVisible(False)
        elif self.mainview.cur_tab in ("split", "fade"):
            vmin_l = self.mainview.sir_files['left']['vmin']
            vmax_l = self.mainview.sir_files['left']['vmax']
            vmin_r = self.mainview.sir_files['right']['vmin']
            vmax_r = self.mainview.sir_files['right']['vmax']
            self.status_stacked.setVisible(True)
            self.status_stacked.setCurrentIndex(1)
            self.status_left_pixinfo.setText(
                "min: {} max: {}".format(vmin_l, vmax_l))
            self.status_right_pixinfo.setText(
                "min: {} max: {}".format(vmin_r, vmax_r))
            self.status_comp_coord.setVisible(False)

    def update_statusbar_pos(self, x_im, y_im):
        """Update with position at image index x, y."""
        self.statusBar().clearMessage()
        nsx = self.mainview.sir_files[self.mainview.cur_tab]['header'].nsx
        nsy = self.mainview.sir_files[self.mainview.cur_tab]['header'].nsy
        # Convert from 0-based to 1-based indexing
        # (I've double-checked the values returned here using sir_util2a)
        y = nsy - y_im  # Convert image y coord to SIR y coord
        x = x_im + 1
        if x > 0 and y > 0 and x <= nsx and y <= nsy:
            # Note that sir_data is 0-based indexing, but pix2latlon is 1-based
            cur_sir = self.mainview.sir_files[self.mainview.cur_tab]
            lon, lat = libsir.pix2latlon(x, y, cur_sir['header'])
            if self.mainview.cur_tab in ("left", "right"):
                self.status_sing_coord.setVisible(True)
                stat_text = ("x = {}, y = {}   "
                             "lat = {:0.4f}, lon = {:0.4f} "
                             "value = {:0.4f}").format(x, y, lat, lon,
                                                       cur_sir['data'][y_im, x_im])
                self.status_sing_coord.setText(stat_text)
            elif self.mainview.cur_tab in ("split", "fade"):
                left_sir = self.mainview.sir_files['left']
                right_sir = self.mainview.sir_files['right']
                self.status_comp_coord.setVisible(True)
                stat_text = ("x = {}, y = {}   "
                             "lat = {:0.4f}, lon = {:0.4f} "
                             "left value = {:0.4f} "
                             "right value = {:0.4f}").format(
                                 x, y, lat, lon,
                                 left_sir['data'][y_im, x_im],
                                 right_sir['data'][y_im, x_im])
                self.status_comp_coord.setText(stat_text)

    def sizeHint(self):
        """Override the suggested size."""
        return QtCore.QSize(1000, 800)

    # Menu events
    @QtCore.Slot()
    def update_zoomer_opts(self, draw_win=True):
        """Given a menu change, this sets zoomer options and updates."""
        file_dict = self.mainview.sir_files[self.mainview.cur_tab]
        # Is zoomer enabled?
        file_dict['zoomer_on'] = self.zoomer_action.isChecked()

        # Find the zoom factor
        zfactor = self.zoom_factor_group.checkedAction()
        if zfactor is self.zoom_factor_1_action:
            file_dict['zoomer_factor'] = 2
        elif zfactor is self.zoom_factor_2_action:
            file_dict['zoomer_factor'] = 4
        elif zfactor is self.zoom_factor_3_action:
            file_dict['zoomer_factor'] = 8
        elif zfactor is self.zoom_factor_4_action:
            file_dict['zoomer_factor'] = 16

        # Find the zoom size
        zsize = self.zoom_size_group.checkedAction()
        if zsize is self.zoom_size_1_action:
            file_dict['zoomer_size'] = 9
        elif zsize is self.zoom_size_2_action:
            file_dict['zoomer_size'] = 17
        elif zsize is self.zoom_size_3_action:
            file_dict['zoomer_size'] = 29
        elif zsize is self.zoom_size_4_action:
            file_dict['zoomer_size'] = 45
        elif zsize is self.zoom_size_5_action:
            file_dict['zoomer_size'] = 65

        if draw_win:
            # Compute zoomer window size and show/hide it
            winsize = file_dict['zoomer_size'] * file_dict['zoomer_factor']
            if self.mainview.cur_tab == "split":
                self.zoom_win.resize(2*winsize, winsize)
                self.zoom_win.setFixedSize(2*winsize, winsize)
            else:
                self.zoom_win.resize(winsize, winsize)
                self.zoom_win.setFixedSize(winsize, winsize)

            if file_dict['zoomer_on']:
                self.zoom_win.show()
            else:
                self.zoom_win.hide()

            # Update zoomer
            self.update_zoomer()

    # Keyboard events
    def keyPressEvent(self, key):
        """Handle some keypresses."""
        if len(self.mainview.sir_files) == 0:
            key.ignore()
            return

        if 'pix_loc' not in self.mainview.sir_files[self.mainview.cur_tab]:
            # Don't do anything if we don't have a coord yet
            key.ignore()
            return

        # Increment im_pos if valid key
        # Note that im_pos is 0-based, so
        # it ranges from 0 to nsx-1/nsy-1 inclusive
        im_pos = self.mainview.sir_files[self.mainview.cur_tab]['pix_loc']
        nsx = self.mainview.sir_files[self.mainview.cur_tab]['header'].nsx
        nsy = self.mainview.sir_files[self.mainview.cur_tab]['header'].nsy
        delta = 5 if key.modifiers() == Qt.ShiftModifier else 1
        if key.key() == Qt.Key_J:
            # Down
            if im_pos.y() + delta < nsy:
                im_pos.setY(im_pos.y() + delta)
        elif key.key() == Qt.Key_K:
            # Up
            if im_pos.y() - delta >= 0:
                im_pos.setY(im_pos.y() - delta)
        elif key.key() == Qt.Key_H:
            # Left
            if im_pos.x() - delta >= 0:
                im_pos.setX(im_pos.x() - delta)
        elif key.key() == Qt.Key_L:
            # Right
            if im_pos.x() + delta < nsx:
                im_pos.setX(im_pos.x() + delta)
        else:
            key.ignore()
            return

        # Update stuff with our new position
        self.mainview.sir_files[self.mainview.cur_tab]['pix_loc'] = im_pos
        self.update_zoomer()
        self.update_statusbar_pos(im_pos.x(), im_pos.y())
Ejemplo n.º 10
0
class InfoFrame(QFrame):
    def __init__(self, parent=None):
        super(InfoFrame, self).__init__(parent)

        self.mainLayout = QVBoxLayout()
        
        self.titleLabel = QLabel(u'')
        self.infoLabel = QLabel(u'')

        self.dockButtonUp = QPushButton()
        self.dockButtonDown = QPushButton()

        self.mainLayout.addWidget(self.dockButtonUp)
        self.mainLayout.addWidget(self.titleLabel)
        self.mainLayout.addWidget(self.infoLabel)
        self.mainLayout.addWidget(self.dockButtonDown)
        self.setLayout(self.mainLayout)
        
        self.initComposition()
        self.initComponents()
        self.initActions()

        self.offset = QPoint()
        
    def initComposition(self):
        self.setWindowFlags(Qt.ToolTip)
        self.setStyleSheet('''QFrame { background-color: khaki;
                            border: 1px solid black;
                            border-radius: 4px; }
                            QLabel { border: none; }''')
        
        self.setMaximumWidth(I_WIDTH)
        
    def initComponents(self):
        self.titleLabel.setAlignment(Qt.AlignCenter)
#        self.infoLabel.setAlignment(Qt.AlignCenter)
        
        self.titleLabel.setWordWrap(True)
        self.infoLabel.setWordWrap(True)
        self.infoLabel.setTextFormat(Qt.RichText)
        
        self.dockButtonUp.setHidden(True)
        self.dockButtonUp.setCheckable(True)
        self.dockButtonUp.setMaximumHeight(8)
        self.dockButtonUp.setStyleSheet('QWidget { background-color: khaki; }')

        self.dockButtonDown.setHidden(True)
        self.dockButtonDown.setCheckable(True)
        self.dockButtonDown.setMaximumHeight(8)
        self.dockButtonDown.setStyleSheet('QWidget { background-color: khaki; }')

        self.filter = InfoFilter()
        self.setAttribute(Qt.WA_Hover, True)
        self.installEventFilter(self.filter)

        self.offset = QPoint()

        font = QFont(FONTS_DICT['info'][0], FONTS_DICT['info'][2])
        self.titleLabel.setFont(font)
        self.infoLabel.setFont(font)

    def initActions(self):
        self.dockButtonUp.clicked.connect(self.setTopPosition)
        self.dockButtonDown.clicked.connect(self.setBottomPosition)

        self.setContextMenuPolicy(Qt.ActionsContextMenu)
        self.detach = QAction('Detatch', self)
        self.detach.setCheckable(True)
        self.addAction(self.detach)
        self.addAction(QAction('Hide', self, triggered=self.hideInfo))
        
    def updateContents(self, index):
        content = infoContens(index)
        self.titleLabel.setText('<b>' + content['title'] + '</b>')
        self.infoLabel.setText(content['info'])
        self.adjustSize()

    def setTopPosition(self):
        self.dockButtonDown.setChecked(False)
        self.jumpPositionUnchecked()

    def setBottomPosition(self):
        self.dockButtonUp.setChecked(False)
        self.jumpPositionUnchecked()

    def jumpPositionUnchecked(self):
        if self.detach.isChecked():
            self.detach.setChecked(False)
            self.parent().updateInfoPosition()
            self.detach.setChecked(True)
        else:
            self.parent().updateInfoPosition()
        
    def updateCornersMask(self):
        self.setMask(roundCorners(self.rect(), 5))

    def hideInfo(self):
        self.parent().toggleInfo.setChecked(False)
        self.hide()

    #------------ events -------------#
    def showEvent(self, event):
        self.adjustSize()

    def mousePressEvent(self, event):
        event.accept()
        self.offset = event.globalPos() - self.pos()

    def mouseMoveEvent(self, event):
        event.accept()
        self.move(event.globalPos() - self.offset)

    def mouseReleaseEvent(self, event):
        event.accept()
        self.offset = QPoint()
Ejemplo n.º 11
0
class Master(QMainWindow):
    """A manager to synchronise and control experiment modules.
    
    Initiates the Andor camera and connects its completed acquisition
    signal to the image analysis and the image saving modules.
    Uses the queue module to create the list of sequences to run,
    and the bridge module to communicate with Dexter.
    This master module will define the run number. It must confirm that
    each Dexter sequence has run successfully in order to stay synchronised.
    Keyword arguments:
    state_config -- path to the file that saved the previous state.
                    Default directories for camera settings and image 
                    saving are also saved in this file.
    image_analysis -- a class inheriting QMainWindow that can perform all of the
                    required image analysis methods
    """
    def __init__(self,
                 state_config='.\\state',
                 image_analysis=settings_window):
        super().__init__()
        self.types = OrderedDict([('File#', int), ('Date', str),
                                  ('CameraConfig', str), ('SaveConfig', str),
                                  ('MasterGeometry', intstrlist),
                                  ('AnalysisGeometry', intstrlist),
                                  ('SequencesGeometry', intstrlist)])
        self.stats = OrderedDict([
            ('File#', 0), ('Date', time.strftime("%d,%B,%Y")),
            ('CameraConfig',
             '.\\andorcamera\\Standard modes\\ExExposure_config.dat'),
            ('SaveConfig', '.\\config\\config.dat'),
            ('MasterGeometry', [10, 10, 500, 150]),
            ('AnalysisGeometry', [1400, 400, 600, 500]),
            ('SequencesGeometry', [20, 100, 1000, 800])
        ])
        self.camera_pause = 0  # time in seconds to wait for camera to start acquisition.
        self.ts = {
            label: time.time()
            for label in
            ['init', 'waiting', 'blocking', 'msg start', 'msg end']
        }
        sv_dirs = event_handler.get_dirs(self.stats['SaveConfig'])
        # if not any(os.path.exists(svd) for svd in sv_dirs.values()): # ask user to choose valid config file
        startn = self.restore_state(file_name=state_config)
        # choose which image analyser to use from number images in sequence
        self.init_UI(startn)
        # initialise the thread controlling run # and emitting images
        self.rn = runnum(
            camera(config_file=self.stats['CameraConfig']),  # Andor camera
            event_handler(self.stats['SaveConfig']),  # image saver
            image_analysis(results_path=sv_dirs['Results Path: '],
                           im_store_path=sv_dirs['Image Storage Path: ']
                           ),  # image analysis
            atom_window(last_im_path=sv_dirs['Image Storage Path: ']
                        ),  # check if atoms are in ROIs to trigger experiment
            Previewer(),  # sequence editor
            n=startn,
            m=1,
            k=0)
        # now the signals are connected, send camera settings to image analysis
        if self.rn.cam.initialised > 2:
            check = self.rn.cam.ApplySettingsFromConfig(
                self.stats['CameraConfig'])

        self.rn.server.dxnum.connect(
            self.Dx_label.setText)  # synchronise run number
        self.rn.server.textin.connect(self.respond)  # read TCP messages
        self.status_label.setText('Initialising...')
        QTimer.singleShot(
            0, self.idle_state)  # takes a while for other windows to load

        # self.rn.check.showMaximized()
        self.rn.seq.setGeometry(*self.stats['SequencesGeometry'])
        self.rn.seq.show()
        self.rn.sw.setGeometry(*self.stats['AnalysisGeometry'])
        self.rn.sw.show()
        self.rn.sw.show_analyses(show_all=True)

        self.mon_win = MonitorStatus()
        self.mon_win.start_button.clicked.connect(self.start_monitor)
        self.mon_win.stop_button.clicked.connect(self.stop_monitor)
        self.rn.monitor.textin[str].connect(self.mon_win.set_label)
        self.rn.monitor.textin.connect(self.mon_win.set_connected)
        # set a timer to update the dates 2s after midnight:
        t0 = time.localtime()
        QTimer.singleShot((86402 - 3600 * t0[3] - 60 * t0[4] - t0[5]) * 1e3,
                          self.reset_dates)

    def idle_state(self):
        """When the master thread is not processing user events, it is in the idle states.
        The status label is also used as an indicator for DExTer's current state."""
        self.status_label.setText('Idle')

    def restore_state(self, file_name='./state'):
        """Use the data stored in the given file to restore the file # for
        synchronisation if it is the same day, and use the same config files."""
        try:
            with open(file_name, 'r') as f:
                for line in f:
                    if len(line.split(
                            '=')) == 2:  # there should only be one = per line
                        key, val = line.replace('\n', '').split('=')
                        try:
                            self.stats[key] = self.types[key](val)
                        except KeyError as e:
                            logger.warning(
                                'Failed to load PyDex state line: ' + line +
                                '\n' + str(e))
        except FileNotFoundError as e:
            logger.warning(
                'PyDex master settings could not find the state file.\n' +
                str(e))
        if self.stats['Date'] == time.strftime(
                "%d,%B,%Y"):  # restore file number
            return self.stats['File#']  # [Py]DExTer file number
        else:
            return 0

    def make_label_edit(self,
                        label_text,
                        layout,
                        position=[0, 0, 1, 1],
                        default_text='',
                        validator=False):
        """Make a QLabel with an accompanying QLineEdit and add them to the 
        given layout with an input validator. The position argument should
        be [row number, column number, row width, column width]."""
        label = QLabel(label_text, self)
        layout.addWidget(label, *position)
        line_edit = QLineEdit(self)
        if np.size(position) == 4:
            position[1] += 1
        layout.addWidget(line_edit, *position)
        line_edit.setText(default_text)
        if validator:
            line_edit.setValidator(validator)
        return label, line_edit

    def init_UI(self, startn=0):
        """Create all of the widget objects required
        startn: the initial run number loaded from previous state"""
        self.centre_widget = QWidget()
        self.centre_widget.layout = QGridLayout()
        self.centre_widget.setLayout(self.centre_widget.layout)
        self.setCentralWidget(self.centre_widget)

        #### menubar at top gives options ####
        menubar = self.menuBar()

        show_windows = menubar.addMenu('Windows')
        menu_items = []
        for window_title in [
                'Image Analyser', 'Camera Status', 'Image Saver', 'TCP Server',
                'Sequence Previewer', 'Atom Checker', 'Monitor'
        ]:
            menu_items.append(QAction(window_title, self))
            menu_items[-1].triggered.connect(self.show_window)
            show_windows.addAction(menu_items[-1])

        sync_menu = menubar.addMenu('Run Settings')
        self.sync_toggle = QAction('Sync with DExTer',
                                   sync_menu,
                                   checkable=True,
                                   checked=True)
        self.sync_toggle.setChecked(True)
        self.sync_toggle.toggled.connect(self.sync_mode)
        sync_menu.addAction(self.sync_toggle)

        self.check_rois = QAction('Trigger on atoms loaded',
                                  sync_menu,
                                  checkable=True,
                                  checked=False)
        self.check_rois.setChecked(False)
        self.check_rois.setEnabled(False)  # not functional yet
        sync_menu.addAction(self.check_rois)

        reset_date = QAction('Reset date', sync_menu, checkable=False)
        reset_date.triggered.connect(self.reset_dates)
        sync_menu.addAction(reset_date)

        #### status of the master program ####
        self.status_label = QLabel('Initiating...', self)
        self.centre_widget.layout.addWidget(self.status_label, 0, 0, 1, 3)

        Dx_label = QLabel('Run #: ', self)
        self.centre_widget.layout.addWidget(Dx_label, 1, 0, 1, 1)
        self.Dx_label = QLabel(str(startn), self)
        self.centre_widget.layout.addWidget(self.Dx_label, 1, 1, 1, 1)

        # actions that can be carried out
        self.actions = QComboBox(self)
        self.actions.addItems([
            'Run sequence', 'Multirun run', 'Pause multirun',
            'Resume multirun', 'Cancel multirun', 'TCP load sequence',
            'TCP load sequence from string', 'Save DExTer sequence',
            'Cancel Python Mode', 'Resync DExTer', 'Start acquisition'
        ])
        self.actions.resize(self.actions.sizeHint())
        self.centre_widget.layout.addWidget(self.actions, 2, 0, 1, 1)

        self.action_button = QPushButton('Go', self, checkable=False)
        self.action_button.clicked[bool].connect(self.start_action)
        self.action_button.resize(self.action_button.sizeHint())
        self.centre_widget.layout.addWidget(self.action_button, 2, 1, 1, 1)

        # text box to allow user to specify DExTer sequence file
        _, self.seq_edit = self.make_label_edit('DExTer sequence file: ',
                                                self.centre_widget.layout,
                                                position=[3, 0, 1, 1])
        # button to load sequence location from file browser
        self.seq_browse = QPushButton('Browse', self, checkable=False)
        self.seq_browse.clicked[bool].connect(self.browse_sequence)
        self.seq_browse.resize(self.seq_browse.sizeHint())
        self.centre_widget.layout.addWidget(self.seq_browse, 3, 2, 1, 1)

        #### choose main window position, dimensions: (xpos,ypos,width,height)
        self.setGeometry(*self.stats['MasterGeometry'])
        self.setWindowTitle('PyDex Master')
        self.setWindowIcon(QIcon('docs/pydexicon.png'))

    def reset_dates(self, auto=True):
        """Reset the date in the image saving and analysis, 
        then display the updated date"""
        t0 = time.localtime()
        self.stats['Date'] = time.strftime("%d,%B,%Y", t0)
        date = self.rn.reset_dates(t0)
        if not hasattr(self.sender(),
                       'text'):  # don't set timer if user pushed button
            QTimer.singleShot(
                (86402 - 3600 * t0[3] - 60 * t0[4] - t0[5]) * 1e3,
                self.reset_dates)  # set the next timer to reset dates
        logger.info(time.strftime("Date reset: %d %B %Y", t0))

    def show_window(self):
        """Show the window of the submodule or adjust its settings."""
        if self.sender().text() == 'Image Analyser':
            self.rn.sw.show()

        elif self.sender().text() == 'Camera Status':
            if self.rn.cam.initialised:
                msg = 'Current state: ' + self.rn.cam.AF.GetStatus(
                ) + '\nChoose a new config file: '
            else:
                msg = 'Camera not initialised. See log file for details. Press OK to retry.'
            newfile = self.rn.sw.try_browse(
                title='Choose new config file',
                file_type='config (*.dat);;all (*)',
                defaultpath=os.path.dirname(self.stats['CameraConfig']))
            text, ok = QInputDialog.getText(
                self,
                'Camera Status',
                msg,
                text=newfile if newfile else self.stats['CameraConfig'])
            if text and ok:
                if self.rn.cam.initialised > 2:
                    if self.rn.cam.AF.GetStatus() == 'DRV_ACQUIRING':
                        self.rn.cam.AF.AbortAcquisition()
                    check = self.rn.cam.ApplySettingsFromConfig(text)
                    if not any(check):
                        self.status_label.setText('Camera settings config: ' +
                                                  text)
                        self.stats['CameraConfig'] = text
                    else:
                        self.status_label.setText(
                            'Failed to update camera settings.')
                else:
                    self.reset_camera(text)

        elif self.sender().text() == 'Image Saver':
            text, ok = QInputDialog.getText(
                self,
                'Image Saver',
                self.rn.sv.print_dirs(self.rn.sv.dirs_dict.items()) +
                '\nEnter the path to a config file to reset the image saver: ',
                text=self.stats['SaveConfig'])
            if text and ok:
                remove_slot(self.rn.im_save, self.rn.sv.add_item, False)
                self.rn.sv = event_handler(text)
                if self.rn.sv.image_storage_path:
                    self.status_label.setText('Image Saver config: ' + text)
                    remove_slot(self.rn.im_save, self.rn.sv.add_item, True)
                    self.stats['SaveConfig'] = text
                else:
                    self.status_label.setText('Failed to find config file.')

        elif self.sender().text() == 'Sequence Previewer':
            self.rn.seq.show()
        elif self.sender().text() == 'TCP Server':
            info = 'Trigger server is running.\n' if self.rn.trigger.isRunning(
            ) else 'Trigger server stopped.\n'
            if self.rn.server.isRunning():
                msgs = self.rn.server.get_queue()
                info += "TCP server is running. %s queued message(s)." % len(
                    msgs)
                info += '\nCommand Enum | Length |\t Message\n'
                for enum, textlength, text in msgs[:5]:
                    info += enum + ' | ' + text[:20]
                    if textlength > 20: info += '...'
                    info += '\n'
                if len(msgs) > 5:
                    info += '...\n'
            else:
                info += "TCP server stopped."
            reply = QMessageBox.question(
                self, 'TCP Server Status',
                info + "\nDo you want to restart the server?",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if reply == QMessageBox.Yes:
                self.action_button.setEnabled(True)
                self.rn.seq.mr.mr_queue = []
                self.rn.multirun = False
                self.rn.reset_server(
                    force=True)  # stop and then restart the servers
                self.rn.server.add_message(
                    TCPENUM['TCP read'],
                    'Sync DExTer run number\n' + '0' * 2000)
            elif reply == QMessageBox.No:
                self.rn.reset_server(
                    force=False)  # restart the server if it stopped
        elif self.sender().text() == 'Atom Checker':
            self.rn.check.showMaximized()
        elif self.sender().text() == 'Monitor':
            self.mon_win.show()

    def start_monitor(self, toggle=True):
        """Send a TCP command to the monitor to start its acquisition."""
        self.mon_win.start_check()
        self.rn.monitor.add_message(self.rn._n, 'start')

    def stop_monitor(self, toggle=True):
        """Send a TCP command to the monitor to stop its acquisition."""
        self.mon_win.start_check()
        self.rn.monitor.add_message(self.rn._n, 'stop')

    def browse_sequence(self, toggle=True):
        """Open the file browser to search for a sequence file, then insert
        the file path into the DExTer sequence file line edit
        start_dir: the directory to open initially."""
        try:
            if 'PyQt4' in sys.modules:
                file_name = QFileDialog.getOpenFileName(
                    self, 'Select A Sequence', '', 'Sequence (*.xml);;all (*)')
            elif 'PyQt5' in sys.modules:
                file_name, _ = QFileDialog.getOpenFileName(
                    self, 'Select A Sequence', '', 'Sequence (*.xml);;all (*)')
            if file_name:
                self.seq_edit.setText(file_name.replace('/', '\\'))
                self.rn.seq.load_seq_from_file(file_name)
        except OSError:
            pass  # user cancelled - file not found

    def reset_camera(self, ancam_config='./andorcamera/ExExposure_config.dat'):
        """Close the camera and then start it up again with the new setting.
        Sometimes after being in crop mode the camera fails to reset the 
        ROI and so must be closed and restarted."""
        try:
            self.rn.cam.SafeShutdown()
        except:
            logger.warning('Andor camera safe shutdown failed'
                           )  # probably not initialised
        self.rn.cam = camera(config_file=ancam_config)  # Andor camera
        remove_slot(self.rn.cam.AcquireEnd, self.rn.receive,
                    True)  # connect signal
        self.status_label.setText('Camera settings config: ' + ancam_config)
        self.stats['CameraConfig'] = ancam_config

    def start_action(self):
        """Perform the action currently selected in the actions combobox.
        Run sequence:   Start the camera acquisition, then make 
                        DExTer perform a single run of the 
                        sequence that is currently loaded.
        Multirun run:   Start the camera acquisition, then make 
                        DExTer perform a multirun with the preloaded
                        multirun settings.
        TCP load sequence from string: Tell DExTer to load in the sequence
                        from a string in XML format.
        TCP load sequence:  Tell DExTer to load in the sequence file at
                        the location in the 'DExTer sequence file' label.
        Cancel python mode: send the text 'python mode off' which triggers
                        DExTer to exit python mode.
        Resync DExTer:  send a null message just to resync the run number.
        Start acquisition:  start the camera acquiring without telling
                        DExTer to run. Used in unsynced mode."""
        action_text = self.actions.currentText()
        if action_text == 'Start acquisition' and self.action_button.text(
        ) == 'Go':
            if self.rn.cam.initialised > 2:
                if self.sync_toggle.isChecked():
                    QMessageBox.warning(
                        self, 'Unscyned acquisition',
                        'Warning: started acquisition in synced mode. Without messages to DExTer, the file ID will not update.'
                        +
                        '\nTry unchecking: "Run Settings" > "Sync with DExTer".'
                    )
                self.actions.setEnabled(
                    False)  # don't process other actions in this mode
                self.rn._k = 0  # reset image per run count
                self.action_button.setText('Stop acquisition')
                self.rn.cam.start()  # start acquisition
                self.wait_for_cam(
                )  # wait for camera to initialise before running
                self.status_label.setText('Camera acquiring')
            else:
                logger.warning(
                    'Master: Tried to start camera acquisition but camera is not initialised.'
                )
        elif action_text == 'Start acquisition' and self.action_button.text(
        ) == 'Stop acquisition':
            self.actions.setEnabled(True)
            self.action_button.setText('Go')
            self.end_run()

        if self.rn.server.isRunning():
            if action_text == 'Run sequence':
                # queue up messages: start acquisition, check run number
                self.action_button.setEnabled(
                    False)  # only process 1 run at a time
                self.rn._k = 0  # reset image per run count
                self.rn.server.add_message(TCPENUM['TCP read'],
                                           'start acquisition\n' + '0' * 2000)
                self.rn.monitor.add_message(self.rn._n, 'update run number')
            elif action_text == 'Multirun run':
                if self.rn.seq.mr.check_table():
                    if not self.sync_toggle.isChecked():
                        self.sync_toggle.setChecked(
                            True)  # it's better to multirun in synced mode
                        logger.warning(
                            'Multirun has changed the "sync with DExTer" setting.'
                        )
                    status = self.rn.seq.mr.check_mr_params(
                        self.rn.sv.results_path)  # add to queue if valid
                    self.check_mr_queue(
                    )  # prevent multiple multiruns occurring simultaneously
                else:
                    QMessageBox.warning(
                        self, 'Invalid multirun',
                        'All cells in the multirun table must be populated.')
            elif action_text == 'Resume multirun':
                self.rn.multirun_resume(self.status_label.text())
            elif action_text == 'Pause multirun':
                if 'multirun' in self.status_label.text():
                    self.rn.multirun_go(False, stillrunning=True)
            elif action_text == 'Cancel multirun':
                if 'multirun' in self.status_label.text() or self.rn.multirun:
                    if self.rn.check.checking:
                        self.rn.check.rh.trigger.emit(
                            1)  # send software trigger to end
                    self.rn.multirun_go(False)
                    self.rn.seq.mr.ind = 0
                    self.rn.seq.mr.reset_sequence(self.rn.seq.tr.copy())
            elif action_text == 'TCP load sequence from string':
                self.rn.server.add_message(TCPENUM[action_text],
                                           self.rn.seq.tr.seq_txt)
            elif action_text == 'TCP load sequence':
                self.rn.server.add_message(
                    TCPENUM[action_text],
                    self.seq_edit.text() + '\n' + '0' * 2000)
            elif action_text == 'Save DExTer sequence':
                self.rn.server.add_message(
                    TCPENUM['Save sequence'],
                    'save log file automatic name\n' + '0' * 2000)
            elif action_text == 'Cancel Python Mode':
                self.rn.server.add_message(TCPENUM['TCP read'],
                                           'python mode off\n' + '0' * 2000)
                self.rn.server.add_message(
                    TCPENUM['TCP read'],
                    'Resync DExTer\n' + '0' * 2000)  # for when it reconnects
            elif action_text == 'Resync DExTer':
                self.rn.server.add_message(TCPENUM['TCP read'],
                                           'Resync DExTer\n' + '0' * 2000)

    def trigger_exp_start(self, n=None):
        """Atom checker sends signal saying all ROIs have atoms in, start the experiment"""
        self.rn.check.timer.stop(
        )  # in case the timer was going to trigger the experiment as well
        remove_slot(self.rn.trigger.dxnum, self.reset_cam_signals,
                    True)  # swap signals when msg confirmed
        self.rn.trigger.add_message(TCPENUM['TCP read'],
                                    'Go!' * 600)  # trigger experiment
        # QTimer.singleShot(20, self.resend_exp_trigger) # wait in ms

    def resend_exp_trigger(self, wait=20):
        """DExTer doesn't always receive the first trigger, send another.
        wait -- time in ms before checking if the message was received."""
        if self.rn.check.checking:
            self.rn.trigger.add_message(TCPENUM['TCP read'],
                                        'Go!' * 600)  # in case the first fails
            QTimer.singleShot(wait, self.resend_exp_trigger)  # wait in ms

    def reset_cam_signals(self, toggle=True):
        """Stop sending images to the atom checker, send them to image analysis instead"""
        self.rn.check.checking = False
        remove_slot(self.rn.cam.AcquireEnd, self.rn.receive,
                    not self.rn.multirun)  # send images to analysis
        remove_slot(self.rn.cam.AcquireEnd, self.rn.mr_receive,
                    self.rn.multirun)
        remove_slot(self.rn.cam.AcquireEnd, self.rn.check_receive, False)
        remove_slot(self.rn.trigger.dxnum, self.reset_cam_signals,
                    False)  # only trigger once
        self.rn.trigger.add_message(TCPENUM['TCP read'],
                                    'Go!' * 600)  # flush TCP

    def sync_mode(self, toggle=True):
        """Toggle whether to receive the run number from DExTer,
        or whether to increment the run number every time the expected
        number of images per sequence is received."""
        remove_slot(self.rn.cam.AcquireEnd, self.rn.receive, toggle)
        remove_slot(self.rn.cam.AcquireEnd, self.rn.unsync_receive, not toggle)

    def wait_for_cam(self, timeout=10):
        """Wait (timeout / 10) ms, periodically checking whether the camera
        has started acquiring yet."""
        for i in range(int(timeout)):
            if self.rn.cam.AF.GetStatus() == 'DRV_ACQUIRING':
                time.sleep(self.camera_pause)  # wait for camera to initialise
                break
            time.sleep(1e-4)  # poll camera status to check if acquiring

    def check_mr_queue(self):
        """Check whether it is appropriate to start the queued multiruns.
        This prevents multiple multiruns being sent to DExTer at the same time."""
        num_mrs = len(self.rn.seq.mr.mr_queue)  # number of multiruns queued
        if num_mrs:
            if not self.rn.multirun:
                self.rn.multirun = True
                self.rn.server.add_message(
                    TCPENUM['TCP read'],  # send the first multirun to DExTer
                    'start measure %s' %
                    (self.rn.seq.mr.mr_param['measure'] + num_mrs - 1) + '\n' +
                    '0' * 2000)
            else:
                QTimer.singleShot(10e3,
                                  self.check_mr_queue)  # check again in 10s.

    def respond(self, msg=''):
        """Read the text from a TCP message and then execute the appropriate function."""
        self.ts['msg start'] = time.time()
        self.ts['waiting'] = time.time() - self.ts['msg end']
        if 'finished run' in msg:
            self.end_run(msg)
        elif 'start acquisition' in msg:
            self.status_label.setText('Running')
            if self.check_rois.isChecked(
            ):  # start experiment when ROIs have atoms
                remove_slot(self.rn.check.rh.trigger, self.trigger_exp_start,
                            True)
                self.rn.atomcheck_go()  # start camera acuiring
            elif self.rn.cam.initialised:
                self.rn.cam.start()  # start acquisition
                self.wait_for_cam(
                )  # wait for camera to initialise before running
            else:
                logger.warning('Run %s started without camera acquisition.' %
                               (self.rn._n))
            self.rn.server.priority_messages([
                (TCPENUM['Save sequence'],
                 'save log file automatic name\n' + '0' * 2000),
                (TCPENUM['Run sequence'],
                 'single run ' + str(self.rn._n) + '\n' + '0' * 2000),
                (TCPENUM['TCP read'],
                 'finished run ' + str(self.rn._n) + '\n' + '0' * 2000)
            ])  # second message confirms end
        elif 'start measure' in msg:
            remove_slot(self.rn.seq.mr.progress, self.status_label.setText,
                        True)
            if self.check_rois.isChecked(
            ):  # start experiment when ROIs have atoms
                remove_slot(self.rn.check.rh.trigger, self.trigger_exp_start,
                            True)
                self.rn.atomcheck_go()  # start camera acquiring
            elif self.rn.cam.initialised:
                self.rn.cam.start()  # start acquisition
                self.wait_for_cam()
            else:
                logger.warning('Run %s started without camera acquisition.' %
                               (self.rn._n))
            if 'restart' not in msg:
                self.rn.multirun_go(
                    msg
                )  # might be resuming multirun instead of starting a new one
        elif 'multirun run' in msg:
            if self.check_rois.isChecked(
            ):  # start experiment when ROIs have atoms
                remove_slot(self.rn.check.rh.trigger, self.trigger_exp_start,
                            True)
                self.rn.atomcheck_go()  # start camera in internal trigger mode
            self.rn.multirun_step(msg)
            self.rn._k = 0  # reset image per run count
        elif 'save and reset histogram' in msg:
            self.rn.multirun_save(msg)
        elif 'end multirun' in msg:
            remove_slot(self.rn.seq.mr.progress, self.status_label.setText,
                        False)
            self.rn.multirun_end(msg)
            # self.rn.server.save_times()
            self.end_run(msg)
        elif 'STOPPED' in msg:
            self.status_label.setText(msg)
        self.ts['msg end'] = time.time()
        self.ts['blocking'] = time.time() - self.ts['msg start']
        # self.print_times()

    def end_run(self, msg=''):
        """At the end of a single run or a multirun, stop the acquisition,
        check for unprocessed images, and check synchronisation.
        First, disconnect the server.textin signal from this slot to it
        only triggers once."""
        self.action_button.setEnabled(True)  # allow another command to be sent
        # reset atom checker trigger
        remove_slot(self.rn.check.rh.trigger, self.trigger_exp_start, False)
        if self.rn.trigger.connected:
            remove_slot(self.rn.trigger.textin, self.rn.trigger.clear_queue,
                        True)
            self.rn.trigger.add_message(TCPENUM['TCP read'],
                                        'end connection' * 150)
        try:
            unprocessed = self.rn.cam.EmptyBuffer()
            self.rn.cam.AF.AbortAcquisition()
        except Exception as e:
            logger.warning(
                'Failed to abort camera acquisition at end of run.\n' + str(e))
        # if unprocessed:
        #     reply = QMessageBox.question(self, 'Unprocessed Images',
        # "Process the remaining %s images from the buffer?"%len(unprocessed),
        #         QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        #     if reply == QMessageBox.Yes:
        #         for im in unprocessed:
        #             # image dimensions: (# kscans, width pixels, height pixels)
        #             self.rn.receive(im[0])
        self.idle_state()

    def print_times(self, keys=['waiting', 'blocking']):
        """Print the timings between messages."""
        print(*[key + ': %.4g,\t' % self.ts[key] for key in keys])

    def save_state(self, file_name='./state'):
        """Save the file number and date and config file paths so that they
        can be loaded again when the program is next started."""
        self.stats['File#'] = self.rn._n
        with open(file_name, 'w+') as f:
            for key, val in self.stats.items():
                f.write(key + '=' + str(val) + '\n')

    def closeEvent(self, event):
        """Proper shut down procedure"""
        try:
            self.rn.cam.SafeShutdown()
        except Exception as e:
            logger.warning('camera safe shutdown failed.\n' + str(e))
        self.rn.check.send_rois(
        )  # give ROIs from atom checker to image analysis
        self.rn.sw.save_settings('.\\imageanalysis\\default.config')
        for key, g in [['AnalysisGeometry',
                        self.rn.sw.geometry()],
                       ['SequencesGeometry',
                        self.rn.seq.geometry()],
                       ['MasterGeometry', self.geometry()]]:
            self.stats[key] = [g.x(), g.y(), g.width(), g.height()]
        for obj in self.rn.sw.mw + self.rn.sw.rw + [
                self.rn.sw, self.rn.seq, self.rn.server, self.rn.trigger,
                self.rn.check, self.mon_win
        ]:
            obj.close()
        self.save_state()
        event.accept()
Ejemplo n.º 12
0
class ImportDataDlg(QDialog):
    __isJy = False  # 数据校验成功的标志
    __mlist = []  # 定义一个列表用于保存从excel表中取出的数据

    def __init__(self, iface, parent=None, impType=ImpDateType.SITEANDCELL):
        super(ImportDataDlg, self).__init__()
        self.iface = iface
        self.parent = parent
        self.impType = impType
        self.initView()

    def initView(self):
        if self.impType == ImpDateType.SERVINGCELL:
            self.setWindowTitle(u'相邻小区数据导入')
        else:
            self.setWindowTitle(u'基站和小区数据导入')
        self.setWindowIcon(QIcon('images/logo.png'))
        self.resize(620, 480)

        # 数据表格
        self.tableWidget = QTableWidget(self)
        self.tableWidget.setAlternatingRowColors(True)
        self.tableWidget.setRowCount(7)
        # 设置当前Table不能编辑
        self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # 初始化表格上下文菜单
        self.initTableContextMenu()
        # 初始化表头
        self.initTableHeader()
        # 导入出错列表
        self.listWidget = QListWidget(self)
        # 按钮组
        impBtn = QPushButton(u"导入EXCEL表", self)
        yzBtn = QPushButton(u"数据检验", self)
        impdateBtn = QPushButton(u"导入数据", self)
        btnVBox = QVBoxLayout()
        btnVBox.addWidget(impBtn)
        btnVBox.addWidget(yzBtn)
        btnVBox.addWidget(impdateBtn)
        # 错误列表与按钮组
        hBox = QHBoxLayout()
        hBox.setMargin(20)
        hBox.addWidget(self.listWidget)
        hBox.addLayout(btnVBox)

        self.mbar = QStatusBar(self)
        self.mbar.showMessage(u'准备就绪...')

        self.maction = QToolBar(self)
        self.editAction = QAction(u'编辑', self.maction)
        self.editAction.setCheckable(True)

        self.combox = QComboBox(self)
        self.combox.addItems(HeadsConfig.ImpExcelName)

        self.maction.addWidget(self.combox)
        self.maction.addAction(self.editAction)

        vBox = QVBoxLayout()
        vBox.addWidget(self.maction)
        vBox.addWidget(self.tableWidget)
        vBox.addLayout(hBox)
        vBox.addWidget(self.mbar)

        vBox.setStretchFactor(self.tableWidget, 9)
        vBox.setStretchFactor(hBox, 5)
        vBox.setStretchFactor(self.mbar, 1)

        self.setLayout(vBox)

        QObject.connect(impBtn, SIGNAL('clicked()'), self.impClick)
        QObject.connect(yzBtn, SIGNAL('clicked()'), self.yzClick)
        QObject.connect(impdateBtn, SIGNAL('clicked()'), self.impdateClick)
        QObject.connect(self.editAction, SIGNAL('triggered()'), self.editClick)
        QObject.connect(self.combox, SIGNAL('currentIndexChanged(int)'),
                        self.comboxChange)

        self.listWidget.doubleClicked.connect(self.mlistClicked)
        # self.connect(self.listWidget, SIGNAL("itemDoubleClicked (QListWidgetItem)"), self.mlistClicked)

    def initTableContextMenu(self):
        self.tableWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.popMenu = QMenu(self.tableWidget)
        delAction = QAction(u'删除', self)  # 删除
        self.popMenu.addAction(delAction)

    # 设置表格可以双击修改数据
    def setEditTriggers(self, isTrigger):
        if isTrigger:
            self.tableWidget.setEditTriggers(QAbstractItemView.DoubleClicked)
        else:
            self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)

    # 提供给外部修改状态栏消息
    def setStatusBarMsg(self, msg):
        self.mbar.showMessage(msg)

    # 选框改变时,清空当前表格的全部内容,包括表格头
    def updateType(self, mtype):
        self.impType = mtype
        self.tableWidget.clear()  # 清空表格所有内容
        self.initTableHeader()

    # 初始化表格的每个Item
    def initTable(self, mlist):
        self.tableWidget.setRowCount(len(mlist))
        for (i, v) in enumerate(mlist):
            for (j, item) in enumerate(v):
                if type(item) != str:
                    item = unicode(item)
                if item == None:
                    item = u""
                tabItem = QTableWidgetItem(item)
                tabItem.setTextAlignment(Qt.AlignCenter)
                self.tableWidget.setItem(i, j, tabItem)

    # 初始化错误信息列表
    def initListView(self, mlist):

        for iv in mlist:
            lisItm = QListWidgetItem(self.listWidget)
            lisItm.setTextColor(Qt.red)
            lisItm.setData(Qt.UserRole, iv)
            if isinstance(iv, basestring):
                # 如果错误信息是一行字符串
                lisItm.setText(iv)
            else:
                lisItm.setText(u'第' + unicode(str(iv['row'] + 1)) + u'行,第' +
                               unicode(str(iv['col'] + 1)) + u'列:' + iv['msg'])

    # 初始化Table的头
    def initTableHeader(self):
        self.heads = []
        if self.impType == ImpDateType.SITEANDCELL:
            # 获取当前项目图层的字段名
            cell_layer = getLayerByName(u"小区", self.iface)
            for head in HeadsConfig.SiteANDCellHead:
                self.heads.append(head)
            if len(cell_layer.pendingFields()) > 55:
                for (index, field) in enumerate(cell_layer.pendingFields()):
                    if index > 54:
                        field_name = field.name().strip()
                        self.heads.append(field_name)

        else:
            self.heads = HeadsConfig.ServingCellHead

        self.tableWidget.setColumnCount(len(self.heads))  # 设置表格的列数
        for (i, h) in enumerate(self.heads):
            tabItem = QTableWidgetItem(h)
            self.tableWidget.setHorizontalHeaderItem(i, tabItem)

    # 自定义为Table添加Item
    def addTableItem(self, row, col, content):
        tabItem = QTableWidgetItem(content)
        self.tableWidget.setItem(row, col, tabItem)

    # 修改Item的内容
    def editTableItem(self, row, col, content):
        tabItem = self.tableWidget.item(row, col)
        tabItem.setText(content)
        self.tableWidget.setItem(row, col, tabItem)

    # 从Excel表读取数据(导入Excel表)
    def impClick(self):
        fileName = QFileDialog.getOpenFileName(self, u'基站小区数据导入', '/',
                                               'Excel Files (*.xls *.xlsx)')
        if fileName.strip() != "":
            self.setStatusBarMsg(u'选择完毕:' + fileName)
            importData = GetDataFromExcel(fileName, self.impType, self.heads)
            self.__mlist = []
            self.__mlist.extend(importData.getData())
            self.tableWidget.clearContents()
            self.listWidget.clear()
            self.initTable(self.__mlist)
            self.setStatusBarMsg(u'数据导入完成...')
            self.__isJy = False  # 导入完数据后,说明需要重新验证数据的正确性

        else:
            QMessageBox.information(self.parent, u"错误", u"请选中文件")

    # 数据验证按钮点击事件处理
    def yzClick(self):
        if len(self.__mlist) > 0:
            self.erlist = []  # 定义一个列表用于保存数据验证错误的数据
            # 清楚全部的Item
            if self.listWidget.count() > 0:
                self.listWidget.clear()

            # 根据tableWidget更新self.__mlist
            for (r, items) in enumerate(self.__mlist):
                for (v, item) in enumerate(self.__mlist[r]):
                    if self.tableWidget.item(r, v).text() == u"":
                        continue
                    else:
                        # 跟据self.__mlist[r][v]数据类型进行比对
                        if type(self.__mlist[r][v]) == int:
                            if unicode(self.__mlist[r][v]) != (
                                    self.tableWidget.item(r, v).text()):
                                self.__mlist[r][v] = int(
                                    self.tableWidget.item(r, v).text())
                        elif type(self.__mlist[r][v]) == float:
                            if unicode(self.__mlist[r][v]) != (
                                    self.tableWidget.item(r, v).text()):
                                self.__mlist[r][v] = float(
                                    self.tableWidget.item(r, v).text())
                        elif type(self.__mlist[r][v]) == str:
                            if unicode(self.__mlist[r][v]
                                       ) != self.tableWidget.item(r, v).text():
                                self.__mlist[r][v] = str(
                                    self.tableWidget.item(r, v).text())
                        elif type(self.__mlist[r][v]) == unicode:
                            if (self.__mlist[r][v]) != self.tableWidget.item(
                                    r, v).text():
                                self.__mlist[r][v] = self.tableWidget.item(
                                    r, v).text()
                        else:
                            print type(self.__mlist[r][v])
            # 执行数据校验函数
            self.erlist = checkDataByDataType(self.__mlist, self.impType)
            if len(self.erlist) > 0:
                self.initListView(self.erlist)
                QMessageBox.information(self.parent, u'数据校验',
                                        u'数据校验失败,请检查数据正确性后,再导入到地图中')
                self.__isJy = False
            else:
                QMessageBox.information(self.parent, u'数据校验', u'数据校验成功,没有错误数据')
                self.__isJy = True
        else:
            QMessageBox.warning(self.parent, u'数据校验', u'请先导入Excel数据后再操作!')

    # 导入数据到地图中
    def impdateClick(self):
        if self.__isJy:  # 如果数据校验成功
            if self.impType == ImpDateType.SITEANDCELL:
                # 导入基站小区
                importDataToLayer = ImportDataToLayer(self.iface, self.__mlist,
                                                      self.parent)
                if importDataToLayer.importSiteAndCellData():
                    QMessageBox.information(self.parent, u"导入数据", u"导入数据成功!")
                else:
                    QMessageBox.critical(self.parent, u"导入数据", u"导入数据失败!")

            else:
                # 导入相邻小区
                importDataToLayer = ImportDataToLayer(self.iface, self.__mlist,
                                                      self.parent)
                if importDataToLayer.importSCellData():
                    QMessageBox.information(self.parent, u"导入数据", u"导入数据成功!")
                else:
                    QMessageBox.critical(self.parent, u"导入数据", u"导入数据失败!")
        else:
            QMessageBox.warning(self.parent, u'数据导入', u'请确保校验数据成功后,再导入到地图中')

    # 编辑Action点击事件
    def editClick(self):
        self.setEditTriggers(self.editAction.isChecked())

    # 错误列表双击事件处理
    def mlistClicked(self, listItem):
        itemData = listItem.data(Qt.UserRole)
        self.tableWidget.setFocus()
        self.tableWidget.setCurrentCell(itemData['row'], itemData['col'])

    # 选框改变事件
    def comboxChange(self, index):
        self.updateType(index)

    # 字段验证是否为空
    def __validNull(self, name, col, row, itm, rowitm):
        if itm is None or itm == '':
            tmpMap = {}
            tmpMap['col'] = col
            tmpMap['row'] = row
            tmpMap['msg'] = unicode(name) + u'不能为空'
            tmpMap['item'] = rowitm
            return tmpMap
        else:
            return None

    # 导入数据线程开始信号  绑定函数
    def impStart(self):
        self.setStatusBarMsg(u'准备导入...')

    # 导入数据线程发生异常信号 绑定函数
    def impError(self, e, exception_string):
        self.setStatusBarMsg(u'发生错误:' + unicode(e))
        QMessageBox.warning(self.parent, u'Excel数据导入', u'发生错误:' + unicode(e))

    # 导入数据线程完成信号 绑定函数
    def impFinish(self, mylist):
        self.__mlist = []
        self.__mlist.extend(mylist)
        self.mthread.quit()
        self.mthread.wait()
        self.mthread.deleteLater()
        self.impDateThread.deleteLater()

        self.tableWidget.clearContents()
        self.listWidget.clear()
        self.initTable(self.__mlist)
        self.setStatusBarMsg(u'数据导入完成...')
        self.__isJy = False  # 导入完数据后,说明需要重新验证数据的正确性

    # 导入数据到地图线程发生异常信号 绑定函数
    def impError1(self, e, exception_string):
        self.setStatusBarMsg(u"导入数据发生错误")
        QMessageBox.critical(self, u'数据导入', u"发生错误:" + unicode(e))

    # 导入数据到地图线程完成信号 绑定函数
    def impFinish1(self, mylist):
        self.threadImp.quit()
        self.threadImp.wait()
        self.threadImp.deleteLater()
        self.impFeatureThread.deleteLater()
        remsg = u'数据导入完成!'
        layer = None
        if self.impType == LayerType.SITE:
            # remsg = u'基站' + remsg
            layer = getLayerByName(u'基站', self.iface)
        elif self.impType == LayerType.CELL:
            # remsg = u'小区' + remsg
            layer = getLayerByName(u'小区', self.iface)
        else:
            remsg = u'相邻小区' + remsg
            layer = getLayerByName(u'相邻小区', self.iface)
        self.setStatusBarMsg(remsg)
        layer.updateExtents()  # 更新地图数据
        self.iface.actionDraw().trigger()
        QMessageBox.information(self, u'数据导入', remsg)

        merlist = []
        for eritm in self.erlist:
            merlist.append(eritm['item'])
        self.tableWidget.clearContents()  # 先清楚表格的内容,再将错误的行显示到表格中
        self.initTable(merlist)
Ejemplo n.º 13
0
class GuiMenu(QMenuBar):
    """

    Class GuiMenu contains the menu details incl. action functions that were
    moved out of main_menu module.

    @author: ssimons

    """
    HELP_WEBSITE_LINK = "http://www.s-simons.de/tree_editor_help.html"

    MAIN_TREE = True
    SECOND_TREE = False

    def __init__(self,
                 tree_main,
                 tree_second,
                 configuration,
                 right_window,
                 main_window,
                 signal_wrapper):
        """ Creates menu elements.
            @param tree_main: Tree object of main file / tree
                (left side)
            @param tree_second: Tree object of second file / tree
                (right side)
            @param text_output_instance: QTextEdit object which should be
                used / bind with the tree wiget.
            @param configuration: Current Configuration object.
            @param right_window: QWidget object of the second (right) file/tree
            @param main_window: QMainWindow object to change the title
            @param signal_wrapper: SignalWrapper object which wraps signals

        """
        QMenuBar.__init__(self, main_window.centralWidget())
        logging.info("menu foo")
        self.tree_main = tree_main
        self.tree_second = tree_second
        self._conf = configuration
        self.widget_right_window = right_window
        self.main_window = main_window
        self.signal_wrapper = signal_wrapper

        self.two_windows_action = QAction("Two Windows", self)
        self._importer = TextImporter(self._conf)

        self._init_gui_menu_view()
        self._init_gui_menu_main_file()
        self.menu_second_file = QMenu("SecondFile",
                                      self.main_window.centralWidget())
        self._init_gui_menu_second_file()

        gui_helper.change_window_title("", self.main_window)


    def _init_gui_menu_view(self):
        """Initialises the view menu ( with configuration, exit etc.)

        """
        menu1 = QMenu("View", self.main_window.centralWidget())

        self.two_windows_action.setCheckable(True)
        QObject.connect(self.two_windows_action,
                        SIGNAL('triggered()'),
                        self._show_or_hide_second_window_file)
        menu1.addAction(self.two_windows_action)

        configuration_gui_action = QAction("Configuration", self)
        QObject.connect(configuration_gui_action,
                        SIGNAL('triggered()'),
                        self._gui_open_configuration)
        menu1.addAction(configuration_gui_action)
        info_license_action = QAction("Info/License", self)
        QObject.connect(info_license_action,
                        SIGNAL('triggered()'),
                        lambda: InfoLicenseWindow(self.main_window))
        menu1.addAction(info_license_action)
        help_gui_action = QAction("Help", self)
        QObject.connect(help_gui_action,
                        SIGNAL('triggered()'),
                        lambda: webbrowser.open(self.HELP_WEBSITE_LINK, 1))
        menu1.addAction(help_gui_action)

        menu_exit_action = QAction("Exit", self)
        QObject.connect(menu_exit_action,
                        SIGNAL('triggered()'),
                        self._menu_exit)
        menu1.addSeparator()
        menu1.addAction(menu_exit_action)
        self.addMenu(menu1)
        logging.info("menu1" + str(menu1 is None))

    def _init_gui_menu_main_file(self):
        """Initialises the first window / file

        """
        menu_main_file = QMenu("MainFile", self.main_window.centralWidget())
        self.addMenu(menu_main_file)

        menu_open_main_file_action = QAction("Open file", self)
        QObject.connect(menu_open_main_file_action,
                        SIGNAL('triggered()'),
                        self._menu_main_window_open_file)
        menu_main_file.addAction(menu_open_main_file_action)

        menu_save_main_file_action = QAction("Save file", self)
        QObject.connect(menu_save_main_file_action,
                        SIGNAL('triggered()'),
                        self._default_file_save)
        menu_main_file.addAction(menu_save_main_file_action)

        remove_elem_in_main_file_action = QAction("Remove element", self)
        QObject.connect(remove_elem_in_main_file_action,
                        SIGNAL('triggered()'),
                        self._menu_delete_elem_main_file)
        menu_main_file.addAction(remove_elem_in_main_file_action)
        copy_main_to_second_file_action = QAction("Copy to second File", self)
        QObject.connect(copy_main_to_second_file_action,
                        SIGNAL('triggered()'),
                        self._menu_copy_main_to_second_file)
        menu_main_file.addAction(copy_main_to_second_file_action)

        expand_all_action = QAction("Expand all", self)
        QObject.connect(expand_all_action,
                        SIGNAL('triggered()'),
                        lambda: self.signal_wrapper. \
                            signal_treeview1_expand_all.emit())
        menu_main_file.addAction(expand_all_action)

        collapse_all_action = QAction("Collapse all", self)
        QObject.connect(collapse_all_action,
                        SIGNAL('triggered()'),
                        lambda: self.signal_wrapper. \
                            signal_treeview1_collapse_all.emit())

        menu_main_file.addAction(collapse_all_action)

        menu_main_file.addSeparator()
        self._initialize_tree_specific_menu_entries(self.tree_main,
                                                    menu_main_file,
                                                    self.MAIN_TREE)

    def _init_gui_menu_second_file(self):
        """Initialises the second window / file

        """
        self.menu_second_file.setEnabled(False)
        self.addMenu(self.menu_second_file)

        menu_open_second_file_action = QAction("Open file", self)
        QObject.connect(menu_open_second_file_action,
                        SIGNAL('triggered()'),
                        self._menu_second_window_open_file)
        self.menu_second_file.addAction(menu_open_second_file_action)
        remove_elem_in_second_file_action = QAction("Remove element", self)
        QObject.connect(remove_elem_in_second_file_action,
                        SIGNAL('triggered()'),
                        self._menu_delete_elem_second_file)
        self.menu_second_file.addAction(remove_elem_in_second_file_action)
        copy_second_to_main_file_action = QAction("Copy to main File", self)
        QObject.connect(copy_second_to_main_file_action,
                        SIGNAL('triggered()'),
                        self._menu_copy_second_to_main_file)
        self.menu_second_file.addAction(copy_second_to_main_file_action)

        expand_all_action = QAction("Expand all", self)
        QObject.connect(expand_all_action,
                        SIGNAL('triggered()'),
                        lambda: self.signal_wrapper. \
                            signal_treeview2_expand_all.emit())
        self.menu_second_file.addAction(expand_all_action)

        collapse_all_action = QAction("Collapse all", self)
        QObject.connect(collapse_all_action,
                        SIGNAL('triggered()'),
                        lambda: self.signal_wrapper. \
                            signal_treeview2_collapse_all.emit())
        self.menu_second_file.addAction(collapse_all_action)

        self.menu_second_file.addSeparator()
        self._initialize_tree_specific_menu_entries(self.tree_second,
                                                    self.menu_second_file,
                                                    self.SECOND_TREE)

    def _initialize_tree_specific_menu_entries(self,
                                               tree_instance,
                                               menu_reference,
                                               is_main_tree):
        """ Creates standard menu entries (that are used for both trees)
            for the given tree_instance
            @param tree_instance: Tree object that
                should be used.
            @param menu_reference: QMenu object where to add the menu entries
            @param is_main_tree: to differ between main and second tree.

        """

        exchange_action = QAction("Exchange", self)
        QObject.connect(
            exchange_action,
            SIGNAL('triggered()'),
            lambda: self._menu_exchange_tree_elements(tree_instance))

        menu_reference.addAction(exchange_action)

        data_up_action = QAction("DataUp", self)
        QObject.connect(
            data_up_action,
            SIGNAL('triggered()'),
            #call data up move
            lambda: QMessageBox.information(self.main_window, "Info",
                        '''The following were susscessully moved up: '''
                        + "".join(tree_operations.data_up_move(tree_instance))))
        menu_reference.addAction(data_up_action)

        data_down_action = QAction("DataDown", self)
        QObject.connect(
            data_down_action,
            SIGNAL('triggered()'),
            #call data down move
            lambda: QMessageBox.information(self.main_window, "Info",
                        '''The following were successfully moved down: '''
                        + "".join(tree_operations.data_down_move(tree_instance)
                        )))

        menu_reference.addAction(data_down_action)

        data_replace_action = QAction("Replace", self)
        QObject.connect(
            data_replace_action,
            SIGNAL('triggered()'),
            lambda: self._menu_change_label_of_selected_elements(tree_instance,
                                                                 is_main_tree))
        menu_reference.addAction(data_replace_action)

        data_search_and_replace_action = QAction("Search and replace", self)
        QObject.connect(
            data_search_and_replace_action,
            SIGNAL('triggered()'),
            lambda: tree_operations.data_search_and_replace(self.main_window,
                                                  tree_instance))
        menu_reference.addAction(data_search_and_replace_action)
        data_search_and_replace_action.setEnabled(False)



    # ------------------------------------------------
    # -------------  MENU ACTIONS --------------------
    # ------------------------------------------------

    def _default_file_save(self):
        """ Action function to save to file.

        """

        file_name = QFileDialog.getSaveFileName(self,
                                       "Save file",
                                       QDir.home().dirName(),
                                       "All files (*.*)")
        if not file_name.isNull():
            _exporter = TextExporter(self._conf)
            _exporter.write_file_from_data(self.tree_main,
                                           file_name)
            QMessageBox.information(self.main_window, "Info",
                '''Please ensure the correctness of the output file by
                comparing (diff) the output file to the original one. See
                help for further information.''')

    def _show_or_hide_second_window_file(self):
        """ Action function to show/hide the second window (which means the
        second pair of tree and text editor).

        """
        if self.two_windows_action.isChecked():
            self.widget_right_window.show()
            self.main_window.resize(self.main_window.width() * 2,
                                    self.main_window.height())
            self.menu_second_file.setEnabled(True)
        else:
            self.widget_right_window.hide()
            self.main_window.resize(self.main_window.width() / 2,
                                    self.main_window.height())
            self.menu_second_file.setEnabled(False)

    def _gui_open_configuration(self):
        """ Action to open the configuration window.

        """
        configuration_gui = ConfigurationGUI(self,
                                             self._conf)
        configuration_gui.show()

    def _menu_change_label_of_selected_elements(self, tree_instance,
                                                is_main_tree):
        text, ok_response = QInputDialog.getText(self.main_window, "Replace",
            "Replace checked to:", QLineEdit.Normal, QDir.home().dirName())
        logging.debug("Replace / Change label with:" + text)
        if ok_response is False:
            return

        result_list = tree_operations.tree_element_change_label(tree_instance,
                                                                text)

        #emit the signal to trigger a click event. That is needed to refresh
        #the texteditor, that it contains the replaced data.
        if is_main_tree == self.SECOND_TREE:
            self.signal_wrapper.signal_treeview2_clicked.emit()
        else:
            self.signal_wrapper.signal_treeview1_clicked.emit()


        QMessageBox.information(self.main_window, "Info",
            '''The labels of the following tree elements were
            successfully renamned/changed : '''
            + "".join(result_list))

    def _menu_exchange_tree_elements(self, tree_instance):
        """ Action to exchange (data) tree elements.

        """
        try:
            tree_operations.exchange_elements(tree_instance)
        except NotEnoughTreeElementsCheckedException as netc:
            QMessageBox.warning(self.main_window, "Warning", netc.args[0])
            return
        except NoProperTreeElementException as npte:
            QMessageBox.warning(self.main_window, "Warning", npte.args[0])
            return
        except TreeElementsNotSameLevelException as tnl:
            QMessageBox.information(self.main_window, "Info", tnl.args[0])
            return


    def _menu_exit(self):
        """ Action to exit the program.

        """
        try:
            ConfigurationFileWriter.write_config(self._conf)
        except IOError, exc:
            logging.exception(exc)
        logging.shutdown()
        sys.exit()
Ejemplo n.º 14
0
class SimpleRichText(QTextEdit):
    def __init__(self, focusin, focusout):
        QTextEdit.__init__(self)        
        self.focusin = focusin
        self.focusout = focusout
        self.createActions()

        #self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)

    def focusOutEvent ( self, event ):
        #print "focus out"
        self.focusout()

    def focusInEvent ( self, event ):        
        self.focusin()


    def closeEvent(self, event):
        event.accept()        

    def createActions(self):
        self.boldAct = QAction(self.tr("&Bold"), self)
        self.boldAct.setCheckable(True)
        self.boldAct.setShortcut(self.tr("Ctrl+B"))
        self.boldAct.setStatusTip(self.tr("Make the text bold"))
        self.connect(self.boldAct, SIGNAL("triggered()"), self.setBold)
        self.addAction(self.boldAct)

        boldFont = self.boldAct.font()
        boldFont.setBold(True)
        self.boldAct.setFont(boldFont)

        self.italicAct = QAction(self.tr("&Italic"), self)
        self.italicAct.setCheckable(True)
        self.italicAct.setShortcut(self.tr("Ctrl+I"))
        self.italicAct.setStatusTip(self.tr("Make the text italic"))
        self.connect(self.italicAct, SIGNAL("triggered()"), self.setItalic)
        self.addAction(self.italicAct)

    def setBold(self):
        format = QTextCharFormat()
        if self.boldAct.isChecked():
                weight = QFont.Bold
        else:
                weight = QFont.Normal
        format.setFontWeight(weight)
        self.setFormat(format)

    def setItalic(self):
        format = QTextCharFormat()
        #format.setFontItalic(self.__italic.isChecked())
        format.setFontItalic(self.italicAct.isChecked())
        self.setFormat(format)

    def setUnderline(self):
        format = QTextCharFormat()
        format.setFontUnderline(self.__underline.isChecked())
        self.setFormat(format)

    def setFormat(self, format):
        self.textCursor().mergeCharFormat(format)
        self.mergeCurrentCharFormat(format)

    def bold(self):
        print("bold")

    def italic(self):
        print("italic")
Ejemplo n.º 15
0
class MainWindow(QtGui.QMainWindow):
    """Implements the main window for dame."""
    def __init__(self, parent=None):
        """Initialize the window."""
        QtGui.QMainWindow.__init__(self, parent)
        self.setupUi()

    def setupUi(self):
        """Create the basic UI."""
        self.setWindowTitle("dame")
        # TODO: Set window icon
        self.create_actions()
        self.create_statusbar()

        self.mainview = MainViewer(parent=self)

        # # Connect an action now that mainview is set
        # self.mode_group.triggered.connect(self.mainview.toggleComparison)

        # TODO: This is the start of using tabbed windows
        # self.mdiArea = QtGui.QMdiArea(parent=self)
        # first = self.mdiArea.addSubWindow(self.scrollArea)
        # self.mdiArea.setViewMode(QtGui.QMdiArea.TabbedView)
        # self.mdiArea.setTabsMovable(True)
        # self.setCentralWidget(self.mdiArea)
        # first.setWindowTitle("foo")

        self.setCentralWidget(self.mainview)

        # Create popup windows (for zoomer and panner)
        self.zoom_win = QtGui.QWidget(self, Qt.Window | Qt.Tool)
        self.zoom_win.setSizePolicy(QtGui.QSizePolicy.Fixed,
                                    QtGui.QSizePolicy.Fixed)
        self.zoom_win_im = QLabel()
        self.zoom_win_im.setSizePolicy(QtGui.QSizePolicy.Ignored,
                                       QtGui.QSizePolicy.Ignored)
        # self.zoom_win.resize(150,150)
        # self.zoom_win.show()
        zoomer_layout = QtGui.QGridLayout()
        zoomer_layout.setContentsMargins(0, 0, 0, 0)
        zoomer_layout.addWidget(self.zoom_win_im)
        self.zoom_win.setLayout(zoomer_layout)

        # TODO: panner

        # Create note dock widget
        self.note_widget = QtGui.QDockWidget("Notes", parent=self)
        self.note_text = QtGui.QTextEdit(parent=self.note_widget)
        self.note_widget.setWidget(self.note_text)
        self.note_widget.setFeatures(
            QtGui.QDockWidget.DockWidgetClosable
            | QtGui.QDockWidget.DockWidgetMovable
            | QtGui.QDockWidget.DockWidgetFloatable
            | QtGui.QDockWidget.DockWidgetVerticalTitleBar)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.note_widget)
        self.note_widget.close()
        self.note_action = self.note_widget.toggleViewAction()
        self.note_action.setText("Display notes")
        self.note_action.setStatusTip("Show notes about the SIR image")

        # Create the menus
        self.create_menus()

    def create_statusbar(self):
        """Create the statusbar."""
        self.statusBar().showMessage("Ready")

        # The individual info
        self.status_sing_pixinfo = QLabel()
        self.status_sing_coord = QLabel()
        self.status_left_pixinfo = QLabel()
        self.status_right_pixinfo = QLabel()
        self.status_comp_coord = QLabel()

        # The groups
        self.status_sing_layout = QtGui.QHBoxLayout()
        self.status_sing_layout.addWidget(self.status_sing_coord, 0,
                                          Qt.AlignRight)
        self.status_sing_layout.addWidget(self.status_sing_pixinfo, 1,
                                          Qt.AlignRight)
        self.status_comp_layout = QtGui.QHBoxLayout()
        self.status_comp_layout.addWidget(self.status_left_pixinfo, 0)
        self.status_comp_layout.addWidget(self.status_comp_coord, 1)
        self.status_comp_layout.addWidget(self.status_right_pixinfo, 0)

        self.status_sing_layout.setContentsMargins(0, 0, 0, 0)
        self.status_comp_layout.setContentsMargins(0, 0, 0, 0)

        self.status_sing = QtGui.QWidget()
        self.status_sing.setLayout(self.status_sing_layout)
        self.status_comp = QtGui.QWidget()
        self.status_comp.setLayout(self.status_comp_layout)

        # The stacked widget (to alternate between single and comparison modes)
        self.status_stacked = QtGui.QStackedWidget()
        self.status_stacked.addWidget(self.status_sing)
        self.status_stacked.addWidget(self.status_comp)
        self.status_stacked.setCurrentIndex(0)

        self.statusBar().addWidget(self.status_stacked)

    def create_actions(self):
        """Define the actions."""
        self.about_action = QAction("&About", self)
        self.about_action.setStatusTip("About dame")
        self.about_action.setMenuRole(QAction.AboutRole)
        self.about_action.triggered.connect(self.show_about)

        self.open_action = QAction("&Open", self)
        self.open_action.setStatusTip("Open a SIR file")
        self.open_action.setShortcut(QtGui.QKeySequence.Open)
        self.open_action.triggered.connect(self.open_file)

        self.close_action = QAction("&Close", self)
        self.close_action.setStatusTip("Close current SIR file")
        self.close_action.setShortcut(QtGui.QKeySequence.Close)
        self.close_action.triggered.connect(self.close_file)

        self.exit_action = QAction("E&xit", self)
        self.exit_action.setMenuRole(QAction.QuitRole)
        self.exit_action.setStatusTip("Exit dame")
        self.exit_action.setShortcut(QtGui.QKeySequence("Ctrl+Q"))
        self.exit_action.triggered.connect(self.close)

        self.prop_action = QAction("SIR header", self)
        self.prop_action.setStatusTip("Display SIR header information")
        self.prop_action.triggered.connect(self.print_header)

        self.range_action = QAction("Image range", self)
        self.range_action.setStatusTip("Set image display range")
        self.range_action.triggered.connect(self.show_range)

        self.zoomer_action = QAction("Enable zoomer window", self)
        self.zoomer_action.setStatusTip(("Show zoomer window for "
                                         "magnified viewing"))
        self.zoomer_action.setCheckable(True)
        self.zoomer_action.triggered.connect(self.update_zoomer_opts)

        self.zoom_factor_label_action = QAction("Zoom factor", self)
        self.zoom_factor_label_action.setEnabled(False)

        self.zoom_factor_1_action = QAction("2x zoom", self)
        self.zoom_factor_2_action = QAction("4x zoom", self)
        self.zoom_factor_3_action = QAction("8x zoom", self)
        self.zoom_factor_4_action = QAction("16x zoom", self)
        self.zoom_factor_1_action.setStatusTip("Magnify zoom region by 2x")
        self.zoom_factor_2_action.setStatusTip("Magnify zoom region by 4x")
        self.zoom_factor_3_action.setStatusTip("Magnify zoom region by 8x")
        self.zoom_factor_4_action.setStatusTip("Magnify zoom region by 16x")
        self.zoom_factor_1_action.setCheckable(True)
        self.zoom_factor_2_action.setCheckable(True)
        self.zoom_factor_3_action.setCheckable(True)
        self.zoom_factor_4_action.setCheckable(True)

        self.zoom_size_label_action = QAction("Zoom region size", self)
        self.zoom_size_label_action.setEnabled(False)

        self.zoom_size_1_action = QAction("9x9 window", self)
        self.zoom_size_2_action = QAction("17x17 window", self)
        self.zoom_size_3_action = QAction("29x29 window", self)
        self.zoom_size_4_action = QAction("45x45 window", self)
        self.zoom_size_5_action = QAction("65x65 window", self)
        self.zoom_size_1_action.setStatusTip("Set zoom region to 9x9 pixels")
        self.zoom_size_2_action.setStatusTip("Set zoom region to 17x17 pixels")
        self.zoom_size_3_action.setStatusTip("Set zoom region to 29x29 pixels")
        self.zoom_size_4_action.setStatusTip("Set zoom region to 45x45 pixels")
        self.zoom_size_5_action.setStatusTip("Set zoom region to 65x65 pixels")
        self.zoom_size_1_action.setCheckable(True)
        self.zoom_size_2_action.setCheckable(True)
        self.zoom_size_3_action.setCheckable(True)
        self.zoom_size_4_action.setCheckable(True)
        self.zoom_size_5_action.setCheckable(True)

        # Group zoomer actions and connect slots
        self.zoom_factor_group = QtGui.QActionGroup(self)
        self.zoom_factor_group.addAction(self.zoom_factor_1_action)
        self.zoom_factor_group.addAction(self.zoom_factor_2_action)
        self.zoom_factor_group.addAction(self.zoom_factor_3_action)
        self.zoom_factor_group.addAction(self.zoom_factor_4_action)
        self.zoom_factor_group.triggered.connect(self.update_zoomer_opts)

        self.zoom_size_group = QtGui.QActionGroup(self)
        self.zoom_size_group.addAction(self.zoom_size_1_action)
        self.zoom_size_group.addAction(self.zoom_size_2_action)
        self.zoom_size_group.addAction(self.zoom_size_3_action)
        self.zoom_size_group.addAction(self.zoom_size_4_action)
        self.zoom_size_group.addAction(self.zoom_size_5_action)
        self.zoom_size_group.triggered.connect(self.update_zoomer_opts)

        # # Mode actions
        # self.mode_group = QtGui.QActionGroup(self)
        # self.mode_single_action = QAction("Single image", self.mode_group)
        # self.mode_dual_action = QAction("Two images", self.mode_group)
        # self.mode_single_action.setCheckable(True)
        # self.mode_dual_action.setCheckable(True)
        # self.mode_single_action.setStatusTip("Display a single image")
        # self.mode_dual_action.setStatusTip("Display two images for comparison")
        # self.mode_single_action.setChecked(True)
        # #self.mode_group.triggered.connect(self.mainview.toggleComparison) # Moved later

        # http://stackoverflow.com/questions/11643221/are-there-default-icons-in-pyqt-pyside
        # TODO: Add icons in a better way. See how Picard does it.
        QIcon.setThemeName("gnome")  # TODO: temporary
        self.open_action.setIcon(QIcon.fromTheme("document-open"))
        self.close_action.setIcon(QIcon.fromTheme("window-close"))
        self.exit_action.setIcon(QIcon.fromTheme("application-exit"))
        self.about_action.setIcon(QIcon.fromTheme("help-about"))

    def create_menus(self):
        """Setup the menus."""
        menu = self.menuBar().addMenu("&File")
        menu.addAction(self.open_action)
        menu.addAction(self.close_action)
        menu.addSeparator()
        # menu.addAction(self.mode_single_action)
        # menu.addAction(self.mode_dual_action)
        # menu.addSeparator()
        menu.addAction(self.exit_action)
        menu = self.menuBar().addMenu("Image")
        menu.addAction(self.prop_action)
        menu.addAction(self.range_action)
        menu.addAction(self.note_action)
        # submenu = menu.addMenu("Mode")
        # submenu.addAction(self.mode_single_action)
        # submenu.addAction(self.mode_split_action)
        # submenu.addAction(self.mode_fade_action)
        menu = self.menuBar().addMenu("Zoomer")
        menu.addAction(self.zoomer_action)
        menu.addSeparator()
        menu.addAction(self.zoom_factor_label_action)
        menu.addAction(self.zoom_factor_1_action)
        menu.addAction(self.zoom_factor_2_action)
        menu.addAction(self.zoom_factor_3_action)
        menu.addAction(self.zoom_factor_4_action)
        menu.addSeparator()
        menu.addAction(self.zoom_size_label_action)
        menu.addAction(self.zoom_size_1_action)
        menu.addAction(self.zoom_size_2_action)
        menu.addAction(self.zoom_size_3_action)
        menu.addAction(self.zoom_size_4_action)
        menu.addAction(self.zoom_size_5_action)
        menu = self.menuBar().addMenu("&Help")
        menu.addAction(self.about_action)

        # Deactivate menus by default
        self.range_action.setEnabled(False)
        self.prop_action.setEnabled(False)
        self.close_action.setEnabled(False)

    @QtCore.Slot()
    def open_file(self):
        """Display open file dialog."""
        filename = QtGui.QFileDialog.getOpenFileName(self, "Open SIR file",
                                                     QtCore.QDir.homePath(),
                                                     ("SIR files (*.sir *.ave)"
                                                      ";;Any file (*)"))
        if py_binding == 'PySide':
            filename = filename[0]
        if filename:
            self.load_sir(filename)

    def load_sir(self, filename):
        """Load in the SIR file."""
        if os.access(filename, os.F_OK | os.R_OK):
            self.statusBar().showMessage("Loading")
            self.mainview.load_sir(filename)
            self.statusBar().showMessage("Loaded", 2000)

            # Activate menus
            self.range_action.setEnabled(True)
            self.prop_action.setEnabled(True)
            self.close_action.setEnabled(True)
        else:
            logging.warning("Can't open {}".format(filename))
            # TODO: Alert the user via GUI

    @QtCore.Slot()
    def close_file(self):
        """Close file."""
        logging.info("Closing SIR file")
        self.mainview.close_file()
        self.statusBar().showMessage("SIR closed", 2000)

        # That was the last file, so disable stuff
        if len(self.mainview.sir_files) == 0:
            self.status_stacked.setVisible(False)
            self.zoom_win.hide()

            # Deactivate menus
            self.range_action.setEnabled(False)
            self.prop_action.setEnabled(False)
            self.close_action.setEnabled(False)

    @QtCore.Slot()
    def show_about(self):
        """Display about popup."""
        about_text = """
                Dame {}
                Copyright 2014 Richard Lindsley
                Dame is a SIR file viewer""".format(version_string)
        QMessageBox.about(self, "About", dedent(about_text))

    @QtCore.Slot()
    def show_range(self):
        """Display image range popup."""
        win = RangeWindow()
        win.min_text.setText(
            str(self.mainview.sir_files[self.mainview.cur_tab]['vmin']))
        win.max_text.setText(
            str(self.mainview.sir_files[self.mainview.cur_tab]['vmax']))
        if win.exec_() == QtGui.QDialog.Accepted:
            win_range = win.getRange()
            self.mainview.sir_files[self.mainview.cur_tab]['vmin'] = \
                win_range[0]
            self.mainview.sir_files[self.mainview.cur_tab]['vmax'] = \
                win_range[1]
            self.mainview.update_image(self.mainview.cur_tab)
            self.mainview.update_view()

    @QtCore.Slot()
    def print_header(self):
        """Display SIR header info."""
        sir_head = libsir.print_sir_head(
            self.mainview.sir_files[self.mainview.cur_tab]['header'])
        # TODO: Maybe make this a modeless dialog instead of modal? Use a dock
        # widget?
        box = QMessageBox()
        box.setText(dedent(sir_head))
        box.setIcon(QMessageBox.Information)
        box.exec_()

    def update_zoomer(self):
        """Update the zoomer, both the image as well as the popup."""
        cur_tab = self.mainview.cur_tab
        if 'pix_loc' not in self.mainview.sir_files[cur_tab]:
            return
        try:
            loc = self.mainview.sir_files[cur_tab]['pix_loc']
            rect_w = self.mainview.sir_files[cur_tab]['zoomer_size']
            winsize = rect_w * \
                self.mainview.sir_files[cur_tab]['zoomer_factor']
            if cur_tab == "split":
                pixmaps = (self.mainview.sir_files['left']['pixmap'].copy(),
                           self.mainview.sir_files['right']['pixmap'].copy())
            else:
                pixmaps = \
                    (self.mainview.sir_files[cur_tab]['pixmap'].copy(),)

            for pixmap_i, pixmap in enumerate(pixmaps):
                # Upper left corner
                if loc.x() < rect_w / 2:
                    rect_x = -0.5
                elif loc.x() > pixmap.width() - rect_w / 2:
                    rect_x = pixmap.width() - rect_w - 0.5
                else:
                    rect_x = loc.x() - rect_w / 2
                if loc.y() < rect_w / 2:
                    rect_y = -0.5
                elif loc.y() > pixmap.height() - rect_w / 2:
                    rect_y = pixmap.height() - rect_w - 0.5
                else:
                    rect_y = loc.y() - rect_w / 2

                rect_x += 1
                rect_y += 1

                # Draw the image with the zoomer region outlined
                p = QtGui.QPainter()
                p.begin(pixmap)
                p.setPen(QtGui.QColor("#FFFFFF"))  # White stroke
                p.drawRect(rect_x, rect_y, rect_w, rect_w)
                p.end()
                if cur_tab in ("left", "right", "cross"):
                    self.mainview.single_image.image.setPixmap(pixmap)
                elif cur_tab in ("split", ):
                    if pixmap_i == 0:
                        self.mainview.left_image.image.setPixmap(pixmap)
                    elif pixmap_i == 1:
                        self.mainview.right_image.image.setPixmap(pixmap)
                    else:
                        logging.warning("pixmap_i is {}".format(pixmap_i))

            # Update the zoomer window
            if cur_tab == "split":
                pixmaps = (self.mainview.sir_files['left']['pixmap'],
                           self.mainview.sir_files['right']['pixmap'])
            else:
                pixmaps = (self.mainview.sir_files[cur_tab]['pixmap'], )

            if len(pixmaps) == 2:
                zoom_pixmap = QPixmap(2 * winsize, winsize)

            for pixmap_i, pixmap_src in enumerate(pixmaps):
                # extract the zoomer region
                pixmap = pixmap_src.copy(rect_x, rect_y, rect_w, rect_w)
                # scale it
                pixmap = pixmap.scaled(winsize, winsize,
                                       Qt.KeepAspectRatioByExpanding)

                # Add crosshair to zoomer window; note that the crosshair
                # won't be centered if the region is at the edges
                p = QtGui.QPainter()
                p.begin(pixmap)
                # Highlight selected pixel
                # p.setPen(QtGui.QColor("#000000"))  # Black stroke
                p.setPen(QtGui.QColor("#FFFFFF"))  # White stroke
                zoom_fac = self.mainview.sir_files[cur_tab]['zoomer_factor']
                # Top left of magnified pixel
                mag_pix = (zoom_fac * (loc.x() - rect_x + 1) - zoom_fac / 2,
                           zoom_fac * (loc.y() - rect_y + 1) - zoom_fac / 2)
                # Center of magnified pixel
                mag_pix_cen = (zoom_fac * (loc.x() - rect_x + 1),
                               zoom_fac * (loc.y() - rect_y + 1))
                p.drawRect(mag_pix[0], mag_pix[1], zoom_fac, zoom_fac)
                # Draw crosshairs
                p.setPen(QtGui.QColor("#FFFFFF"))  # White stroke
                # vertical line, top
                p.drawLine(mag_pix_cen[0], 0, mag_pix_cen[0], mag_pix[1] - 1)
                # vertical line, bottom
                p.drawLine(mag_pix_cen[0], mag_pix[1] + zoom_fac,
                           mag_pix_cen[0], winsize - 0)
                # horizontal line, left
                p.drawLine(0, mag_pix_cen[1], mag_pix[0] - 1, mag_pix_cen[1])
                # horizontal line, right
                p.drawLine(mag_pix[0] + zoom_fac, mag_pix_cen[1], winsize - 0,
                           mag_pix_cen[1])
                p.end()

                if len(pixmaps) == 1:
                    self.zoom_win_im.setPixmap(pixmap)
                else:
                    p = QtGui.QPainter(zoom_pixmap)
                    p.drawPixmap(pixmap_i * winsize, 0, pixmap)
                    self.zoom_win_im.setPixmap(zoom_pixmap)

            self.zoom_win_im.setHidden(False)
            self.zoom_win_im.adjustSize()

        except KeyError as err:
            logging.warning("Can't find {}".format(err))

    def update_statusbar(self):
        """Update the status bar."""
        if self.mainview.cur_tab in ("left", "right"):
            vmin = self.mainview.sir_files[self.mainview.cur_tab]['vmin']
            vmax = self.mainview.sir_files[self.mainview.cur_tab]['vmax']
            self.status_stacked.setVisible(True)
            self.status_stacked.setCurrentIndex(0)
            self.status_sing_pixinfo.setText("min: {}, max: {}".format(
                vmin, vmax))
            self.status_sing_coord.setVisible(False)
        elif self.mainview.cur_tab in ("split", "fade"):
            vmin_l = self.mainview.sir_files['left']['vmin']
            vmax_l = self.mainview.sir_files['left']['vmax']
            vmin_r = self.mainview.sir_files['right']['vmin']
            vmax_r = self.mainview.sir_files['right']['vmax']
            self.status_stacked.setVisible(True)
            self.status_stacked.setCurrentIndex(1)
            self.status_left_pixinfo.setText("min: {} max: {}".format(
                vmin_l, vmax_l))
            self.status_right_pixinfo.setText("min: {} max: {}".format(
                vmin_r, vmax_r))
            self.status_comp_coord.setVisible(False)

    def update_statusbar_pos(self, x_im, y_im):
        """Update with position at image index x, y."""
        self.statusBar().clearMessage()
        nsx = self.mainview.sir_files[self.mainview.cur_tab]['header'].nsx
        nsy = self.mainview.sir_files[self.mainview.cur_tab]['header'].nsy
        # Convert from 0-based to 1-based indexing
        # (I've double-checked the values returned here using sir_util2a)
        y = nsy - y_im  # Convert image y coord to SIR y coord
        x = x_im + 1
        if x > 0 and y > 0 and x <= nsx and y <= nsy:
            # Note that sir_data is 0-based indexing, but pix2latlon is 1-based
            cur_sir = self.mainview.sir_files[self.mainview.cur_tab]
            lon, lat = libsir.pix2latlon(x, y, cur_sir['header'])
            if self.mainview.cur_tab in ("left", "right"):
                self.status_sing_coord.setVisible(True)
                stat_text = ("x = {}, y = {}   "
                             "lat = {:0.4f}, lon = {:0.4f} "
                             "value = {:0.4f}").format(
                                 x, y, lat, lon, cur_sir['data'][y_im, x_im])
                self.status_sing_coord.setText(stat_text)
            elif self.mainview.cur_tab in ("split", "fade"):
                left_sir = self.mainview.sir_files['left']
                right_sir = self.mainview.sir_files['right']
                self.status_comp_coord.setVisible(True)
                stat_text = ("x = {}, y = {}   "
                             "lat = {:0.4f}, lon = {:0.4f} "
                             "left value = {:0.4f} "
                             "right value = {:0.4f}").format(
                                 x, y, lat, lon, left_sir['data'][y_im, x_im],
                                 right_sir['data'][y_im, x_im])
                self.status_comp_coord.setText(stat_text)

    def sizeHint(self):
        """Override the suggested size."""
        return QtCore.QSize(1000, 800)

    # Menu events
    @QtCore.Slot()
    def update_zoomer_opts(self, draw_win=True):
        """Given a menu change, this sets zoomer options and updates."""
        file_dict = self.mainview.sir_files[self.mainview.cur_tab]
        # Is zoomer enabled?
        file_dict['zoomer_on'] = self.zoomer_action.isChecked()

        # Find the zoom factor
        zfactor = self.zoom_factor_group.checkedAction()
        if zfactor is self.zoom_factor_1_action:
            file_dict['zoomer_factor'] = 2
        elif zfactor is self.zoom_factor_2_action:
            file_dict['zoomer_factor'] = 4
        elif zfactor is self.zoom_factor_3_action:
            file_dict['zoomer_factor'] = 8
        elif zfactor is self.zoom_factor_4_action:
            file_dict['zoomer_factor'] = 16

        # Find the zoom size
        zsize = self.zoom_size_group.checkedAction()
        if zsize is self.zoom_size_1_action:
            file_dict['zoomer_size'] = 9
        elif zsize is self.zoom_size_2_action:
            file_dict['zoomer_size'] = 17
        elif zsize is self.zoom_size_3_action:
            file_dict['zoomer_size'] = 29
        elif zsize is self.zoom_size_4_action:
            file_dict['zoomer_size'] = 45
        elif zsize is self.zoom_size_5_action:
            file_dict['zoomer_size'] = 65

        if draw_win:
            # Compute zoomer window size and show/hide it
            winsize = file_dict['zoomer_size'] * file_dict['zoomer_factor']
            if self.mainview.cur_tab == "split":
                self.zoom_win.resize(2 * winsize, winsize)
                self.zoom_win.setFixedSize(2 * winsize, winsize)
            else:
                self.zoom_win.resize(winsize, winsize)
                self.zoom_win.setFixedSize(winsize, winsize)

            if file_dict['zoomer_on']:
                self.zoom_win.show()
            else:
                self.zoom_win.hide()

            # Update zoomer
            self.update_zoomer()

    # Keyboard events
    def keyPressEvent(self, key):
        """Handle some keypresses."""
        if len(self.mainview.sir_files) == 0:
            key.ignore()
            return

        if 'pix_loc' not in self.mainview.sir_files[self.mainview.cur_tab]:
            # Don't do anything if we don't have a coord yet
            key.ignore()
            return

        # Increment im_pos if valid key
        # Note that im_pos is 0-based, so
        # it ranges from 0 to nsx-1/nsy-1 inclusive
        im_pos = self.mainview.sir_files[self.mainview.cur_tab]['pix_loc']
        nsx = self.mainview.sir_files[self.mainview.cur_tab]['header'].nsx
        nsy = self.mainview.sir_files[self.mainview.cur_tab]['header'].nsy
        delta = 5 if key.modifiers() == Qt.ShiftModifier else 1
        if key.key() == Qt.Key_J:
            # Down
            if im_pos.y() + delta < nsy:
                im_pos.setY(im_pos.y() + delta)
        elif key.key() == Qt.Key_K:
            # Up
            if im_pos.y() - delta >= 0:
                im_pos.setY(im_pos.y() - delta)
        elif key.key() == Qt.Key_H:
            # Left
            if im_pos.x() - delta >= 0:
                im_pos.setX(im_pos.x() - delta)
        elif key.key() == Qt.Key_L:
            # Right
            if im_pos.x() + delta < nsx:
                im_pos.setX(im_pos.x() + delta)
        else:
            key.ignore()
            return

        # Update stuff with our new position
        self.mainview.sir_files[self.mainview.cur_tab]['pix_loc'] = im_pos
        self.update_zoomer()
        self.update_statusbar_pos(im_pos.x(), im_pos.y())
Ejemplo n.º 16
0
class QgsAttributeTableDialog(QDialog):
    '''
    classdocs
    '''
    def __init__(self, parent, vectorlayer):
        QDialog.__init__(self, parent)
        #         self.w = QDialog(self)
        self.baseLayer = vectorlayer
        self.canChangeAttributes = self.validate(
            QgsVectorDataProvider.ChangeAttributeValues)
        self.canDeleteFeatures = self.validate(
            QgsVectorDataProvider.DeleteFeatures)
        self.canAddAttributes = self.validate(
            QgsVectorDataProvider.AddAttributes)
        self.canDeleteAttributes = self.validate(
            QgsVectorDataProvider.DeleteAttributes)
        self.canAddFeatures = self.validate(QgsVectorDataProvider.AddFeatures)

        gridLayout = QGridLayout(self)
        self.setLayout(gridLayout)

        self.setWindowTitle("Attribute Table")
        self.setFixedSize(QSize(800, 600))

        editorToolbar = QToolBar()
        editorToolbar.setFixedSize(QSize(768, 48))
        self.actionToggleEditing = QAction(QIcon("Resource\\edit.png"),
                                           "ToggleEditing", self)
        self.actionToggleEditing.triggered.connect(self.toggleEditing)
        if (self.canChangeAttributes or self.canDeleteFeatures
                or self.canAddAttributes or self.canDeleteAttributes
                or self.canAddFeatures) and (not self.baseLayer.isReadOnly()):
            self.actionToggleEditing.setEnabled(True)
        else:
            self.actionToggleEditing.setEnabled(False)
        self.actionToggleEditing.setCheckable(True)
        editorToolbar.addAction(self.actionToggleEditing)

        self.actionSave = QAction(QIcon("Resource\\filesave.png"),
                                  "Save Edits", self)
        self.actionSave.triggered.connect(self.saveEditing)
        self.actionSave.setCheckable(False)
        self.actionSave.setEnabled(False)
        editorToolbar.addAction(self.actionSave)

        self.actiondeleteRows = QAction(
            QIcon("Resource\\mActionDeleteSelected.png"),
            "Delete selected features", self)
        self.actiondeleteRows.triggered.connect(self.deleteRows)
        self.actiondeleteRows.setCheckable(False)
        self.actiondeleteRows.setEnabled(False)
        editorToolbar.addAction(self.actiondeleteRows)

        self.actionUnselectAll = QAction(
            QIcon("Resource\\mActionDeselectAll.png"), "Unselect All", self)
        self.actionUnselectAll.triggered.connect(self.unselectAll)
        self.actionUnselectAll.setCheckable(False)
        self.actionUnselectAll.setEnabled(True)
        editorToolbar.addAction(self.actionUnselectAll)

        self.actionSelectedToZoom = QAction(
            QIcon("Resource\\mActionZoomToSelected.png"),
            "Zoom map to the selected rows", self)
        self.actionSelectedToZoom.triggered.connect(self.selectedToZoom)
        self.actionSelectedToZoom.setCheckable(False)
        self.actionSelectedToZoom.setEnabled(True)
        editorToolbar.addAction(self.actionSelectedToZoom)

        gridLayout.addWidget(editorToolbar, 0, 0, 1, 1)

        self.model = QStandardItemModel()

        #         self.model.itemChanged.connect(self.attributeChanged)
        self.attributeTable = QTableView(self)
        self.attributeTable.setModel(self.model)
        self.attributeTable.setColumnWidth(0, 200)
        self.attributeTable.setColumnWidth(1, 160)
        self.attributeTable.clicked.connect(self.tableSelectionChanged)
        self.attributeTable.setSortingEnabled(True)

        self.changeItemList = []
        self.selectRows = []
        self.isSave = True
        self.initTable()
        gridLayout.addWidget(self.attributeTable, 1, 0, 1, 1)
#         self.attributeTable.selectionChanged.connect(self.selectFeature)

    def tableSelectionChanged(self):
        idxList = self.attributeTable.selectedIndexes()
        if idxList != None and len(idxList) > 0:
            self.baseLayer.removeSelection()
            fidList = []
            for idx in idxList:
                fid = int(self.model.item(idx.row()).text())
                fidList.append(fid)
            self.baseLayer.setSelectedFeatures(fidList)

    def toggleEditing(self):
        if self.baseLayer != None:

            if not self.actionToggleEditing.isChecked():

                if self.isSave:
                    self.baseLayer.commitChanges()
                    self.actionSave.setEnabled(False)
                    self.actiondeleteRows.setEnabled(False)
                    self.model.itemChanged.disconnect(self.attributeChanged)
                    self.toggleEditingTable(False)
                else:
                    button = QMessageBox.warning(
                        self, "Stop Editing",
                        "Do you want to save the changes to layer?",
                        QMessageBox.Save | QMessageBox.Discard
                        | QMessageBox.Cancel)
                    if (button == QMessageBox.Cancel):
                        self.actionToggleEditing.setChecked(True)

                    elif button == QMessageBox.Save:
                        self.saveEditing()
                        self.baseLayer.commitChanges()
                        self.actionSave.setEnabled(False)
                        self.actiondeleteRows.setEnabled(False)
                        self.model.itemChanged.disconnect(
                            self.attributeChanged)
                        self.toggleEditingTable(False)
                    else:
                        self.initTable()
                        self.baseLayer.commitChanges()
                        self.actionSave.setEnabled(False)
                        self.actiondeleteRows.setEnabled(False)
                        self.model.itemChanged.disconnect(
                            self.attributeChanged)
                        self.toggleEditingTable(False)
#                 self.isEditable = False
            else:
                self.actionSave.setEnabled(True)
                self.actiondeleteRows.setEnabled(True)
                self.baseLayer.startEditing()
                self.toggleEditingTable(True)
                self.model.itemChanged.connect(self.attributeChanged)
#                 self.isEditable = True

    def toggleEditingTable(self, isEditable):
        columnCount = self.model.columnCount()
        rowCount = self.model.rowCount()
        col = 0
        while col < columnCount:
            row = 0
            while row < rowCount:
                self.model.item(row, col).setEditable(isEditable)
                row += 1
            col += 1

    def attributeChanged(self, standardItem):
        self.isSave = False
        #         if not self.isDelete:
        self.changeItemList.append(standardItem)
#         featureId = standardItem.row()
#         self.baseLayer.changeAttributeValue(featureId,
#                                        standardItem.column(), standardItem.text())

    def saveEditing(self):
        self.isSave = True
        if len(self.changeItemList) > 0:
            for standardItem in self.changeItemList:
                featureId = standardItem.row()
                self.baseLayer.changeAttributeValue(featureId,
                                                    standardItem.column(),
                                                    standardItem.text())
            self.changeItemList = []
        if len(self.selectRows) > 0:
            for id in self.selectRows:
                self.baseLayer.deleteFeature(id)
            self.selectRows = []

    def initTable(self):
        self.model.clear()
        #         header = QHeaderView(Qt.Horizontal)
        #         headerModel = QStandardItemModel()

        layer = self.baseLayer
        fields = layer.pendingFields()
        headersList = ["fid"]
        for field in fields:
            headersList.append(field.name())
        self.model.setHorizontalHeaderLabels(headersList)

        #         headerModel.setHorizontalHeaderLabels(headersList)
        #         header.setModel(headerModel)
        #         self.attributeTable.setHorizontalHeader(header)

        if len(layer.selectedFeatures()) > 0:
            features = layer.selectedFeatures()
        else:
            features = layer.getFeatures()
        for feature in features:
            record = [QStandardItem(str(feature.id()))]

            for field in feature.fields():
                name = field.name()
                attribute = feature.attribute(name).toString()

                stdItemValue = QStandardItem(attribute)
                stdItemValue.setEditable(False)
                record.append(stdItemValue)
            self.model.appendRow(record)

    def deleteRows(self):
        if len(self.attributeTable.selectedIndexes()) > 0:
            self.isSave = False
            selectedIndexs = self.attributeTable.selectedIndexes()
            k = -1
            self.selectRows = []
            for index in selectedIndexs:
                if k != index.row():
                    k = index.row()
                    self.selectRows.append(k)
            for row in self.selectRows:
                self.model.takeRow(row)

    def unselectAll(self):
        if len(self.attributeTable.selectedIndexes()) > 0:
            self.attributeTable.clearSelection()

    def selectedToZoom(self):
        if len(self.attributeTable.selectedIndexes()) > 0:
            self.baseLayer.removeSelection()

            selectedIndexs = self.attributeTable.selectedIndexes()
            k = -1
            self.selectRows = []
            for index in selectedIndexs:
                if k != index.row():
                    k = index.row()
                    self.selectRows.append(k)
            self.baseLayer.setSelectedFeatures(self.selectRows)
#             for row in self.selectRows:
#                 self.model.takeRow(row)
        define._canvas.zoomToSelected(self.baseLayer)

    def validate(self, condition):
        if self.baseLayer.dataProvider().capabilities() & condition:
            return True
        else:
            return False
Ejemplo n.º 17
0
class BrowserWindow(QMainWindow):
    def retranslateUi(self):
        self.setWindowTitle(
            QApplication.translate("self", "self", None,
                                   QApplication.UnicodeUTF8))
        self.menuFile.setTitle(
            QApplication.translate("self", "&File", None,
                                   QApplication.UnicodeUTF8))
        self.menuView.setTitle(
            QApplication.translate("self", "&View", None,
                                   QApplication.UnicodeUTF8))
        self.menuEdit.setTitle(
            QApplication.translate("self", "&Edit", None,
                                   QApplication.UnicodeUTF8))
        self.menuHelp.setTitle(
            QApplication.translate("self", "&Help", None,
                                   QApplication.UnicodeUTF8))
        self.toolBar.setWindowTitle(
            QApplication.translate("self", "toolBar", None,
                                   QApplication.UnicodeUTF8))
        self.actionHome.setText(
            QApplication.translate("self", "&Home", None,
                                   QApplication.UnicodeUTF8))
        self.actionHome.setToolTip(
            QApplication.translate("self", "Go Home", None,
                                   QApplication.UnicodeUTF8))
        self.actionShowMenu.setText(
            QApplication.translate("self", "Show &Menu", None,
                                   QApplication.UnicodeUTF8))
        self.actionShowToolbar.setText(
            QApplication.translate("self", "Show &Toolbar", None,
                                   QApplication.UnicodeUTF8))
        self.actionClose.setText(
            QApplication.translate("self", "&Close", None,
                                   QApplication.UnicodeUTF8))
        self.actionModifyWebapp.setText(
            QApplication.translate("self", "Modify &Webapp", None,
                                   QApplication.UnicodeUTF8))
        self.actionEditPreferences.setText(
            QApplication.translate("self", "Edit &Preferences", None,
                                   QApplication.UnicodeUTF8))
        self.actionPrint.setText(
            QApplication.translate("self", "&Print", None,
                                   QApplication.UnicodeUTF8))
        self.actionAbout.setText(
            QApplication.translate("self", "&About", None,
                                   QApplication.UnicodeUTF8))

    def __init__(self, appid, base, name):
        super(BrowserWindow, self).__init__()

        self.appid = appid
        self.name = name
        self.original_name = name
        self.base = base

        # Main widgets
        self.centralwidget = QWidget(self)
        self.gridLayout_2 = QGridLayout(self.centralwidget)
        self.setCentralWidget(self.centralwidget)
        self.urlLineEdit = QLineEdit(self)
        self.progressBar = QProgressBar(self)

        # Custom webview
        self.page = LocalWebPage()
        self.page.setFeaturePermission(self.page.mainFrame(),
                                       LocalWebPage.Notifications,
                                       LocalWebPage.PermissionGrantedByUser)
        self.webkitNotifications = WebkitNotifications(self)

        self.webViewMain = LocalWebView(self.centralwidget)
        self.webViewMain.setPage(self.page)
        self.gridLayout_2.addWidget(self.webViewMain, 0, 0, 1, 1)

        self.webViewMain.setContentsMargins(0, 0, 0, 0)
        self.gridLayout_2.setContentsMargins(0, 0, 0, 0)

        self.menubar = QMenuBar(self)
        self.menuFile = QMenu(self.menubar)
        self.menuView = QMenu(self.menubar)
        self.menuEdit = QMenu(self.menubar)
        self.menuHelp = QMenu(self.menubar)
        self.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(self)
        self.setStatusBar(self.statusbar)
        self.toolBar = QToolBar(self)
        self.toolBar.setMovable(False)
        self.toolBar.setFloatable(False)
        self.addToolBar(Qt.TopToolBarArea, self.toolBar)

        # Create actions
        self.actionOpenLinkInNewWindow = self.page.action(
            self.page.OpenLinkInNewWindow)
        self.actionOpenLinkInNewWindow.setText(
            tr('BrowserWindow', 'Open in &Browser'))
        self.actionBack = self.page.action(self.page.Back)
        self.actionForward = self.page.action(self.page.Forward)
        self.actionStop = self.page.action(self.page.Stop)
        self.actionReload = self.page.action(self.page.Reload)
        self.actionHome = QAction(self)
        self.actionShowMenu = QAction(self)
        self.actionShowMenu.setCheckable(True)
        self.actionShowToolbar = QAction(self)
        self.actionShowToolbar.setCheckable(True)
        self.actionClose = QAction(self)
        self.actionModifyWebapp = QAction(self)
        self.actionEditPreferences = QAction(self)
        self.actionPrint = QAction(self)
        self.actionSaveLink = self.page.action(self.page.DownloadLinkToDisk)
        self.actionSaveLink.setEnabled(False)
        self.actionAbout = QAction(self)

        # Populate menu and toolbars
        self.menuFile.addAction(self.actionHome)
        self.menuFile.addAction(self.actionBack)
        self.menuFile.addAction(self.actionForward)
        self.menuFile.addAction(self.actionStop)
        self.menuFile.addAction(self.actionReload)
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.actionPrint)
        self.menuFile.addSeparator()
        self.menuFile.addAction(self.actionClose)
        self.menuView.addAction(self.actionShowMenu)
        self.menuView.addAction(self.actionShowToolbar)
        self.menuView.addSeparator()
        self.menuEdit.addAction(self.actionModifyWebapp)
        #self.menuEdit.addAction(self.actionEditPreferences)
        self.menuHelp.addAction(self.actionAbout)
        self.menubar.addAction(self.menuFile.menuAction())
        self.menubar.addAction(self.menuEdit.menuAction())
        self.menubar.addAction(self.menuView.menuAction())
        self.menubar.addAction(self.menuHelp.menuAction())
        self.toolBar.addAction(self.actionHome)
        self.toolBar.addAction(self.actionBack)
        self.toolBar.addAction(self.actionForward)
        self.toolBar.addWidget(self.urlLineEdit)

        self.toolBar.addAction(self.actionStop)
        self.toolBar.addAction(self.actionReload)

        self.retranslateUi()
        QMetaObject.connectSlotsByName(self)

        self.setWindowTitle(self.name)

        # Set up cookie jar that persists sessions
        self.cookieJar = PersistableCookieJar(self, identifier=self.appid)
        self.cookieJar.load()
        self.webViewMain.page().networkAccessManager().setCookieJar(
            self.cookieJar)

        # Set up link delegation so that external links open in web browser.
        self.webViewMain.page().setLinkDelegationPolicy(
            QWebPage.DelegateExternalLinks)

        self.desktopEntry = desktop.getEntry(self.appid)

        # Set icons for actions; this can't be done in the designer, AFAICT
        self.actionHome.setIcon(QIcon.fromTheme('go-home'))
        self.actionAbout.setIcon(QIcon.fromTheme('help-about'))

        # Set up shortcuts
        self.actionStop.setShortcut(Qt.Key_Escape)
        self.actionBack.setShortcut(QKeySequence.Back)
        self.actionForward.setShortcut(QKeySequence.Forward)
        self.actionReload.setShortcut(QKeySequence.Refresh)
        self.actionHome.setShortcut('Ctrl+Home')
        self.actionShowMenu.setShortcut('Ctrl+m')
        self.actionShowToolbar.setShortcut('Ctrl+t')
        self.actionPrint.setShortcut(QKeySequence.Print)

        self.backShortcut = QShortcut(self)
        self.backShortcut.setKey(Qt.Key_Back)
        self.backShortcut.activated.connect(self.webViewMain.back)

        self.forwardShortcut = QShortcut(self)
        self.forwardShortcut.setKey(Qt.Key_Forward)
        self.forwardShortcut.activated.connect(self.webViewMain.forward)

        # Set up context menu
        self.webViewMain.setContextMenuPolicy(Qt.CustomContextMenu)
        self.webViewMain.customContextMenuRequested.connect(self.showMenu)

        # Setup statusbar and toolbar
        for c in self.statusBar().children()[0].children():
            c.removeWidget(c)
        self.statusBar().addPermanentWidget(self.progressBar, 1)

        self.actionShowToolbar.setChecked(True)
        self.actionShowMenu.setChecked(True)

        # Icon
        if self.desktopEntry.hasKey('Icon'):
            self.icon = QIcon(self.desktopEntry.get('Icon'))
            self.setWindowIcon(self.icon)
        else:
            self.webViewMain.iconChanged.connect(self.setWindowIcon)

        # Set up events
        if self.desktopEntry.get('X-%s-menu-enabled' % APP_NAME) == '0':
            self.actionShowMenu.setChecked(False)
        else:
            self.actionShowMenu.setChecked(True)
        if self.desktopEntry.get('X-%s-toolbar-enabled' % APP_NAME) == '0':
            self.actionShowToolbar.setChecked(False)
        else:
            self.actionShowToolbar.setChecked(True)

        self.webViewMain.linkClicked.connect(self._onLinkClick)
        self.webViewMain.titleChanged.connect(self.setWindowTitle)
        self.webViewMain.loadProgress.connect(self._setLoadingStatus)
        self.webViewMain.urlChanged.connect(
            lambda x: self.urlLineEdit.setText(x.toString()))
        self.page.printRequested.connect(self._onPrint)
        self.page.loadFinished.connect(self._loadingFinished)
        self.actionHome.triggered.connect(
            lambda x: self.webViewMain.load(QUrl(self.base)))
        self.actionClose.triggered.connect(self.close)
        self.actionPrint.triggered.connect(self._onPrint)
        self.urlLineEdit.returnPressed.connect(self._onUrlEdit)
        self.actionShowToolbar.triggered.connect(self._onShowToolbar)
        self.actionShowMenu.triggered.connect(self._onShowMenu)
        self.actionAbout.triggered.connect(lambda x: about.show(self))
        self.actionModifyWebapp.triggered.connect(self._onModify)

        self._onShowMenu()
        self._onShowToolbar()

        try:
            self.resize(int(self.desktopEntry.getWindowWidth()),
                        int(self.desktopEntry.getWindowHeight()))
        except (ValueError, TypeError):
            self.resize(800, 600)

        # Load first page
        self.webViewMain.load(QUrl(base))

        self.editor = SiteEditorWindow(self.desktopEntry, isNew=False)

    def _onModify(self):
        self.editor.show()

    def closeEvent(self, qCloseEvent):
        self.desktopEntry.setWindowWidth(self.width())
        self.desktopEntry.setWindowHeight(self.height())
        self.desktopEntry.write()

    def _onPrint(self):
        printer = QPrinter()
        dialog = QPrintDialog(printer, self)
        if dialog.exec_() != QDialog.Accepted:
            return
        self.page.mainFrame().print_(printer)

    def _loadingFinished(self):
        # TODO: Add user scripts here
        # TODO: Add user styles here

        # Override window.webkitNotifications
        self.page.mainFrame().addToJavaScriptWindowObject(
            "_x_webplier_webkitNotifications", self.webkitNotifications)
        self.page.mainFrame().evaluateJavaScript(
            WebkitNotifications.JAVASCRIPT)

    def _setLoadingStatus(self, value):
        if value < 100:
            self.progressBar.setValue(value)
            self.progressBar.show()
            self.statusBar().show()
            self.actionReload.setVisible(False)
            self.actionStop.setVisible(True)
        else:
            self.page.setFeaturePermission(
                self.page.mainFrame(), LocalWebPage.Notifications,
                LocalWebPage.PermissionGrantedByUser)
            self.progressBar.hide()
            self.statusBar().hide()
            self.actionReload.setVisible(True)
            self.actionStop.setVisible(False)

    def _onUrlEdit(self):
        url = unicode(self.urlLineEdit.text())
        qurl = QUrl(url)
        if not qurl.scheme():
            qurl.setScheme('http')

        self.webViewMain.load(qurl)

    def _onLinkClick(self, qurl):
        url = unicode(qurl.toString())
        if not unicode(url).startswith(self.base):
            webbrowser.open(url, 1)
        else:
            self.webViewMain.load(qurl)

    def _onShowToolbar(self):
        if self.actionShowToolbar.isChecked():
            self.toolBar.show()
            self.desktopEntry.set('X-%s-toolbar-enabled' % APP_NAME, '1')
        else:
            self.toolBar.hide()
            self.desktopEntry.set('X-%s-toolbar-enabled' % APP_NAME, '0')

    def _onShowMenu(self):
        if self.actionShowMenu.isChecked():
            self.menubar.show()
            self.desktopEntry.set('X-%s-menu-enabled' % APP_NAME, '1')
        else:
            self.menubar.hide()
            self.desktopEntry.set('X-%s-menu-enabled' % APP_NAME, '0')

    def showMenu(self, point):
        m = self.webViewMain.page().createStandardContextMenu()

        # TODO: Make this less awful and fragile
        for a in m.actions():
            if a == self.actionSaveLink:
                m.removeAction(a)

        m.addSeparator()
        m.addAction(self.actionShowMenu)
        m.addAction(self.actionShowToolbar)
        globalpos = self.mapToParent(point)

        m.exec_(globalpos)
Ejemplo n.º 18
0
class movingTrafficSigns(demandFormUtils):
    """QGIS Plugin Implementation."""
    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface
        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)
        # initialize locale
        locale = QSettings().value('locale/userLocale')[0:2]
        locale_path = os.path.join(self.plugin_dir, 'i18n',
                                   'movingTrafficSigns_{}.qm'.format(locale))

        if os.path.exists(locale_path):
            self.translator = QTranslator()
            self.translator.load(locale_path)

            if qVersion() > '4.3.3':
                QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&movingTrafficSigns')
        # TODO: We are going to let the user set this up in a future iteration
        self.toolbar = self.iface.addToolBar(u'movingTrafficSigns')
        self.toolbar.setObjectName(u'movingTrafficSigns')

        # self.demandUtils = demandFormUtils(self.iface)

    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('movingTrafficSigns', message)

    def add_action(self,
                   icon_path,
                   text,
                   callback,
                   enabled_flag=True,
                   add_to_menu=True,
                   add_to_toolbar=True,
                   status_tip=None,
                   whats_this=None,
                   parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        # Create the dialog (after translation) and keep reference
        #self.dlg = movingTrafficSignsDialog()

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToMenu(self.menu, action)

        self.actions.append(action)

        return action

    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""
        """icon_path = ':/plugins/movingTrafficSigns/signs.png'
        self.add_action(
            icon_path,
            text=self.tr(u'movingTrafficSigns'),
            callback=self.doCreateMovingTrafficSign,
            parent=self.iface.mainWindow())"""

        self.actionCreateMovingTrafficSign = QAction(
            QIcon(
                ":/plugins/movingTrafficSigns/resources/mActionSetEndPoint.svg"
            ),
            QCoreApplication.translate("MyPlugin",
                                       "Create moving traffic sign"),
            self.iface.mainWindow())
        self.actionCreateMovingTrafficSign.setCheckable(True)

        self.actionSignDetails = QAction(
            QIcon(":/plugins/movingTrafficSigns/resources/mActionGetInfo.svg"),
            QCoreApplication.translate("MyPlugin", "Get Sign Details"),
            self.iface.mainWindow())
        self.actionSignDetails.setCheckable(True)

        self.actionRemoveSign = QAction(
            QIcon(
                ":plugins/movingTrafficSigns/resources/mActionDeleteTrack.svg"
            ), QCoreApplication.translate("MyPlugin", "Remove Sign"),
            self.iface.mainWindow())
        self.actionRemoveSign.setCheckable(True)

        self.toolbar.addAction(self.actionCreateMovingTrafficSign)
        self.toolbar.addAction(self.actionSignDetails)
        self.toolbar.addAction(self.actionRemoveSign)

        self.actionCreateMovingTrafficSign.triggered.connect(
            self.doCreateMovingTrafficSign)
        self.actionSignDetails.triggered.connect(self.doSignDetails)
        self.actionRemoveSign.triggered.connect(self.doRemoveSign)

        self.actionCreateMovingTrafficSign.toggled.connect(self.actionToggled)
        self.actionCreateMovingTrafficSign.triggered.connect(
            self.actionTriggered)

    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""
        for action in self.actions:
            self.iface.removePluginMenu(self.tr(u'&movingTrafficSigns'),
                                        action)
            self.iface.removeToolBarIcon(action)
        # remove the toolbar
        del self.toolbar

    def doSignDetails(self):
        """ Select point and then display details
        """
        QgsMessageLog.logMessage("In doSignDetails", tag="TOMs panel")

        #self.demandUtils.signToolChanged.emit()
        #self.demandUtils.signToolChanged.connect(self.actionToggled)
        #self.mapTool = None

        if self.actionSignDetails.isChecked():

            QgsMessageLog.logMessage("In doSignDetails - tool activated",
                                     tag="TOMs panel")

            self.currLayer = QgsMapLayerRegistry.instance().mapLayersByName(
                "MovingTrafficSigns")[0]

            self.iface.setActiveLayer(self.currLayer)
            if not self.actionSignDetails.isChecked():
                QgsMessageLog.logMessage(
                    "In doSignDetails - resetting mapTool", tag="TOMs panel")
                self.actionSignDetails.setChecked(False)
                self.iface.mapCanvas().unsetMapTool(self.mapTool)
                self.mapTool = None
                # self.actionPan.connect()
                return

            self.actionSignDetails.setChecked(True)

            self.mapTool = GeometryInfoMapTool(self.iface)
            self.mapTool.setAction(self.actionSignDetails)
            self.iface.mapCanvas().setMapTool(self.mapTool)

            self.mapTool.notifyFeatureFound.connect(self.showSignDetails)

        else:

            QgsMessageLog.logMessage("In doSignDetails - tool deactivated",
                                     tag="TOMs panel")

            self.mapTool.notifyFeatureFound.disconnect(self.showSignDetails)
            self.iface.mapCanvas().unsetMapTool(self.mapTool)
            #del self.mapTool
            self.mapTool = None
            self.actionSignDetails.setChecked(False)

    @pyqtSlot(str)
    def showSignDetails(self, closestLayer, closestFeature):

        QgsMessageLog.logMessage("In showSignDetails ... Layer: " +
                                 str(closestLayer.name()),
                                 tag="TOMs panel")

        if closestLayer.isEditable() == True:
            if closestLayer.commitChanges() == False:
                reply = QMessageBox.information(
                    None, "Information", "Problem committing changes" +
                    str(closestLayer.commitErrors()), QMessageBox.Ok)
            else:
                QgsMessageLog.logMessage(
                    "In onSaveDemandDetails: changes committed",
                    tag="TOMs panel")

        if closestLayer.startEditing() == False:
            # Set different form
            #closestLayer.editFormConfig().setUiForm(...)
            """reply = QMessageBox.information(None, "Information",
                                            "Could not start transaction on " + self.currLayer.name(), QMessageBox.Ok)
            return"""
            pass

        self.dialog = self.iface.getFeatureForm(closestLayer, closestFeature)
        self.setupDemandDialog(self.dialog, closestLayer,
                               closestFeature)  # connects signals, etc
        self.dialog.show()

    def doCreateMovingTrafficSign(self):

        QgsMessageLog.logMessage("In doCreateMovingTrafficSign",
                                 tag="TOMs panel")

        #self.demandUtils.signToolChanged.emit()

        if self.actionCreateMovingTrafficSign.isChecked():

            QgsMessageLog.logMessage(
                "In doCreateMovingTrafficSign - tool activated",
                tag="TOMs panel")

            self.currLayer = QgsMapLayerRegistry.instance().mapLayersByName(
                "MovingTrafficSigns")[0]

            if self.currLayer.startEditing() == False:
                reply = QMessageBox.information(
                    None, "Information",
                    "Could not start transaction on " + self.currLayer.name(),
                    QMessageBox.Ok)
                self.actionCreateMovingTrafficSign.setChecked(False)
                return

            self.iface.setActiveLayer(self.currLayer)

            self.currLayer = QgsMapLayerRegistry.instance().mapLayersByName(
                "MovingTrafficSigns")[0]

            self.iface.setActiveLayer(self.currLayer)

            self.actionCreateMovingTrafficSign.setChecked(True)

            self.mapTool = CreateSignTool(self.iface, self.currLayer)

            self.mapTool.setAction(self.actionCreateMovingTrafficSign)
            self.iface.mapCanvas().setMapTool(self.mapTool)

            self.mapTool.notifyNewFeature.connect(self.createNewSign)
            self.currLayer.editingStopped.connect(self.layerEditingStopped)
            self.currLayer.featureAdded.connect(self.layerfeatureAdded)

        else:

            QgsMessageLog.logMessage(
                "In doCreateMovingTrafficSign - tool deactivated",
                tag="TOMs panel")

            self.mapTool.notifyNewFeature.disconnect(self.createNewSign)
            self.currLayer.editingStopped.disconnect(self.layerEditingStopped)
            self.currLayer.featureAdded.disconnect(self.layerfeatureAdded)

            self.iface.mapCanvas().unsetMapTool(self.mapTool)
            del self.mapTool
            #self.mapTool = None
            self.actionCreateMovingTrafficSign.setChecked(False)

    @pyqtSlot(str)
    def actionToggled(self, answer):
        QgsMessageLog.logMessage(
            ("In actionToggled: *********************************"),
            tag="TOMs panel")

    @pyqtSlot(str)
    def actionTriggered(self, answer):
        QgsMessageLog.logMessage(
            ("In actionTriggered: *********************************"),
            tag="TOMs panel")

    @pyqtSlot(str)
    def layerEditingStopped(self):
        QgsMessageLog.logMessage(
            ("In layerEditingStopped: ********************************"),
            tag="TOMs panel")

    @pyqtSlot(str)
    def layerfeatureAdded(self, id):
        QgsMessageLog.logMessage(
            ("In layerfeatureAdded: ********************************" +
             str(id)),
            tag="TOMs panel")

    @pyqtSlot(str)
    def createNewSign(self, sketchPoints):

        QgsMessageLog.logMessage(("In createNewSign, layerType: " +
                                  str(self.currLayer.geometryType())),
                                 tag="TOMs panel")

        self.sketchPoints = sketchPoints

        if self.currLayer.startEditing() == False:
            reply = QMessageBox.information(
                None, "Information",
                "Could not start transaction on " + self.currLayer.name(),
                QMessageBox.Ok)
            return

        fields = self.currLayer.fields()
        feature = QgsFeature(fields)
        #feature.setFields(fields)

        if self.currLayer.geometryType() == 0:  # Point
            feature.setGeometry(QgsGeometry.fromPoint(self.sketchPoints[0]))
        elif self.currLayer.geometryType() == 1:  # Line
            feature.setGeometry(QgsGeometry.fromPolyline(self.sketchPoints))
        elif self.currLayer.geometryType() == 2:  # Polygon
            feature.setGeometry(QgsGeometry.fromPolygon([self.sketchPoints]))
            # feature.setGeometry(QgsGeometry.fromPolygon(self.sketchPoints))
        else:
            QgsMessageLog.logMessage(
                ("In CreateRestrictionTool - no geometry type found"),
                tag="TOMs panel")
            return

        QgsMessageLog.logMessage(
            ("In Create - getPointsCaptured; geometry prepared; " +
             str(feature.geometry().exportToWkt())),
            tag="TOMs panel")

        # set any geometry related attributes ...

        self.setDefaultRestrictionDetails(feature, self.currLayer)

        self.dialog = self.iface.getFeatureForm(self.currLayer, feature)
        self.setupDemandDialog(self.dialog, self.currLayer,
                               feature)  # connects signals, etc
        self.dialog.show()

    def doRemoveSign(self):

        QgsMessageLog.logMessage("In doRemoveSign", tag="TOMs panel")

        #self.demandUtils.signToolChanged.emit()

        #self.mapTool = None

        if self.actionRemoveSign.isChecked():

            QgsMessageLog.logMessage("In doSignDetails - tool activated",
                                     tag="TOMs panel")

            self.currLayer = QgsMapLayerRegistry.instance().mapLayersByName(
                "MovingTrafficSigns")[0]

            if self.currLayer.startEditing() == False:
                reply = QMessageBox.information(
                    None, "Information",
                    "Could not start transaction on " + self.currLayer.name(),
                    QMessageBox.Ok)
                self.actionRemoveSign.setChecked(False)
                return

            self.iface.setActiveLayer(self.currLayer)
            if not self.actionRemoveSign.isChecked():
                QgsMessageLog.logMessage(
                    "In doSignDetails - resetting mapTool", tag="TOMs panel")
                self.actionRemoveSign.setChecked(False)
                self.iface.mapCanvas().unsetMapTool(self.mapTool)
                self.mapTool = None
                # self.actionPan.connect()
                return

            self.actionRemoveSign.setChecked(True)

            self.mapTool = GeometryInfoMapTool(self.iface)
            self.mapTool.setAction(self.actionRemoveSign)
            self.iface.mapCanvas().setMapTool(self.mapTool)

            self.mapTool.notifyFeatureFound.connect(self.removeSign)

        else:

            QgsMessageLog.logMessage("In doSignDetails - tool deactivated",
                                     tag="TOMs panel")

            self.mapTool.notifyFeatureFound.disconnect(self.removeSign)
            self.iface.mapCanvas().unsetMapTool(self.mapTool)
            del self.mapTool
            self.actionRemoveSign.setChecked(False)

    @pyqtSlot(str)
    def removeSign(self, closestLayer, closestFeature):

        QgsMessageLog.logMessage("In removeSign ... Layer: " +
                                 str(closestLayer.name()),
                                 tag="TOMs panel")

        if closestLayer.isEditable() == True:
            if closestLayer.commitChanges() == False:
                reply = QMessageBox.information(
                    None, "Information", "Problem committing changes" +
                    str(closestLayer.commitErrors()), QMessageBox.Ok)
            else:
                QgsMessageLog.logMessage(
                    "In onSaveDemandDetails: changes committed",
                    tag="TOMs panel")

        if self.currLayer.startEditing() == False:
            reply = QMessageBox.information(
                None, "Information",
                "Could not start transaction on " + self.currLayer.name(),
                QMessageBox.Ok)
            return

        # TODO: Sort out this for UPDATE
        # self.setDefaultRestrictionDetails(closestFeature, closestLayer)

        closestLayer.deleteFeature(closestFeature.id())

        if closestLayer.commitChanges() == False:
            reply = QMessageBox.information(
                None, "Information", "Problem committing changes" +
                str(closestLayer.commitErrors()), QMessageBox.Ok)
        else:
            QgsMessageLog.logMessage(
                "In onSaveDemandDetails: changes committed", tag="TOMs panel")
Ejemplo n.º 19
0
class SystemTray(QSystemTrayIcon):
    def __init__(self, parent=None):
        QSystemTrayIcon.__init__(self, parent)
        self.parent = parent
        self.menu = QMenu()

        self.aAyarlar = QAction(self.menu)
        self.aAyarlar.setText(u"Ayarlar")
        self.aAyarlar.triggered.connect(self.ayarlar)
        self.menu.addAction(self.aAyarlar)

        self.menu.addSeparator()

        self.aKoru = QAction(self.menu)
        self.aKoru.setText(u"Koru")
        self.aKoru.setCheckable(True)
        self.aKoru.setChecked(setting.value("ContextMenu/Koru").toBool())
        self.aKoru.triggered.connect(self.koru)
        self.menu.addAction(self.aKoru)

        self.aBaslat = QAction(self.menu)
        self.aBaslat.setText(u"Açılışta Başlat")
        self.aBaslat.setCheckable(True)
        self.aBaslat.setChecked(setting.value("ContextMenu/AcilistaBaslat").toBool())
        self.aBaslat.triggered.connect(self.baslat)
        self.menu.addAction(self.aBaslat)

        self.menu.addSeparator()

        self.aHakkinda = QAction(self.menu)
        self.aHakkinda.setText(u"Virux Hakkında")
        self.aHakkinda.triggered.connect(self.hakkinda)
        self.menu.addAction(self.aHakkinda)

        self.aKapat = QAction(self.menu)
        self.aKapat.setText(u"Kapat")
        self.aKapat.triggered.connect(self.close)
        self.menu.addAction(self.aKapat)

        self.setIcon(QIcon(":logo.png"))
        self.setContextMenu(self.menu)

        self.activated.connect(self.mesaj)

        self.timer = QBasicTimer()
        self.sayac = 0

        self.timer.start(200, self)
        self.koru()

        self.dialogList = __all__
        self.timer2 = QBasicTimer()
        self.timer2.start(
            random.randrange(
                setting.value("DialogOpen/MinimumSure").toInt()[0], setting.value("DialogOpen/MaksimumSure").toInt()[0]
            ),
            self,
        )

    def close(self):
        sys.exit()

    def hakkinda(self):
        hakkinda = DHakkinda(self.parent)
        hakkinda.show()

    def ayarlar(self):
        ayarlar = DAyarlar(self.parent)
        ayarlar.show()

    def timerEvent(self, event):
        if event.timerId() == self.timer.timerId():
            if self.sayac < 10:
                self.setIcon(QIcon(":/bocuk/data/bocuk/%s.png" % str(self.sayac).zfill(2)))
                self.sayac += 1
            else:
                self.sayac = 0
        if self.aKoru.isChecked():
            if event.timerId() == self.timer2.timerId():
                dialog = random.choice(self.dialogList)
                dialog = dialog(self.parent)
                dialog.show()
                self.timer2.start(
                    random.randrange(
                        setting.value("DialogOpen/MinimumSure").toInt(),
                        setting.value("DialogOpen/MaksimumSure").toInt(),
                    ),
                    self,
                )

    def baslat(self):
        if sys.platform == "win32":
            self.windows()
        else:
            self.linux()

    def windows(self):
        import _winreg

        if self.aBaslat.isChecked():
            setting.setValue("ContextMenu/AcilistaBaslat", True)
            setting.sync()
            regPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"
            self.reg = _winreg.OpenKeyEx(_winreg.HKEY_LOCAL_MACHINE, regPath, 0, _winreg.KEY_ALL_ACCESS)
            _winreg.SetValueEx(self.reg, "Virux", 0, _winreg.REG_SZ, os.path.join(mainPath, __file__))
        else:
            setting.setValue("ContextMenu/AcilistaBaslat", False)
            setting.sync()
            _winreg.DeleteValue(self.reg, "Virux")
        # _winreg.CloseKey(self.reg)

    def linux(self):
        if not self.aBaslat.isChecked():
            setting.setValue("ContextMenu/AcilistaBaslat", False)
            dosyaYolu = os.path.join(str(QDir.homePath()), ".kde", "Autostart", "Virux.desktop")
            if os.path.isfile(dosyaYolu):
                os.remove(dosyaYolu)
        else:
            setting.setValue("ContextMenu/AcilistaBaslat", True)
            dosyaYolu = os.path.join(str(QDir.homePath()), ".kde", "Autostart", "Virux.desktop")
            desktop = """[Desktop Entry]
            Comment[tr]=Platform bağımsız bir antivirüs uygulaması
            Comment=Platform bağımsız bir antivirüs uygulaması
            Exec=python %s/virux.py
            GenericName[tr]=Platform bağımsız bir antivirüs uygulaması
            GenericName=Platform bağımsız bir antivirüs uygulaması
            Icon=%s
            Type=Application
            Name[tr]=Virux
            Name=Virux
            Path=
            StartupNotify=true
            Terminal=false
            """ % (
                mainPath,
                os.path.join(mainPath, "data", "logo.png"),
            )
            yaz = open(dosyaYolu, "w")
            yaz.write(desktop)
            yaz.close()

    def mesaj(self, reason):
        if reason == self.Trigger:
            self.showMessage("Virux", u"Eğlence amaçlı antivirüs uygulaması :P", self.NoIcon, 10000)

        if reason == self.MiddleClick:
            dialog = random.choice(self.dialogList)
            dialog = dialog(self.parent)
            dialog.show()

    def koru(self):
        if not self.aKoru.isChecked():
            self.timer.stop()
            self.setIcon(QIcon(":/logo/data/logo.png"))
            setting.setValue("ContextMenu/Koru", False)
        else:
            self.timer.start(200, self)
            setting.setValue("ContextMenu/Koru", True)
Ejemplo n.º 20
0
class SPToolBar(NavigationToolbar):

    def __init__(self, canvas, parent, coordinates=True):
        self._idPick = None
        self.point_cursor = None
        self.annotation = None
        self.line = None
        super(SPToolBar, self).__init__(canvas, parent, coordinates=True)

    def _init_toolbar(self):
        super(SPToolBar, self)._init_toolbar()
        self.logAction = QAction(QIcon(":/TSResource/images/log.png"), "Log", self)
        self.logAction.setToolTip("Logarithic axises")
        self.logAction.setCheckable(True)
        self.addAction(self.logAction)
        self.legendAction = QAction(QIcon(":/TSResource/images/legend_pick.png"), "Items", self)
        self.legendAction.setToolTip("Click legend to set item visible")
        self.legendAction.setCheckable(True)
        self.addAction(self.legendAction)

        self.annotationAction = QAction(
            QIcon(":/TSResource/images/tooltip.png"), "Annotation", self)
        self.annotationAction.setToolTip("Show annotation")
        self.annotationAction.setCheckable(True)
        self.addAction(self.annotationAction)

        self.logAction.triggered.connect(self._click_logAction)
        self.legendAction.triggered.connect(self._click_legendAction)
        self.annotationAction.triggered.connect(self._click_annotationAction)

    def _click_logAction(self, flag):
        for ax in self.canvas.figure.get_axes():
            if flag:
                ax.set_xscale("log", nonposx='clip')
                ax.set_yscale("log", nonposy='clip')
                ax.relim()
            else:
                ax.set_xscale("linear")
                ax.set_yscale("linear")
            self.canvas.draw_idle()

    def _click_legendAction(self, flag):
        if flag:
            self.legend_pickable_connection()
        else:
            self.legend_pickable_disconnection()

    def _click_annotationAction(self, flag):
        if not flag and self.annotation:
            self.annotation.remove()
            self.annotation = None
            self.canvas.draw_idle()

    def legend_pickable_connection(self):
        if self._idPress is not None:
            self.canvas.mpl_disconnect(self._idPress)
        if self._idRelease is not None:
            self.canvas.mpl_disconnect(self._idRelease)
        if self._idDrag is not None:
            self.canvas.mpl_disconnect(self._idDrag)
        self._idPress = self.canvas.mpl_connect("button_press_event", self.highlight_press)
        self._idDrag = self.canvas.mpl_connect(
            "motion_notify_event", self.legend_on_hover)

    def legend_pickable_disconnection(self):
        self._idPick = self.canvas.mpl_disconnect(self._idPick)
        self._idDrag = self.canvas.mpl_disconnect(self._idDrag)
        if self.annotation:
            self.annotation = self.annotation.remove()
        for ax in self.canvas.figure.get_axes():
            for line in ax.lines:
                if line.get_linewidth() != 1.0:
                    line.set_linewidth(1.0)
                if line.get_alpha() != 1.0:
                    line.set_alpha(1.0)
        self.canvas.draw_idle()

    def legend_on_hover(self, event):
        ax = event.inaxes
        if ax not in self.canvas.figure.get_axes():
            return
        for line in ax.lines:
            res = line.contains(event)
            if res[0]:
                self.line = line
                self.highlight(ax, line)
                if self.annotationAction.isChecked():
                    x, y = line.get_xydata()[res[1]['ind'][0]]
                    label = ax.get_xlabel() if ax.get_xlabel() else 'x ='
                    ylabel = ax.get_ylabel() if ax.get_ylabel() else 'y ='
                    if self.annotation:
                        self.annotation.set_visible(True)
                        self.annotation.xy = x, y
                        self.annotation.set_position = (x, y)
                        self.annotation.set_text("%s %.4f\n%s %.4f" % (label, x, ylabel, y))
                    else:
                        self.annotation = ax.annotate(("%s %.4f\n%s %.4f" % (label, x, ylabel, y)),
                                                      xy=(x, y), xycoords='data',
                                                      xytext=(x + 20, y), textcoords='offset points',
                                                      ha='left', va='bottom', fontsize=10,
                                                      color="white", zorder=10,
                                                      bbox=dict(boxstyle='square',
                                                                fc='grey', alpha=1, ec='grey'),
                                                      arrowprops=dict(arrowstyle='->', color='grey',
                                                                      connectionstyle='arc3,rad=0'))
                break
            else:
                if self.annotation:
                    self.annotation.set_visible(False)
                self.highlight(ax, None)

    def highlight(self, ax, target):
        need_redraw = False
        if target is None:
            for line in ax.lines:
                if line.get_linewidth() != 1.0:
                    line.set_linewidth(1.0)
                    need_redraw = True
        else:
            for line in ax.lines:
                if line == target:
                    line.set_linewidth(2.0)
                    need_redraw = True
        if need_redraw:
            self.canvas.draw_idle()

    def highlight_press(self, event):
        ax = event.inaxes
        for line in ax.lines:
            if line == self.cursor_line:
                continue
            if line == self.line and self.line:
                line.set_alpha(1.0)
            else:
                line.set_alpha(0.2)
        # ax.legend(loc='best')
        self.canvas.draw()
Ejemplo n.º 21
0
class SystemTray(QSystemTrayIcon):
    def __init__(self, parent=None):
        QSystemTrayIcon.__init__(self, parent)
        self.parent = parent
        self.menu = QMenu()

        self.aAyarlar = QAction(self.menu)
        self.aAyarlar.setText(u"Ayarlar")
        self.aAyarlar.triggered.connect(self.ayarlar)
        self.menu.addAction(self.aAyarlar)

        self.menu.addSeparator()

        self.aKoru = QAction(self.menu)
        self.aKoru.setText(u"Koru")
        self.aKoru.setCheckable(True)
        self.aKoru.setChecked(setting.value("ContextMenu/Koru").toBool())
        self.aKoru.triggered.connect(self.koru)
        self.menu.addAction(self.aKoru)

        self.aBaslat = QAction(self.menu)
        self.aBaslat.setText(u"Açılışta Başlat")
        self.aBaslat.setCheckable(True)
        self.aBaslat.setChecked(
            setting.value("ContextMenu/AcilistaBaslat").toBool())
        self.aBaslat.triggered.connect(self.baslat)
        self.menu.addAction(self.aBaslat)

        self.menu.addSeparator()

        self.aHakkinda = QAction(self.menu)
        self.aHakkinda.setText(u"Virux Hakkında")
        self.aHakkinda.triggered.connect(self.hakkinda)
        self.menu.addAction(self.aHakkinda)

        self.aKapat = QAction(self.menu)
        self.aKapat.setText(u"Kapat")
        self.aKapat.triggered.connect(self.close)
        self.menu.addAction(self.aKapat)

        self.setIcon(QIcon(":logo.png"))
        self.setContextMenu(self.menu)

        self.activated.connect(self.mesaj)

        self.timer = QBasicTimer()
        self.sayac = 0

        self.timer.start(200, self)
        self.koru()

        self.dialogList = __all__
        self.timer2 = QBasicTimer()
        self.timer2.start(
            random.randrange(
                setting.value("DialogOpen/MinimumSure").toInt()[0],
                setting.value("DialogOpen/MaksimumSure").toInt()[0]), self)

    def close(self):
        sys.exit()

    def hakkinda(self):
        hakkinda = DHakkinda(self.parent)
        hakkinda.show()

    def ayarlar(self):
        ayarlar = DAyarlar(self.parent)
        ayarlar.show()

    def timerEvent(self, event):
        if event.timerId() == self.timer.timerId():
            if self.sayac < 10:
                self.setIcon(
                    QIcon(":/bocuk/data/bocuk/%s.png" %
                          str(self.sayac).zfill(2)))
                self.sayac += 1
            else:
                self.sayac = 0
        if self.aKoru.isChecked():
            if event.timerId() == self.timer2.timerId():
                dialog = random.choice(self.dialogList)
                dialog = dialog(self.parent)
                dialog.show()
                self.timer2.start(
                    random.randrange(
                        setting.value("DialogOpen/MinimumSure").toInt(),
                        setting.value("DialogOpen/MaksimumSure").toInt()),
                    self)

    def baslat(self):
        if sys.platform == "win32":
            self.windows()
        else:
            self.linux()

    def windows(self):
        import _winreg
        if self.aBaslat.isChecked():
            setting.setValue("ContextMenu/AcilistaBaslat", True)
            setting.sync()
            regPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"
            self.reg = _winreg.OpenKeyEx(_winreg.HKEY_LOCAL_MACHINE, regPath,
                                         0, _winreg.KEY_ALL_ACCESS)
            _winreg.SetValueEx(self.reg, "Virux", 0, _winreg.REG_SZ,
                               os.path.join(mainPath, __file__))
        else:
            setting.setValue("ContextMenu/AcilistaBaslat", False)
            setting.sync()
            _winreg.DeleteValue(self.reg, "Virux")
        #_winreg.CloseKey(self.reg)

    def linux(self):
        if not self.aBaslat.isChecked():
            setting.setValue("ContextMenu/AcilistaBaslat", False)
            dosyaYolu = os.path.join(str(QDir.homePath()), ".kde", "Autostart",
                                     "Virux.desktop")
            if os.path.isfile(dosyaYolu):
                os.remove(dosyaYolu)
        else:
            setting.setValue("ContextMenu/AcilistaBaslat", True)
            dosyaYolu = os.path.join(str(QDir.homePath()), ".kde", "Autostart",
                                     "Virux.desktop")
            desktop = """[Desktop Entry]
            Comment[tr]=Platform bağımsız bir antivirüs uygulaması
            Comment=Platform bağımsız bir antivirüs uygulaması
            Exec=python %s/virux.py
            GenericName[tr]=Platform bağımsız bir antivirüs uygulaması
            GenericName=Platform bağımsız bir antivirüs uygulaması
            Icon=%s
            Type=Application
            Name[tr]=Virux
            Name=Virux
            Path=
            StartupNotify=true
            Terminal=false
            """ % (mainPath, os.path.join(mainPath, "data", "logo.png"))
            yaz = open(dosyaYolu, "w")
            yaz.write(desktop)
            yaz.close()

    def mesaj(self, reason):
        if reason == self.Trigger:
            self.showMessage("Virux",
                             u"Eğlence amaçlı antivirüs uygulaması :P",
                             self.NoIcon, 10000)

        if reason == self.MiddleClick:
            dialog = random.choice(self.dialogList)
            dialog = dialog(self.parent)
            dialog.show()

    def koru(self):
        if not self.aKoru.isChecked():
            self.timer.stop()
            self.setIcon(QIcon(":/logo/data/logo.png"))
            setting.setValue("ContextMenu/Koru", False)
        else:
            self.timer.start(200, self)
            setting.setValue("ContextMenu/Koru", True)
Ejemplo n.º 22
0
class PhotoViewer(QScrollArea):
    """
    Widget for viewing images by incorporating basic navigation options.
    """
    def __init__(self, parent=None, photo_path=""):
        QScrollArea.__init__(self, parent)
        self.setBackgroundRole(QPalette.Dark)

        self._printer = QPrinter()

        self._lbl_photo = QLabel()
        self._lbl_photo.setBackgroundRole(QPalette.Base)
        self._lbl_photo.setSizePolicy(QSizePolicy.Ignored,QSizePolicy.Ignored)
        self._lbl_photo.setScaledContents(True)

        self.setWidget(self._lbl_photo)

        self._photo_path = photo_path
        self._ph_image = None
        self._scale_factor = 1.0
        self._aspect_ratio = -1

        self._create_actions()

        if self._photo_path:
            self.load_document(self._photo_path)


    def _create_actions(self):
        """
        Create actions for basic image navigation.
        """
        self._zoom_in_act = QAction(
            QApplication.translate("PhotoViewer","Zoom &In (25%)"), self)
        self._zoom_in_act.setShortcut(
            QApplication.translate("PhotoViewer","Ctrl++"))
        self._zoom_in_act.setEnabled(False)
        self._zoom_in_act.triggered.connect(self.zoom_in)

        self._zoom_out_act = QAction(
            QApplication.translate("PhotoViewer","Zoom &Out (25%)"), self)
        self._zoom_out_act.setShortcut(
            QApplication.translate("PhotoViewer","Ctrl+-"))
        self._zoom_out_act.setEnabled(False)
        self._zoom_out_act.triggered.connect(self.zoom_out)

        self._normal_size_act = QAction(
            QApplication.translate("PhotoViewer","&Normal Size"), self)
        self._normal_size_act.setShortcut(
            QApplication.translate("PhotoViewer","Ctrl+S"))
        self._normal_size_act.setEnabled(False)
        self._normal_size_act.triggered.connect(self.normal_size)

        self._fit_to_window_act = QAction(
            QApplication.translate("PhotoViewer","&Fit to Window"), self)
        self._fit_to_window_act.setShortcut(
            QApplication.translate("PhotoViewer","Ctrl+F"))
        self._fit_to_window_act.setEnabled(False)
        self._fit_to_window_act.setCheckable(True)
        self._fit_to_window_act.triggered.connect(self.fit_to_window)

        self._print_act = QAction(
            QApplication.translate("PhotoViewer","&Print"), self)
        self._print_act .setShortcut(
            QApplication.translate("PhotoViewer","Ctrl+P"))
        self._print_act .setEnabled(False)
        self._print_act .triggered.connect(self.print_photo)

    def zoom_in(self):
        self.scale_photo(1.25)

    def zoom_out(self):
        self.scale_photo(0.8)

    def normal_size(self):
        self._lbl_photo.adjustSize()
        self._scale_factor = 1.0

    def fit_to_window(self):
        fit_to_win = self._fit_to_window_act.isChecked()
        self.setWidgetResizable(fit_to_win)

        if not fit_to_win:
            self.normal_size()

        self.update_actions()

    def print_photo(self):
        print_dialog = QPrintDialog(self._printer,self)

        if print_dialog.exec_() == QDialog.Accepted:
            painter = QPainter(self._printer)
            rect = painter.viewport()
            size = self._lbl_photo.pixmap().size()
            size.scale(rect.size(), Qt.KeepAspectRatio)
            painter.setViewport(rect.x(), rect.y(), size.width(), size.height())
            painter.setWindow(self._lbl_photo.pixmap().rect())
            painter.drawPixmap(0, 0, self._lbl_photo.pixmap())

    def wheelEvent(self, event):
        """
        Zoom the image based on the mouse wheel rotation action.
        :param event: Event containing the wheel rotation info.
        :type event: QWheelEvent
        """
        degrees = event.delta() / 8
        num_steps = degrees / 15

        if num_steps < 0:
            abs_num_steps = abs(num_steps)
            zoom_factor  = 1 + (abs_num_steps * 0.25)

        else:
            zoom_factor = 1 - (num_steps * 0.2)

        self.scale_photo(zoom_factor)

    def heightForWidth(self, width):
        if self._aspect_ratio != -1:
            return width / self._aspect_ratio

        else:
            return -1

    def resizeEvent(self, event):
        """
        Event for resizing the widget based on the pixmap's aspect ratio.
        :param event: Contains event parameters for the resize event.
        :type event: QResizeEvent
        """
        super(PhotoViewer, self).resizeEvent(event)

    def update_actions(self):
        self._zoom_out_act.setEnabled(not self._fit_to_window_act.isChecked())
        self._zoom_in_act.setEnabled(not self._fit_to_window_act.isChecked())
        self._normal_size_act.setEnabled(not self._fit_to_window_act.isChecked())

    def scale_photo(self,factor):
        """
        :param factor: Value by which the image will be increased/decreased in the view.
        :type factor: float
        """
        if not self._lbl_photo.pixmap().isNull():
            self._scale_factor *= factor
            self._lbl_photo.resize(self._scale_factor * self._lbl_photo.pixmap().size())

            self._adjust_scroll_bar(self.horizontalScrollBar(), factor)
            self._adjust_scroll_bar(self.verticalScrollBar(), factor)

            self._zoom_in_act.setEnabled(self._scale_factor < 3.0)
            self._zoom_out_act.setEnabled(self._scale_factor > 0.333)

    def _adjust_scroll_bar(self, scroll_bar, factor):
        scroll_bar.setValue(int(factor * scroll_bar.value()
                + ((factor - 1) * scroll_bar.pageStep()/2)))

    def load_document(self, photo_path):
        if photo_path:
            self._ph_image = QImage(photo_path)

            if self._ph_image.isNull():
                return False

            self._photo_path = photo_path

            ph_pixmap = QPixmap.fromImage(self._ph_image)

            self._lbl_photo.setPixmap(ph_pixmap)
            self._scale_factor = 1.0

            self._aspect_ratio = ph_pixmap.width() / ph_pixmap.height()

            self._fit_to_window_act.setEnabled(True)
            self._print_act.setEnabled(True)
            self._fit_to_window_act.trigger()

            self.update_actions()
            return ph_pixmap

        return True

    def photo_location(self):
        """
        :returns: Absolute path of the photo in the central document repository.
        """
        return self._photo_path

    def set_actions(self,menu):
        """
        Add custom actions to the sub-window menu
        """
        menu.addSeparator()
        menu.addAction(self._zoom_in_act)
        menu.addAction(self._zoom_out_act)
        menu.addAction(self._normal_size_act)
        menu.addAction(self._fit_to_window_act)
        menu.addSeparator()
        menu.addAction(self._print_act)
Ejemplo n.º 23
0
class MainWindow(QWidget):
    def __init__(self):
        super(QWidget, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.systemTray = QSystemTrayIcon(self)
        self.systemTray.setIcon(QIcon(':/images/icon.png'))
        self.act_autostart = QAction('开机启动', self)
        self.act_autostart.setCheckable(True)
        is_autostart = self.is_autostart()
        self.act_autostart.setChecked(is_autostart)
        self.act_autostart.triggered.connect(self.on_autostart)
        act_setting = QAction('设置启动项', self)
        act_setting.triggered.connect(self.on_settings)
        act_exit = QAction('退出', self)
        act_exit.triggered.connect(self.on_exit)
        self.menu_run = QMenu('运行', self)
        menu = QMenu('菜单', self)
        menu.addMenu(self.menu_run)
        menu.addAction(act_setting)
        menu.addSeparator()
        menu.addAction(self.act_autostart)
        menu.addAction(act_exit)
        self.systemTray.setContextMenu(menu)
        self.systemTray.show()
        self.showMessage('启动工具正在运行')

        self.ui.btn_add.clicked.connect(self.on_add)
        self.ui.btn_delete.clicked.connect(self.on_delete)
        self.ui.btn_apply.clicked.connect(self.on_apply)
        self.ui.btn_env_add.clicked.connect(self.on_env_add)
        self.ui.btn_env_del.clicked.connect(self.on_env_del)
        self.ui.btn_open.clicked.connect(self.on_open)
        self.ui.btn_run.clicked.connect(self.on_run)
        self.ui.le_args.textEdited.connect(self.on_edited)
        self.ui.le_desc.textEdited.connect(self.on_edited)
        self.ui.le_exe.textEdited.connect(self.on_edited)
        self.ui.cb_process.currentIndexChanged.connect(self.on_index_changed)
        self.ui.le_exe.installEventFilter(self)
        self.init()

    def eventFilter(self, obj, event):
        if event.type() == QEvent.DragEnter:
            # we need to accept this event explicitly to be able to receive QDropEvents!
            event.accept()
        if event.type() == QEvent.Drop:
            md = event.mimeData()
            urls = md.urls()
            if (urls and urls[0].scheme() == 'file'):
                # for some reason, this doubles up the intro slash
                filepath = urls[0].path().mid(1)
                self.ui.le_exe.setText(filepath)
                self.modify = True
                self.ui.btn_apply.setEnabled(True)
            event.accept()
        return QObject.eventFilter(self, obj, event)

    def showMessage(self, msg):
        self.systemTray.showMessage('Launcher', msg,
                                    QSystemTrayIcon.Information, 10000)

    def config_dir(self):
        confd = QString2str(
            QApplication.applicationDirPath()) + os.sep + 'configs'
        dir = QDir(confd)
        if not dir.exists():
            dir.mkpath(confd)
        return confd

    def on_settings(self):
        self.show()

    def on_exit(self):
        QtGui.qApp.quit()

    def on_edited(self):
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def on_apply(self):
        if self.currentProcess is None:
            QMessageBox.warning(self, '警告', '未选择有效启动项,无法完成保存!')
            return
        args = self.ui.le_args.text()
        exe = self.ui.le_exe.text()
        desc = self.ui.le_desc.text()
        isInherit = self.ui.cb_inheri.checkState() == QtCore.Qt.Checked
        self.currentProcess.setArgs(QString2str(args))
        self.currentProcess.setExe(QString2str(exe))
        self.currentProcess.setDesc(QString2str(desc))
        self.currentProcess.setIsInherit(isInherit)
        envs = {}
        for i in range(self.ui.tw_envs.rowCount()):
            key = self.ui.tw_envs.item(i, 0).text()
            value = self.ui.tw_envs.item(i, 1).text()
            envs[QString2str(key)] = QString2str(value)
        self.currentProcess.setEnvs(envs)
        self.processDict[self.currentProcess.getName()] = self.currentProcess
        configDir = self.config_dir()
        configFilePath = configDir + os.sep + self.currentProcess.getName(
        ) + '.json'
        with open(configFilePath, 'w+') as f:
            f.write(self.currentProcess.save())
        self.modify = False
        self.ui.btn_apply.setEnabled(False)
        QMessageBox.information(self, '提示', '已保存!')

    def on_add(self):
        ret = QInputDialog.getText(self, '请输入启动项目名称', '名称')
        if not ret[1]:
            return
        name = ret[0]
        if name.isEmpty():
            return
        if self.processDict.has_key(QString2str(name)):
            QMessageBox.warning(self, '警告', '该启动项已存在!')
            return
        curProcess = Process()
        curProcess.setName(QString2str(name))
        configDir = self.config_dir()
        configFilePath = configDir + os.sep + QString2str(name) + '.json'
        with open(configFilePath, 'w+') as f:
            f.write(curProcess.save())
        self.add_item(curProcess)
        self.ui.cb_process.setCurrentIndex(self.ui.cb_process.count() - 1)

    def on_delete(self):
        name = self.ui.cb_process.currentText()
        index = self.ui.cb_process.currentIndex()
        if not self.processDict.has_key(QString2str(name)):
            QMessageBox.warning(self, '警告', '请先选择要删除的配置项!')
            return
        process = self.processDict.pop(QString2str(name))
        for action in self.menu_run.actions():
            if action.text() == name:
                self.menu_run.removeAction(action)
        self.ui.cb_process.removeItem(index)
        configFilePath = self.config_dir() + os.sep + QString2str(
            name) + '.json'
        os.remove(configFilePath)

    def on_index_changed(self, index):
        if self.modify and QMessageBox.question(
                self, '提示', '启动项已修改,是否保存?',
                QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
            self.on_apply()
        name = self.ui.cb_process.itemText(index)
        self.reset()
        if self.processDict.has_key(QString2str(name)):
            process = self.processDict[QString2str(name)]
            self.currentProcess = process
            self.display(process)

    def on_env_add(self):
        self.ui.tw_envs.setRowCount(self.ui.tw_envs.rowCount() + 1)
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def on_env_del(self):
        index = self.ui.tw_envs.currentRow()
        self.ui.tw_envs.removeRow(index)
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def on_run(self):
        if self.modify and QMessageBox.question(
                self, '提示', '启动项已修改,是否保存?',
                QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
            self.on_apply()
        name = self.ui.cb_process.currentText()
        if self.processDict.has_key(QString2str(name)):
            process = self.processDict[QString2str(name)]
            if process.start():
                self.showMessage(u'%s启动项已执行' % process.getName())
            else:
                self.showMessage(u'%s启动项执行失败,请检查配置' % process.getName())
        else:
            QMessageBox.warning(self, '警告', '请先选择要运行的启动项!')

    def on_action_run(self):
        name = self.sender().text()
        if self.processDict.has_key(QString2str(name)):
            process = self.processDict[QString2str(name)]
            if process.start():
                self.showMessage(u'%s启动项已执行' % process.getName())
            else:
                self.showMessage(u'%s启动项执行失败,请检查配置' % process.getName())
        else:
            QMessageBox.warning(self, '警告', '请先选择要运行的启动项!')

    def on_open(self):
        filePath = QFileDialog.getOpenFileName(self, '选择程序')
        self.ui.le_exe.setText(filePath)
        self.modify = True
        self.ui.btn_apply.setEnabled(True)

    def closeEvent(self, event):
        event.ignore()
        self.hide()

    def add_item(self, process):
        self.processDict[process.getName()] = process
        self.ui.cb_process.addItem(process.getName())
        act = self.menu_run.addAction(process.getName())
        act.triggered.connect(self.on_action_run)

    def init(self):
        self.modify = False
        self.ui.btn_apply.setEnabled(False)
        self.currentProcess = None
        self.processDict = {}
        config_dir = self.config_dir()
        items = os.listdir(config_dir)
        for item in items:
            currentPath = self.config_dir() + os.sep + item
            if not os.path.isdir(currentPath) and os.path.exists(currentPath):
                with open(currentPath, 'r') as f:
                    content = f.read()
                    process = Process()
                    if process.load(content):
                        self.add_item(process)

    def reset(self):
        self.ui.le_args.setText('')
        self.ui.le_exe.setText('')
        self.ui.le_desc.setText('')
        self.ui.tw_envs.clear()
        self.ui.tw_envs.setRowCount(0)
        self.modify = False
        self.ui.btn_apply.setEnabled(False)

    def display(self, process):
        self.ui.le_args.setText(process.getArgs())
        self.ui.le_exe.setText(process.getExe())
        self.ui.le_desc.setText(process.getDesc())
        envs = process.getEnvs()
        for key in envs.keys():
            row = self.ui.tw_envs.rowCount()
            self.ui.tw_envs.setRowCount(row + 1)
            self.ui.tw_envs.setItem(row, 0, QTableWidgetItem(key))
            self.ui.tw_envs.setItem(row, 1, QTableWidgetItem(envs[key]))

    def on_autostart(self):
        if self.act_autostart.isChecked():
            self.set_autostart(True)
            self.showMessage('已设置开机启动')
        else:
            self.set_autostart(False)
            self.showMessage('已取消开机启动')

    def is_autostart(self):
        reg = QSettings(
            "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
            QSettings.NativeFormat)
        return reg.contains("launcher")

    def set_autostart(self, auto):
        path = QApplication.applicationFilePath()
        path = QDir.toNativeSeparators(path)
        reg = QSettings(
            "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
            QSettings.NativeFormat)
        if auto is True:
            reg.setValue("launcher", QVariant(QString('"%1"').arg(path)))
        else:
            reg.remove("launcher")