Ejemplo n.º 1
0
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        layout = QVBoxLayout()
        self.editor = TextEdit()
        # Setup the QTextEdit editor configuration
        self.editor.setAutoFormatting(QTextEdit.AutoAll)
        self.editor.selectionChanged.connect(self.update_format)
        # Initialize default font size.
        font = QFont('Times', 12)
        self.editor.setFont(font)
        # We need to repeat the size to init the current format.
        self.editor.setFontPointSize(12)

        # self.path holds the path of the currently open file.
        # If none, we haven't got a file open yet (or creating new).
        self.path = None

        layout.addWidget(self.editor)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.status = QStatusBar()
        self.setStatusBar(self.status)

        # Uncomment to disable native menubar on Mac
        # self.menuBar().setNativeMenuBar(False)

        file_toolbar = QToolBar("File")
        file_toolbar.setIconSize(QSize(14, 14))
        self.addToolBar(file_toolbar)
        file_menu = self.menuBar().addMenu("&File")

        open_file_action = QAction(
            QIcon(os.path.join('images', 'blue-folder-open-document.png')),
            "Open file...", self)
        open_file_action.setStatusTip("Open file")
        open_file_action.triggered.connect(self.file_open)
        file_menu.addAction(open_file_action)
        file_toolbar.addAction(open_file_action)

        save_file_action = QAction(QIcon(os.path.join('images', 'disk.png')),
                                   "Save", self)
        save_file_action.setStatusTip("Save current page")
        save_file_action.triggered.connect(self.file_save)
        file_menu.addAction(save_file_action)
        file_toolbar.addAction(save_file_action)

        saveas_file_action = QAction(
            QIcon(os.path.join('images', 'disk--pencil.png')), "Save As...",
            self)
        saveas_file_action.setStatusTip("Save current page to specified file")
        saveas_file_action.triggered.connect(self.file_saveas)
        file_menu.addAction(saveas_file_action)
        file_toolbar.addAction(saveas_file_action)

        print_action = QAction(QIcon(os.path.join('images', 'printer.png')),
                               "Print...", self)
        print_action.setStatusTip("Print current page")
        print_action.triggered.connect(self.file_print)
        file_menu.addAction(print_action)
        file_toolbar.addAction(print_action)

        edit_toolbar = QToolBar("Edit")
        edit_toolbar.setIconSize(QSize(16, 16))
        self.addToolBar(edit_toolbar)
        edit_menu = self.menuBar().addMenu("&Edit")

        undo_action = QAction(
            QIcon(os.path.join('images', 'arrow-curve-180-left.png')), "Undo",
            self)
        undo_action.setStatusTip("Undo last change")
        undo_action.triggered.connect(self.editor.undo)
        edit_menu.addAction(undo_action)

        redo_action = QAction(QIcon(os.path.join('images', 'arrow-curve.png')),
                              "Redo", self)
        redo_action.setStatusTip("Redo last change")
        redo_action.triggered.connect(self.editor.redo)
        edit_toolbar.addAction(redo_action)
        edit_menu.addAction(redo_action)

        edit_menu.addSeparator()

        cut_action = QAction(QIcon(os.path.join('images', 'scissors.png')),
                             "Cut", self)
        cut_action.setStatusTip("Cut selected text")
        cut_action.setShortcut(QKeySequence.Cut)
        cut_action.triggered.connect(self.editor.cut)
        edit_toolbar.addAction(cut_action)
        edit_menu.addAction(cut_action)

        copy_action = QAction(
            QIcon(os.path.join('images', 'document-copy.png')), "Copy", self)
        copy_action.setStatusTip("Copy selected text")
        cut_action.setShortcut(QKeySequence.Copy)
        copy_action.triggered.connect(self.editor.copy)
        edit_toolbar.addAction(copy_action)
        edit_menu.addAction(copy_action)

        paste_action = QAction(
            QIcon(os.path.join('images', 'clipboard-paste-document-text.png')),
            "Paste", self)
        paste_action.setStatusTip("Paste from clipboard")
        cut_action.setShortcut(QKeySequence.Paste)
        paste_action.triggered.connect(self.editor.paste)
        edit_toolbar.addAction(paste_action)
        edit_menu.addAction(paste_action)

        select_action = QAction(
            QIcon(os.path.join('images', 'selection-input.png')), "Select all",
            self)
        select_action.setStatusTip("Select all text")
        cut_action.setShortcut(QKeySequence.SelectAll)
        select_action.triggered.connect(self.editor.selectAll)
        edit_menu.addAction(select_action)

        edit_menu.addSeparator()

        wrap_action = QAction(
            QIcon(os.path.join('images', 'arrow-continue.png')),
            "Wrap text to window", self)
        wrap_action.setStatusTip("Toggle wrap text to window")
        wrap_action.setCheckable(True)
        wrap_action.setChecked(True)
        wrap_action.triggered.connect(self.edit_toggle_wrap)
        edit_menu.addAction(wrap_action)

        format_toolbar = QToolBar("Format")
        format_toolbar.setIconSize(QSize(16, 16))
        self.addToolBar(format_toolbar)
        format_menu = self.menuBar().addMenu("&Format")

        # We need references to these actions/settings to update as selection changes, so attach to self.
        self.fonts = QFontComboBox()
        self.fonts.currentFontChanged.connect(self.editor.setCurrentFont)
        format_toolbar.addWidget(self.fonts)

        self.fontsize = QComboBox()
        self.fontsize.addItems([str(s) for s in FONT_SIZES])

        # Connect to the signal producing the text of the current selection. Convert the string to float
        # and set as the pointsize. We could also use the index + retrieve from FONT_SIZES.
        self.fontsize.currentIndexChanged[str].connect(
            lambda s: self.editor.setFontPointSize(float(s)))
        format_toolbar.addWidget(self.fontsize)

        self.bold_action = QAction(
            QIcon(os.path.join('images', 'edit-bold.png')), "Bold", self)
        self.bold_action.setStatusTip("Bold")
        self.bold_action.setShortcut(QKeySequence.Bold)
        self.bold_action.setCheckable(True)
        self.bold_action.toggled.connect(lambda x: self.editor.setFontWeight(
            QFont.Bold if x else QFont.Normal))
        format_toolbar.addAction(self.bold_action)
        format_menu.addAction(self.bold_action)

        self.italic_action = QAction(
            QIcon(os.path.join('images', 'edit-italic.png')), "Italic", self)
        self.italic_action.setStatusTip("Italic")
        self.italic_action.setShortcut(QKeySequence.Italic)
        self.italic_action.setCheckable(True)
        self.italic_action.toggled.connect(self.editor.setFontItalic)
        format_toolbar.addAction(self.italic_action)
        format_menu.addAction(self.italic_action)

        self.underline_action = QAction(
            QIcon(os.path.join('images', 'edit-underline.png')), "Underline",
            self)
        self.underline_action.setStatusTip("Underline")
        self.underline_action.setShortcut(QKeySequence.Underline)
        self.underline_action.setCheckable(True)
        self.underline_action.toggled.connect(self.editor.setFontUnderline)
        format_toolbar.addAction(self.underline_action)
        format_menu.addAction(self.underline_action)

        format_menu.addSeparator()

        self.alignl_action = QAction(
            QIcon(os.path.join('images', 'edit-alignment.png')), "Align left",
            self)
        self.alignl_action.setStatusTip("Align text left")
        self.alignl_action.setCheckable(True)
        self.alignl_action.triggered.connect(
            lambda: self.editor.setAlignment(Qt.AlignLeft))
        format_toolbar.addAction(self.alignl_action)
        format_menu.addAction(self.alignl_action)

        self.alignc_action = QAction(
            QIcon(os.path.join('images', 'edit-alignment-center.png')),
            "Align center", self)
        self.alignc_action.setStatusTip("Align text center")
        self.alignc_action.setCheckable(True)
        self.alignc_action.triggered.connect(
            lambda: self.editor.setAlignment(Qt.AlignCenter))
        format_toolbar.addAction(self.alignc_action)
        format_menu.addAction(self.alignc_action)

        self.alignr_action = QAction(
            QIcon(os.path.join('images', 'edit-alignment-right.png')),
            "Align right", self)
        self.alignr_action.setStatusTip("Align text right")
        self.alignr_action.setCheckable(True)
        self.alignr_action.triggered.connect(
            lambda: self.editor.setAlignment(Qt.AlignRight))
        format_toolbar.addAction(self.alignr_action)
        format_menu.addAction(self.alignr_action)

        self.alignj_action = QAction(
            QIcon(os.path.join('images', 'edit-alignment-justify.png')),
            "Justify", self)
        self.alignj_action.setStatusTip("Justify text")
        self.alignj_action.setCheckable(True)
        self.alignj_action.triggered.connect(
            lambda: self.editor.setAlignment(Qt.AlignJustify))
        format_toolbar.addAction(self.alignj_action)
        format_menu.addAction(self.alignj_action)

        format_group = QActionGroup(self)
        format_group.setExclusive(True)
        format_group.addAction(self.alignl_action)
        format_group.addAction(self.alignc_action)
        format_group.addAction(self.alignr_action)
        format_group.addAction(self.alignj_action)

        format_menu.addSeparator()

        # A list of all format-related widgets/actions, so we can disable/enable signals when updating.
        self._format_actions = [
            self.fonts,
            self.fontsize,
            self.bold_action,
            self.italic_action,
            self.underline_action,
            # We don't need to disable signals for alignment, as they are paragraph-wide.
        ]

        # Initialize.
        self.update_format()
        self.update_title()
        self.show()
Ejemplo n.º 2
0
    def initMenuBar(self):
        self.menu = self.menuBar()

        file_menu = self.menu.addMenu("File")
        file_menu.addAction(self.newGameAction)
        #file_menu.addAction(QIcon(CONST.ICONS["Open"]), "Open") # TODO : implement
        file_menu.addAction(self.saveGameAction)
        file_menu.addSeparator()
        file_menu.addAction(self.showLiberationPrefDialogAction)
        file_menu.addSeparator()
        #file_menu.addAction("Save As") # TODO : implement
        #file_menu.addAction("Close Current Game", lambda: self.closeGame()) # Not working
        file_menu.addAction("Exit" , lambda: self.exit())


        help_menu = self.menu.addMenu("Help")
        help_menu.addAction("Online Manual", lambda: webbrowser.open_new_tab(URLS["Manual"]))
        help_menu.addAction("Discord", lambda: webbrowser.open_new_tab("https://" + "discord.gg" + "/" + "bKrt" + "rkJ"))
        #help_menu.addAction("Troubleshooting Guide", lambda: webbrowser.open_new_tab(URLS["Troubleshooting"]))
        #help_menu.addAction("Modding Guide", lambda: webbrowser.open_new_tab(URLS["Modding"]))
        #help_menu.addSeparator() ----> Note from Khopa : I disable these links since it's not up to date for this branch
        #help_menu.addAction("Contribute", lambda: webbrowser.open_new_tab(URLS["Repository"]))
        help_menu.addAction("Forum Thread", lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
        help_menu.addAction("Report an issue", lambda: webbrowser.open_new_tab(URLS["Issues"]))
        help_menu.addSeparator()
        help_menu.addAction(self.showAboutDialogAction)

        displayMenu = self.menu.addMenu("Display")

        tg_cp_visibility = QAction('Control Point', displayMenu)
        tg_cp_visibility.setCheckable(True)
        tg_cp_visibility.setChecked(True)
        tg_cp_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("cp", tg_cp_visibility.isChecked()))

        tg_go_visibility = QAction('Ground Objects', displayMenu)
        tg_go_visibility.setCheckable(True)
        tg_go_visibility.setChecked(True)
        tg_go_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("go", tg_go_visibility.isChecked()))

        tg_line_visibility = QAction('Lines', displayMenu)
        tg_line_visibility.setCheckable(True)
        tg_line_visibility.setChecked(True)
        tg_line_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule("lines", tg_line_visibility.isChecked()))

        tg_event_visibility = QAction('Events', displayMenu)
        tg_event_visibility.setCheckable(True)
        tg_event_visibility.setChecked(True)
        tg_event_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("events", tg_event_visibility.isChecked()))

        tg_sam_visibility = QAction('SAM Range', displayMenu)
        tg_sam_visibility.setCheckable(True)
        tg_sam_visibility.setChecked(True)
        tg_sam_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("sam", tg_sam_visibility.isChecked()))

        tg_flight_path_visibility = QAction('Flight Paths', displayMenu)
        tg_flight_path_visibility.setCheckable(True)
        tg_flight_path_visibility.setChecked(False)
        tg_flight_path_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("flight_paths", tg_flight_path_visibility.isChecked()))

        displayMenu.addAction(tg_go_visibility)
        displayMenu.addAction(tg_cp_visibility)
        displayMenu.addAction(tg_line_visibility)
        displayMenu.addAction(tg_event_visibility)
        displayMenu.addAction(tg_sam_visibility)
        displayMenu.addAction(tg_flight_path_visibility)
    def initMenuBar(self):
        self.menu = self.menuBar()

        file_menu = self.menu.addMenu("&File")
        file_menu.addAction(self.newGameAction)
        file_menu.addAction(self.openAction)
        file_menu.addSeparator()
        file_menu.addAction(self.saveGameAction)
        file_menu.addAction(self.saveAsAction)
        file_menu.addSeparator()
        file_menu.addAction(self.showLiberationPrefDialogAction)
        file_menu.addSeparator()
        #file_menu.addAction("Close Current Game", lambda: self.closeGame()) # Not working
        file_menu.addAction("E&xit" , lambda: self.exit())

        displayMenu = self.menu.addMenu("&Display")

        tg_cp_visibility = QAction('&Control Point', displayMenu)
        tg_cp_visibility.setCheckable(True)
        tg_cp_visibility.setChecked(True)
        tg_cp_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("cp", tg_cp_visibility.isChecked()))

        tg_go_visibility = QAction('&Ground Objects', displayMenu)
        tg_go_visibility.setCheckable(True)
        tg_go_visibility.setChecked(True)
        tg_go_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("go", tg_go_visibility.isChecked()))

        tg_line_visibility = QAction('&Lines', displayMenu)
        tg_line_visibility.setCheckable(True)
        tg_line_visibility.setChecked(True)
        tg_line_visibility.toggled.connect(
            lambda: QLiberationMap.set_display_rule("lines", tg_line_visibility.isChecked()))

        tg_event_visibility = QAction('&Events', displayMenu)
        tg_event_visibility.setCheckable(True)
        tg_event_visibility.setChecked(True)
        tg_event_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("events", tg_event_visibility.isChecked()))

        tg_sam_visibility = QAction('&SAM Range', displayMenu)
        tg_sam_visibility.setCheckable(True)
        tg_sam_visibility.setChecked(True)
        tg_sam_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("sam", tg_sam_visibility.isChecked()))

        tg_flight_path_visibility = QAction('&Flight Paths', displayMenu)
        tg_flight_path_visibility.setCheckable(True)
        tg_flight_path_visibility.setChecked(False)
        tg_flight_path_visibility.toggled.connect(lambda: QLiberationMap.set_display_rule("flight_paths", tg_flight_path_visibility.isChecked()))

        displayMenu.addAction(tg_go_visibility)
        displayMenu.addAction(tg_cp_visibility)
        displayMenu.addAction(tg_line_visibility)
        displayMenu.addAction(tg_event_visibility)
        displayMenu.addAction(tg_sam_visibility)
        displayMenu.addAction(tg_flight_path_visibility)

        help_menu = self.menu.addMenu("&Help")
        help_menu.addAction("&Discord Server", lambda: webbrowser.open_new_tab("https://" + "discord.gg" + "/" + "bKrt" + "rkJ"))
        help_menu.addAction("&Github Repository", lambda: webbrowser.open_new_tab("https://github.com/khopa/dcs_liberation"))
        help_menu.addAction("&Releases", lambda: webbrowser.open_new_tab("https://github.com/Khopa/dcs_liberation/releases"))
        help_menu.addAction("&Online Manual", lambda: webbrowser.open_new_tab(URLS["Manual"]))
        help_menu.addAction("&ED Forum Thread", lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
        help_menu.addAction("Report an &issue", lambda: webbrowser.open_new_tab(URLS["Issues"]))

        help_menu.addSeparator()
        help_menu.addAction(self.showAboutDialogAction)
Ejemplo n.º 4
0
class MainWindow(QMainWindow):
    def __init__(self, tedaCommandLine):
        super().__init__()
        self.tedaCommandLine = tedaCommandLine
        self.cmaps = ColorMaps()
        self.combobox = QComboBox()
        self.filename = None
        self.isMousePressed = False
        self.isCmdPressed = False
        self.cursor_coords = CoordinatesModel()
        self.scales_model = ScalesModel()
        fig = Figure(figsize=(14, 10))
        fig.tight_layout()
        self.fits_image = FitsPlotter(figure=fig)
        fig.subplots_adjust(left=0,
                            bottom=0.001,
                            right=1,
                            top=1,
                            wspace=None,
                            hspace=None)

        self.fits_image = FitsPlotterFitsFile(figure=fig,
                                              cmap_model=self.cmaps,
                                              scale_model=self.scales_model)
        self.central_widget = FigureCanvas(fig)
        self.setCentralWidget(self.central_widget)

        self.current_x_coord = 0
        self.current_y_coord = 0

        self.fullWidgetXcord = 0
        self.fullWidgetYcord = 0
        self.centralWidgetcordX = 0
        self.centralWidgetcordY = 0

        self.painterComponent = PainterComponent(self.fits_image)
        # self.painterComponent.startMovingEvents(self.central_widget)
        self.painterComponent.setCanvas(self.central_widget)
        self.scanObject = ScanToolbar(self)
        self.createActions()
        self.createMenus()
        self.createToolBars()
        self.createStatusBar()
        self.createDockWindows()
        if not self.tedaCommandLine.ignoreSettings:
            self.scaleWidget.readSlidersValues()
        # self.defineButtonsActions()
        self.setWindowTitle("TeDa")

        self.painterComponent.observe(
            lambda change: self.onAutoCenterChange(change), ['auto_center'])

        self.readWindowSettings()
        self.readAppState()

        self.updateHeaderData()
        self.dragging = draggingComponent.Dragging(
            widget=self, scale_widget=self.scaleWidget)
        self.activeLinearAdjustmentByMouseMovement()

        # Observing here may be to late for values loaded from settings e.g. via readAppState
        self.painterComponent.observe(
            lambda change: self.onCenterCircleChange(change),
            ['ccenter_x', 'ccenter_y'])
        self.painterComponent.observe(
            lambda change: self.onCenterCircleRadiusChange(change),
            ['cradius'])
        self.fits_image.observe(lambda change: self.onMouseMoveOnImage(change),
                                ['mouse_xdata', 'mouse_ydata'])
        # self.cmaps.observe(lambda change: self.on_colormap_change(change))
        self.full_view_widget.painterComponent.observe(
            lambda change: self.onRectangleInWidgetMove(change),
            ['viewX', 'viewY'])
        self.painterComponent.observe(
            lambda change: self.movingCentralWidget(change),
            ['movingViewX', 'movingViewY'])
        self.fits_image.observe(lambda change: self.onMouseZoomOnImage(change),
                                ['viewBounaries_versionno'])

        # open last fits
        try:
            self.openLastFits()
        except FileNotFoundError:
            print('Błąd w odczycie lub brak ostatio wczytanego pliku')

    def closeEvent(self, event: PySide2.QtGui.QCloseEvent):
        self.writeAppState()
        self.writeWindowSettings()
        if not self.tedaCommandLine.ignoreSettings:
            self.scaleWidget.writeSlidersValues()
        super().closeEvent(event)

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Delete:
            self.deleteSelected()
        if e.key() == Qt.Key_R:
            action = self.dockRadialFit.toggleViewAction()
            if not action.isChecked():
                action.trigger()
            if (self.cursor_coords.img_x != 0 and self.cursor_coords.img_x !=
                    None) and (self.cursor_coords.img_y != 0
                               and self.cursor_coords.img_y != None):
                self.painterComponent.add(self.cursor_coords.img_x,
                                          self.cursor_coords.img_y,
                                          type="circleCenter")
                self.painterComponent.paintAllShapes(
                    self.central_widget.figure.axes[0])
        if e.key() == Qt.Key_Control:
            self.isCmdPressed = True

    def keyReleaseEvent(self, event: PySide2.QtGui.QKeyEvent):
        if event.key() == Qt.Key_Control:
            self.isCmdPressed = False

    def canvasMousePressEvent(self, event):
        self.isMousePressed = not self.isMousePressed

    def mouseMoveEventOnCanvas(self, event):
        if self.isCmdPressed:
            if self.isMousePressed:
                self.dragging.mouseMoveEvent(event)

    def print_(self):
        document = self.textEdit.document()
        printer = QPrinter()

        dlg = QPrintDialog(printer, self)
        if dlg.exec_() != QDialog.Accepted:
            return

        document.print_(printer)

        self.statusBar().showMessage("Ready", 2000)

    def open_dialog(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Open Image", ".",
                                                  "Fits files (*.fits)")
        if fileName:
            self.open_fits(fileName)

    def save(self):
        filename, _ = QFileDialog.getSaveFileName(self, "Choose a file name",
                                                  '.', "HTML (*.html *.htm)")
        if not filename:
            return

        file = QFile(filename)
        if not file.open(QFile.WriteOnly | QFile.Text):
            QMessageBox.warning(
                self, "Dock Widgets",
                "Cannot write file %s:\n%s." % (filename, file.errorString()))
            return

        out = QTextStream(file)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        out << self.textEdit.toHtml()
        QApplication.restoreOverrideCursor()

        self.statusBar().showMessage("Saved '%s'" % filename, 2000)

    def save_dialog(self):
        figure = self.central_widget.figure
        filetypes = figure.canvas.get_supported_filetypes_grouped()
        filterstr = ';;'.join([
            k + ' (' + ' '.join(['*.' + ext for ext in v]) + ')'
            for k, v in filetypes.items()
        ])
        dialog = QFileDialog.getSaveFileName(
            self, "Save Image As...",
            os.path.splitext(self.filename)[0], filterstr)
        if dialog[0] != "":
            try:
                self.central_widget.figure.savefig(dialog[0])
            except ValueError:
                print("Unsupported format")

    def open_fits(self, fileName):
        """Opens specified FITS file and loads it to user interface"""
        self.fits_image.set_file(fileName)
        self.filename = fileName
        self.cursor_coords.set_wcs_from_fits(
            self.fits_image.header
        )  # TODO: one up and extract and set wcs in fits_image before plot
        self.fits_image.set_wcs(self.cursor_coords.wcs)

        self.fits_image.plot()

        self.radial_profile_widget.set_data(self.fits_image.data)
        self.radial_profile_iraf_widget.set_data(self.fits_image.data)

        self.updateHeaderData()

        self.zoom_view_widget.updateFits(self.fits_image)
        self.full_view_widget.updateFits(self.fits_image)
        self.saveLastFits()

    def saveLastFits(self):
        if self.tedaCommandLine.ignoreSettings:
            return
        settings = QSettings()
        settings.beginGroup("Files")
        settings.setValue("lastFile", self.filename)
        settings.endGroup()

    def openLastFits(self):
        if (self.tedaCommandLine.openFile is None):
            if self.tedaCommandLine.ignoreSettings:
                return
            settings = QSettings()
            settings.beginGroup("Files")
            filename = settings.value("lastFile")
            settings.endGroup()
        else:
            filename = self.tedaCommandLine.openFile
        if filename:
            self.open_fits(filename)

    def readAppState(self):
        if self.tedaCommandLine.ignoreSettings:
            return
        settings = QSettings()
        settings.beginGroup("WCS")
        self.wcsSexAct.setChecked(bool(settings.value("sexagesimal", True)))
        self.wcsGridAct.setChecked(bool(settings.value("grid", False)))
        settings.endGroup()
        settings.beginGroup("paint")
        self.painterComponent.auto_center = bool(
            settings.value("auto_center", True))
        settings.endGroup()

    def writeAppState(self):
        if self.tedaCommandLine.ignoreSettings:
            return
        settings = QSettings()
        settings.beginGroup("WCS")
        settings.setValue("sexagesimal", self.wcsSexAct.isChecked())
        settings.setValue("grid", self.wcsGridAct.isChecked())
        settings.endGroup()
        settings.beginGroup("paint")
        settings.setValue("auto_center", self.painterComponent.auto_center)
        settings.endGroup()

    def undo(self):
        document = self.textEdit.document()
        document.undo()

    def insertCustomer(self, customer):
        if not customer:
            return

    def addParagraph(self, paragraph):
        if not paragraph:
            return

    def about(self):
        QMessageBox.about(
            self, "TeDa FITS Viewer", f"TeDa FITS Viewer {__version__} <br/>"
            "Authors: <ul> "
            "<li>Michał Brodniak</li>"
            "<li>Konrad Górski</li>"
            "<li>Mikołaj Kałuszyński</li>"
            "<li>Edward Lis</li>"
            "<li>Grzegorz Mroczkowski</li>"
            "</ul>"
            "Created by <a href='https://akond.com'>Akond Lab</a> for The "
            "<a href='https://araucaria.camk.edu.pl'>Araucaria Project</a><br/>"
            "Licence: MIT <br/>"
            "3rd party work used: "
            "<a href='https://material.io/resources/icons/'> Google Material Icons</a>, "
            "<a href='https://www.astropy.org'> AstroPy</a>, "
            "<a href='https://doc.qt.io/qtforpython/'> Qt5/PySide2</a>, "
            "<a href='https://www.scipy.org'> SciPy</a>, and other..."
            "<br/><br/>"
            "Visit the <a href='https://github.com/majkelx/teda'>project's GitHub  page</a> for help"
            " and the issue tracker")

    def on_console_show(self):
        console.show(ax=self.fits_image.ax,
                     window=self,
                     data=self.fits_image.data,
                     header=self.fits_image.header,
                     wcs=self.cursor_coords.wcs)

    def on_sex_toggle(self):
        print('sex toggled to :', self.wcsSexAct.isChecked())
        self.cursor_coords.wcs_sexagesimal = self.wcsSexAct.isChecked()

    def on_grid_toggle(self):
        self.fits_image.plot_grid = self.wcsGridAct.isChecked()

    def createActions(self):
        # ico1 = QPixmap('/Users/mka/projects/astro/teda/icons/png.png')
        # self.openAct = QAction(ico1, "&Open", self, shortcut=QKeySequence.Open, statusTip="Open FITS file", triggered=self.open)
        self.openAct = QAction(IconFactory.getIcon('note_add'),
                               "&Open",
                               self,
                               shortcut=QKeySequence.Open,
                               statusTip="Open FITS file",
                               triggered=self.open_dialog)
        self.saveAct = QAction(IconFactory.getIcon('save'),
                               "&Save",
                               self,
                               shortcut=QKeySequence.Save,
                               statusTip="Save FITS view",
                               triggered=self.save_dialog)
        self.quitAct = QAction("&Quit",
                               self,
                               shortcut="Ctrl+Q",
                               statusTip="Quit the application",
                               triggered=self.close)
        self.aboutAct = QAction("&About",
                                self,
                                statusTip="Show the application's About box",
                                triggered=self.about)
        self.aboutQtAct = QAction("About &Qt",
                                  self,
                                  statusTip="Show the Qt library's About box",
                                  triggered=QApplication.instance().aboutQt)

        self.qtConsoleAct = QAction('Python Console',
                                    self,
                                    statusTip="Open IPython console window",
                                    triggered=self.on_console_show)

        self.wcsSexAct = QAction(
            'Sexagesimal',
            self,
            statusTip=
            "Format WCS coordinates as sexagesimal (RA in hour angle) instead of decimal deg"
        )
        self.wcsSexAct.toggled.connect(self.on_sex_toggle)
        self.wcsSexAct.setCheckable(True)

        self.wcsGridAct = QAction(
            'Show Grid',
            self,
            statusTip="Overlay WCS coordinates grid over image",
        )
        self.wcsGridAct.setCheckable(True)
        self.wcsGridAct.toggled.connect(self.on_grid_toggle)

        self.prevHDUAct = QAction(IconFactory.getIcon('skip_previous'),
                                  'Prev HDU',
                                  self,
                                  statusTip="Previous HDU",
                                  triggered=self.prevHDU)
        self.nextHDUAct = QAction(IconFactory.getIcon('skip_next'),
                                  'Next HDU',
                                  self,
                                  statusTip="Next HDU",
                                  triggered=self.nextHDU)

        self.zoom4Act = QAction(IconFactory.getIcon("x4"),
                                'Zoom ×4',
                                self,
                                statusTip="Zoom ×4",
                                triggered=self.setZoomButton4)
        self.zoom2Act = QAction(IconFactory.getIcon("x2"),
                                'Zoom ×2',
                                self,
                                statusTip="Zoom ×2",
                                triggered=self.setZoomButton2)
        self.zoomHomeAct = QAction(IconFactory.getIcon('home'),
                                   'Home',
                                   self,
                                   statusTip="Reset zoom an position",
                                   triggered=self.setZoomButtonHome)
        self.zoom05Act = QAction(IconFactory.getIcon("1-2"),
                                 'Zoom 1/2',
                                 self,
                                 statusTip="Zoom 1/2",
                                 triggered=self.setZoomButton05)
        self.zoom025Act = QAction(IconFactory.getIcon("1-4"),
                                  'Zoom 1/4',
                                  self,
                                  statusTip="Zoom 1/4",
                                  triggered=self.setZoomButton025)

        self.panningAct = QAction(IconFactory.getIcon('panning'),
                                  'Panning',
                                  self,
                                  statusTip="Panning",
                                  triggered=self.changePanningStatus)
        self.circleAct = QAction(IconFactory.getIcon('circle'),
                                 'Add Region',
                                 self,
                                 statusTip="Add Region",
                                 triggered=self.changeAddCircleStatus)
        self.centerCircleAct = QAction(
            IconFactory.getIcon('add_circle_outline'),
            'Radial profile',
            self,
            statusTip="Radial profile with gaussoide fit [R]-key",
            triggered=self.changeAddCenterCircleStatus)
        self.autoCenterAct = QAction(
            'Auto Center',
            self,
            statusTip="Automatically center cursor on star centroid",
            triggered=self.changeAutoCenter)
        self.deleteAct = QAction(IconFactory.getIcon('delete_forever'),
                                 'Delete selected',
                                 self,
                                 statusTip="Delete selected [Del]-key",
                                 triggered=self.deleteSelected)

        self.slidersAct = QAction(
            IconFactory.getIcon('slider'),
            'Dynamic Scale Sliders',
            self,
            statusTip='Show/Hide Dynamic Scale',
            triggered=self.dynamicScaleDockWidgetTriggerActions)

        self.panningAct.setCheckable(True)
        self.panningAct.setChecked(True)
        self.circleAct.setCheckable(True)
        self.autoCenterAct.setCheckable(True)
        self.autoCenterAct.setChecked(self.painterComponent.auto_center)
        self.centerCircleAct.setCheckable(True)

    def createMenus(self):
        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenu.addAction(self.openAct)
        self.fileMenu.addAction(self.scanObject.scanAct)
        self.fileMenu.addAction(self.scanObject.stopAct)
        self.fileMenu.addAction(self.scanObject.pauseAct)
        self.fileMenu.addAction(self.scanObject.resumeAct)
        self.fileMenu.addAction(self.scanObject.autopauseAct)
        self.fileMenu.addAction(self.scanObject.disabledautopauseAct)
        self.fileMenu.addAction(self.saveAct)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.quitAct)

        self.editMenu = self.menuBar().addMenu("&Edit")
        self.editMenu.addAction(self.panningAct)
        self.editMenu.addAction(self.circleAct)
        self.editMenu.addAction(self.centerCircleAct)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.autoCenterAct)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.deleteAct)

        self.hduMenu = self.menuBar().addMenu("HDU")
        self.hduMenu.addAction(self.prevHDUAct)
        self.hduMenu.addAction(self.nextHDUAct)
        self.hduMenu.addSeparator()

        self.zoomMenu = self.menuBar().addMenu("Zoom")
        self.zoomMenu.addAction(self.zoom4Act)
        self.zoomMenu.addAction(self.zoom2Act)
        self.zoomMenu.addAction(self.zoomHomeAct)
        self.zoomMenu.addAction(self.zoom05Act)
        self.zoomMenu.addAction(self.zoom025Act)

        self.WcsMenu = self.menuBar().addMenu("W&CS")
        self.WcsMenu.addAction(self.wcsSexAct)
        self.WcsMenu.addSeparator()
        self.WcsMenu.addAction(self.wcsGridAct)

        self.viewMenu = self.menuBar().addMenu("&View")
        self.viewMenu.addAction(self.qtConsoleAct)
        self.viewMenu.addSeparator()

        self.menuBar().addSeparator()

        self.helpMenu = self.menuBar().addMenu("&Help")
        self.helpMenu.addAction(self.aboutAct)
        self.helpMenu.addAction(self.aboutQtAct)

    def createToolBars(self):
        self.fileToolBar = self.addToolBar("File Toolbar")
        self.fileToolBar.addAction(self.openAct)
        self.fileToolBar.addAction(self.saveAct)

        self.hduToolBar = self.addToolBar("HDU Toolbar")
        self.hduToolBar.addAction(self.prevHDUAct)
        self.hduToolBar.addAction(self.nextHDUAct)

        self.scanToolBar = self.addToolBar("Scan Toolbar")
        self.scanToolBar.addAction(self.scanObject.scanAct)
        self.scanToolBar.addAction(self.scanObject.stopAct)
        self.scanToolBar.addAction(self.scanObject.pauseAct)
        self.scanToolBar.addAction(self.scanObject.resumeAct)
        self.scanToolBar.addAction(self.scanObject.autopauseAct)
        self.scanToolBar.addAction(self.scanObject.disabledautopauseAct)
        self.scanToolBar.hide()

        # self.infoToolBar = self.addToolBar("Info Toolbar")
        # self.mouse_x_label = QLabel('100.1')
        # self.mouse_y_label = QLabel('100.145')
        # self.infoToolBar.addWidget(QLabel('image x:'))
        # self.infoToolBar.addWidget(self.mouse_x_label)
        # self.infoToolBar.addWidget(QLabel('y:'))
        # self.infoToolBar.addWidget(self.mouse_y_label)
        # self.infoToolBar.hide()

        self.zoomToolBar = self.addToolBar("Zoom Toolbar")
        self.zoomToolBar.addAction(self.zoom4Act)
        self.zoomToolBar.addAction(self.zoom2Act)
        self.zoomToolBar.addAction(self.zoomHomeAct)
        self.zoomToolBar.addAction(self.zoom05Act)
        self.zoomToolBar.addAction(self.zoom025Act)

        self.mouseActionToolBar = self.addToolBar("Mouse Task Toolbar")
        self.mouseActionToolBar.addAction(self.panningAct)
        self.mouseActionToolBar.addAction(self.circleAct)
        self.mouseActionToolBar.addAction(self.centerCircleAct)
        self.mouseActionToolBar.addAction(self.deleteAct)

        self.sliderToolBar = self.addToolBar("Slider Toolbar")
        self.slidersAct.setChecked(True)
        self.sliderToolBar.addAction(self.slidersAct)

        self.viewMenu.addAction(self.fileToolBar.toggleViewAction())
        self.viewMenu.addAction(self.hduToolBar.toggleViewAction())
        self.viewMenu.addAction(self.scanToolBar.toggleViewAction())
        # self.viewMenu.addAction(self.infoToolBar.toggleViewAction())
        self.viewMenu.addAction(self.zoomToolBar.toggleViewAction())
        self.viewMenu.addAction(self.mouseActionToolBar.toggleViewAction())
        self.viewMenu.addAction(self.sliderToolBar.toggleViewAction())
        self.viewMenu.addSeparator()

    def nextHDU(self):
        self.fits_image.changeHDU(True, 1)
        self.updateHeaderData()

    def prevHDU(self):
        self.fits_image.changeHDU(True, -1)
        self.updateHeaderData()

    def updateHeaderData(self):
        self.headerWidget.setHeader()
        self.prevHDUAct.setEnabled(self.fits_image._huds is not None
                                   and self.fits_image.hdu != 0)
        self.nextHDUAct.setEnabled(
            self.fits_image._huds is not None
            and self.fits_image.hdu != len(self.fits_image._huds) - 1)

    def setZoomButton4(self):
        self.setZoomButton(4, False)

    def setZoomButton2(self):
        self.setZoomButton(2, False)

    def setZoomButtonHome(self):
        self.setZoomButton(1, True)

    def setZoomButton05(self):
        self.setZoomButton(0.5, False)

    def setZoomButton025(self):
        self.setZoomButton(0.25, False)

    def setZoomButton(self, zoom: float, reset: bool):
        if self.fits_image.ax != None:
            self.fits_image.setZoom(zoom, reset)
            self.full_view_widget.updateMiniatureShape(self.fits_image.viewX,
                                                       self.fits_image.viewY,
                                                       self.fits_image.viewW,
                                                       self.fits_image.viewH)

    def changePanningStatus(self):
        if self.panningAct.isChecked():
            self.toogleOffRegionButtons()
            self.panningAct.toggle()
            self.painterComponent.stopPainting(self.central_widget)
            self.painterComponent.startMovingEvents(self.central_widget)
        else:
            self.painterComponent.stopPainting(self.central_widget)
            self.painterComponent.stopMovingEvents(self.central_widget)

    def changeAddCircleStatus(self):
        if self.circleAct.isChecked():
            self.toogleOffRegionButtons()
            self.circleAct.toggle()
            self.painterComponent.startPainting(self.central_widget, "circle")
        else:
            self.painterComponent.stopPainting(self.central_widget)
            self.painterComponent.startMovingEvents(self.central_widget)
            self.panningAct.toggle()

    def changeAddCenterCircleStatus(self):
        if self.centerCircleAct.isChecked():
            self.toogleOffRegionButtons()
            self.centerCircleAct.toggle()
            self.painterComponent.startPainting(self.central_widget,
                                                "circleCenter")
        else:
            self.painterComponent.stopPainting(self.central_widget)
            self.painterComponent.startMovingEvents(self.central_widget)
            self.panningAct.toggle()

    def changeAutoCenter(self):
        self.painterComponent.auto_center = self.autoCenterAct.isChecked()

    def deleteSelected(self):
        self.painterComponent.deleteSelectedShapes(
            self.central_widget.figure.axes[0])

    def toogleOffRegionButtons(self):
        if self.panningAct.isChecked():
            self.panningAct.toggle()
        if self.circleAct.isChecked():
            self.circleAct.toggle()
        if self.centerCircleAct.isChecked():
            self.centerCircleAct.toggle()
        self.painterComponent.stopPainting(self.central_widget)

    def createStatusBar(self):
        self.statusBar().showMessage("Ready")

    def createDockWindows(self):
        # Scale
        self.dynamic_scale_dock = QDockWidget("Dynamic Scale", self)
        self.dynamic_scale_dock.setObjectName("SCALE")
        self.dynamic_scale_dock.setAllowedAreas(Qt.LeftDockWidgetArea
                                                | Qt.RightDockWidgetArea
                                                | Qt.TopDockWidgetArea)
        self.scaleWidget = ScaleWidget(self,
                                       scales_model=self.scales_model,
                                       cmap_model=self.cmaps)
        self.dynamic_scale_dock.setWidget(self.scaleWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, self.dynamic_scale_dock)
        self.viewMenu.addAction(self.dynamic_scale_dock.toggleViewAction())
        self.dynamic_scale_dock.setFloating(True)
        self.dynamic_scale_dock.hide()

        #radial profiles
        dock = QDockWidget("Radial Profile Fit", self)
        dock.setObjectName("RADIAL_PROFILE_IRAF")
        dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea
                             | Qt.TopDockWidgetArea)
        self.radial_profile_iraf_widget = IRAFRadialProfileWidget(
            self.fits_image.data)
        dock.setWidget(self.radial_profile_iraf_widget)
        self.addDockWidget(Qt.RightDockWidgetArea, dock)
        self.viewMenu.addAction(dock.toggleViewAction())
        self.dockRadialFit = dock

        dock = QDockWidget("Radial Profile Curve", self)
        dock.setObjectName("RADIAL_PROFILE")
        dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea
                             | Qt.TopDockWidgetArea)
        self.radial_profile_widget = RadialProfileWidget(self.fits_image.data)
        dock.setWidget(self.radial_profile_widget)
        self.addDockWidget(Qt.RightDockWidgetArea, dock)
        self.viewMenu.addAction(dock.toggleViewAction())
        dock.hide()

        #info panel
        dock = QDockWidget("Info", self)
        dock.setObjectName("INFO_PANEL")
        dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea
                             | Qt.TopDockWidgetArea)
        self.info_widget = InfoWidget(self)
        dock.setWidget(self.info_widget)
        self.addDockWidget(Qt.TopDockWidgetArea, dock)
        self.viewMenu.addAction(dock.toggleViewAction())

        # FITS headers
        dock = QDockWidget("FITS header", self)
        dock.setObjectName("FTIS_DATA")
        dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea
                             | Qt.TopDockWidgetArea)
        self.addDockWidget(Qt.TopDockWidgetArea, dock)
        self.viewMenu.addAction(dock.toggleViewAction())
        self.headerWidget = HeaderTableWidget(self)
        self.headerWidget.setColumnCount(2)
        self.headerWidget.setHorizontalHeaderItem(0, QTableWidgetItem("KEY"))
        self.headerWidget.setHorizontalHeaderItem(1, QTableWidgetItem("VALUE"))
        self.headerWidget.horizontalHeader().setStretchLastSection(1)
        self.headerWidget.setEditTriggers(
            QtWidgets.QTableWidget.NoEditTriggers)
        self.headerWidget.clearFocus()
        dock.setWidget(self.headerWidget)

        # full
        dock = QDockWidget("Full view", self)
        dock.setObjectName("FULL_VIEW")
        dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea
                             | Qt.TopDockWidgetArea)
        self.full_view_widget = FullViewWidget(self.fits_image)
        self.full_view_widget.fits_image.set_scale_model(self.scales_model)
        self.full_view_widget.fits_image.set_cmap_model(self.cmaps)
        dock.setWidget(self.full_view_widget)
        self.addDockWidget(Qt.TopDockWidgetArea, dock)
        self.viewMenu.addAction(dock.toggleViewAction())
        # zoom
        dock = QDockWidget("Zoom view", self)
        dock.setObjectName("ZOOM_VIEW")
        dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea
                             | Qt.TopDockWidgetArea)
        self.zoom_view_widget = ZoomViewWidget(self.fits_image)
        self.zoom_view_widget.fits_image.set_scale_model(self.scales_model)
        self.zoom_view_widget.fits_image.set_cmap_model(self.cmaps)
        dock.setWidget(self.zoom_view_widget)
        self.addDockWidget(Qt.TopDockWidgetArea, dock)
        self.viewMenu.addAction(dock.toggleViewAction())

        # fileSelector
        dock = QDockWidget("Directory view", self)
        dock.setObjectName("DIRECTORY_VIEW")
        dock.setAllowedAreas(Qt.LeftDockWidgetArea)
        self.file_widget = FileSystemWidget(self)
        dock.setWidget(self.file_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, dock)
        self.viewMenu.addAction(dock.toggleViewAction())

        self.viewMenu.addSeparator()

    # def changeColor(self, color):
    #     self.cmaps.set_active_color_map(color)

    # def on_colormap_change(self, change):
    #     self.fits_image.cmap = self.cmaps.get_active_color_map()
    #     self.fits_image.plot()
    #     self.updateFitsInWidgets()

    def onAutoCenterChange(self, change):
        self.autoCenterAct.setChecked(change.new)

    def dynamicScaleDockWidgetTriggerActions(self):
        if self.dynamic_scale_dock.isHidden():
            self.dynamic_scale_dock.show()
        else:
            self.dynamic_scale_dock.hide()

    def onCenterCircleChange(self, change):
        self.radial_profile_widget.set_centroid(
            self.painterComponent.ccenter_x, self.painterComponent.ccenter_y)
        self.radial_profile_iraf_widget.set_centroid(
            self.painterComponent.ccenter_x, self.painterComponent.ccenter_y)

    def onCenterCircleRadiusChange(self, change):
        self.radial_profile_widget.set_radius(self.painterComponent.cradius)
        self.radial_profile_iraf_widget.set_radius(
            self.painterComponent.cradius)

    def onRectangleInWidgetMove(self, change):
        changed = False
        if change.new is not None:
            changed = True
        if change.name == 'viewX':
            self.fullWidgetXcord = change.new
        elif change.name == 'viewY':
            self.fullWidgetYcord = change.new
        if changed:
            self.fits_image.moveToXYcords(self.fullWidgetXcord,
                                          self.fullWidgetYcord)

    def movingCentralWidget(self, change):
        changed = False
        if change.new is not None:
            changed = True
        if change.name == 'movingViewX':
            self.centralWidgetcordX = change.new
        elif change.name == 'movingViewY':
            self.centralWidgetcordY = change.new
        if changed:
            self.full_view_widget.updateMiniatureShapeXYonly(
                self.centralWidgetcordX, self.centralWidgetcordY)

    def onMouseMoveOnImage(self, change):
        display = ''
        val = 0
        if change.new is not None:
            display = f'{change.new:f}'
            val = change.new
        if change.name == 'mouse_xdata':
            # self.mouse_x_label.setText(display)
            self.current_x_coord = val
            self.cursor_coords.set_img_x(change.new)
        elif change.name == 'mouse_ydata':
            # self.mouse_y_label.setText(display)
            self.current_y_coord = val
            self.cursor_coords.set_img_y(change.new)
        if display != '':
            self.zoom_view_widget.setXYofZoom(self.fits_image,
                                              self.current_x_coord,
                                              self.current_y_coord,
                                              self.fits_image.zoom)
            if not self.hasFocus():
                self.setFocus()
            if self.scanObject.activeScan and self.scanObject.enableAutopause:  #reser autopause
                if not self.scanObject.obserwableValue.autopauseFlag:
                    self.scanObject.obserwableValue.autopauseFlag = True

    def activeLinearAdjustmentByMouseMovement(self):
        self.central_widget.mpl_connect('motion_notify_event',
                                        self.mouseMoveEventOnCanvas)
        self.central_widget.mpl_connect('button_press_event',
                                        self.canvasMousePressEvent)
        self.central_widget.mpl_connect('button_release_event',
                                        self.canvasMousePressEvent)

    def onMouseZoomOnImage(self, change):
        changed = False
        if change.new is not None:
            changed = True
        if changed:
            self.full_view_widget.updateMiniatureShape(self.fits_image.viewX,
                                                       self.fits_image.viewY,
                                                       self.fits_image.viewW,
                                                       self.fits_image.viewH)

    def readWindowSettings(self):
        if self.tedaCommandLine.ignoreSettings:
            return
        settings = QSettings()
        settings.beginGroup("MainWindow")
        size, pos = settings.value("size"), settings.value("pos")
        settings.endGroup()
        if size is not None and pos is not None:
            print('settings: resize to {} and move to {}', size, pos)
            self.move(pos)
            # self.resize(size)
            print('Size reported ', self.size())
            print('Size set ', size)
            self.resize(size)
            print('Size reported ', self.size())
        else:
            self.resize(800, 600)

        geometry = settings.value("geometry")
        if geometry is not None:
            self.restoreGeometry(geometry)
            self.restoreState(settings.value("windowState"))

        self.headerWidget.readSettings(settings)
        self.file_widget.readSettings(settings)

    def writeWindowSettings(self):
        if self.tedaCommandLine.ignoreSettings:
            return
        settings = QSettings()
        settings.beginGroup("MainWindow")
        settings.setValue("size", self.size())
        settings.setValue("pos", self.pos())
        settings.endGroup()

        settings.setValue('geometry', self.saveGeometry())
        settings.setValue('windowState', self.saveState())

        self.headerWidget.writeSettings(settings)
        self.file_widget.writeSettings(settings)
Ejemplo n.º 5
0
class MVCPlaybackControlGUI(PlaybackControlConsole):
    """
    GUI implementation of MVCPlaybackControlBase
    """
    nameFiltersChanged = Signal("QStringList")

    def __init__(self, config):
        assertMainThread()
        super().__init__(config)

        # state
        self.preventSeek = False
        self.beginTime = None
        self.timeRatio = 1.0

        # gui
        srv = Services.getService("MainWindow")
        config.configLoaded.connect(self.restoreState)
        config.configAboutToSave.connect(self.saveState)
        self.config = config
        playbackMenu = srv.menuBar().addMenu("&Playback")

        style = QApplication.style()
        self.actStart = QAction(
            QIcon.fromTheme("media-playback-start",
                            style.standardIcon(QStyle.SP_MediaPlay)),
            "Start Playback", self)
        self.actPause = QAction(
            QIcon.fromTheme("media-playback-pause",
                            style.standardIcon(QStyle.SP_MediaPause)),
            "Pause Playback", self)
        self.actPause.setEnabled(False)
        self.actStepFwd = QAction(
            QIcon.fromTheme("media-seek-forward",
                            style.standardIcon(QStyle.SP_MediaSeekForward)),
            "Step Forward", self)
        self.actStepBwd = QAction(
            QIcon.fromTheme("media-seek-backward",
                            style.standardIcon(QStyle.SP_MediaSeekBackward)),
            "Step Backward", self)
        self.actSeekEnd = QAction(
            QIcon.fromTheme("media-skip-forward",
                            style.standardIcon(QStyle.SP_MediaSkipForward)),
            "Seek End", self)
        self.actSeekBegin = QAction(
            QIcon.fromTheme("media-skip-backward",
                            style.standardIcon(QStyle.SP_MediaSkipBackward)),
            "Seek Begin", self)
        self.actSetTimeFactor = {
            r: QAction("x 1/%d" %
                       (1 / r), self) if r < 1 else QAction("x %d" % r, self)
            for r in (1 / 8, 1 / 4, 1 / 2, 1, 2, 4, 8)
        }

        # pylint: disable=unnecessary-lambda
        # let's stay on the safe side and do not use emit as a slot...
        self.actStart.triggered.connect(self.startPlayback)
        self.actPause.triggered.connect(self.pausePlayback)
        self.actStepFwd.triggered.connect(
            lambda: self.stepForward(self.selectedStream()))
        self.actStepBwd.triggered.connect(
            lambda: self.stepBackward(self.selectedStream()))
        self.actSeekEnd.triggered.connect(self.seekEnd)
        self.actSeekBegin.triggered.connect(self.seekBeginning)

        # pylint: enable=unnecessary-lambda

        def setTimeFactor(newFactor):
            logger.debug("new time factor %f", newFactor)
            self.setTimeFactor(newFactor)

        for r in self.actSetTimeFactor:
            logger.debug("adding action for time factor %f", r)
            self.actSetTimeFactor[r].triggered.connect(
                functools.partial(setTimeFactor, r))

        self.dockWidget = srv.newDockWidget("PlaybackControl", None,
                                            Qt.LeftDockWidgetArea)
        self.dockWidgetContents = QWidget(self.dockWidget)
        self.dockWidget.setWidget(self.dockWidgetContents)
        toolLayout = QBoxLayout(QBoxLayout.TopToBottom,
                                self.dockWidgetContents)
        toolLayout.setContentsMargins(0, 0, 0, 0)
        toolBar = QToolBar()
        toolLayout.addWidget(toolBar)
        toolBar.addAction(self.actSeekBegin)
        toolBar.addAction(self.actStepBwd)
        toolBar.addAction(self.actStart)
        toolBar.addAction(self.actPause)
        toolBar.addAction(self.actStepFwd)
        toolBar.addAction(self.actSeekEnd)
        playbackMenu.addAction(self.actSeekBegin)
        playbackMenu.addAction(self.actStepBwd)
        playbackMenu.addAction(self.actStart)
        playbackMenu.addAction(self.actPause)
        playbackMenu.addAction(self.actStepFwd)
        playbackMenu.addAction(self.actSeekEnd)
        playbackMenu.addSeparator()
        for r in self.actSetTimeFactor:
            playbackMenu.addAction(self.actSetTimeFactor[r])
        self.timeRatioLabel = QLabel("x 1")
        self.timeRatioLabel.addActions(list(self.actSetTimeFactor.values()))
        self.timeRatioLabel.setContextMenuPolicy(Qt.ActionsContextMenu)
        toolBar.addSeparator()
        toolBar.addWidget(self.timeRatioLabel)
        contentsLayout = QGridLayout()
        toolLayout.addLayout(contentsLayout, 10)
        # now we add a position view
        self.positionSlider = QSlider(Qt.Horizontal, self.dockWidgetContents)
        self.beginLabel = QLabel(parent=self.dockWidgetContents)
        self.beginLabel.setAlignment(Qt.AlignLeft | Qt.AlignCenter)
        self.currentLabel = QLabel(parent=self.dockWidgetContents)
        self.currentLabel.setAlignment(Qt.AlignHCenter | Qt.AlignCenter)
        self.endLabel = QLabel(parent=self.dockWidgetContents)
        self.endLabel.setAlignment(Qt.AlignRight | Qt.AlignCenter)
        contentsLayout.addWidget(self.beginLabel, 0, 0, alignment=Qt.AlignLeft)
        contentsLayout.addWidget(self.currentLabel,
                                 0,
                                 1,
                                 alignment=Qt.AlignHCenter)
        contentsLayout.addWidget(self.endLabel, 0, 2, alignment=Qt.AlignRight)
        contentsLayout.addWidget(self.positionSlider, 1, 0, 1, 3)
        self.positionSlider.setTracking(False)
        self.positionSlider.valueChanged.connect(self.onSliderValueChanged,
                                                 Qt.DirectConnection)
        self.positionSlider.sliderMoved.connect(self.displayPosition)

        # file browser
        self.browser = BrowserWidget(self.dockWidget)
        self.nameFiltersChanged.connect(self._onNameFiltersChanged,
                                        Qt.QueuedConnection)
        contentsLayout.addWidget(self.browser, 3, 0, 1, 3)
        contentsLayout.setRowStretch(3, 100)
        self.browser.activated.connect(self.browserActivated)

        self.actShowAllFiles = QAction("Show all files")
        self.actShowAllFiles.setCheckable(True)
        self.actShowAllFiles.setChecked(False)
        self.actShowAllFiles.toggled.connect(self._onShowAllFiles)
        playbackMenu.addSeparator()
        playbackMenu.addAction(self.actShowAllFiles)

        self.actGroupStream = QActionGroup(self)
        self.actGroupStream.setExclusionPolicy(
            QActionGroup.ExclusionPolicy.ExclusiveOptional)
        playbackMenu.addSeparator()
        self.actGroupStreamMenu = playbackMenu.addMenu("Step Stream")
        self._selectedStream = None

        self.recentSeqs = [QAction() for i in range(10)]
        playbackMenu.addSeparator()
        recentMenu = playbackMenu.addMenu("Recent")
        for a in self.recentSeqs:
            a.setVisible(False)
            a.triggered.connect(self.openRecent)
            recentMenu.addAction(a)

        self._supportedFeaturesChanged(set(), set())

    def __del__(self):
        logger.internal("deleting playback control")

    def _onNameFiltersChanged(self, nameFilt):
        self.browser.setFilter(nameFilt)
        if isinstance(nameFilt, str):
            nameFilt = [nameFilt]
        for a in self.recentSeqs:
            if a.isVisible():
                m = QDir.match(nameFilt, Path(a.data()).name)
                a.setEnabled(m)

    def _onShowAllFiles(self, enabled):
        self.fileSystemModel.setNameFilterDisables(enabled)

    def _supportedFeaturesChanged(self, featureset, nameFilters):
        """
        overwritten from MVCPlaybackControlBase. This function is called
        from multiple threads, but not at the same time.

        :param featureset: the current featureset
        :return:
        """
        assertMainThread()
        self.featureset = featureset
        self.actStepFwd.setEnabled("stepForward" in featureset)
        self.actStepBwd.setEnabled("stepBackward" in featureset)
        self.actSeekBegin.setEnabled("seekBeginning" in featureset)
        self.actSeekEnd.setEnabled("seekEnd" in featureset)
        self.positionSlider.setEnabled("seekTime" in featureset)
        self.browser.setEnabled("setSequence" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        for f in self.actSetTimeFactor:
            self.actSetTimeFactor[f].setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        self.timeRatioLabel.setEnabled("setTimeFactor" in featureset)
        if "startPlayback" not in featureset:
            self.actStart.setEnabled(False)
        if "pausePlayback" not in featureset:
            self.actPause.setEnabled(False)
        logger.debug("current feature set: %s", featureset)
        logger.debug("Setting name filters of browser: %s", list(nameFilters))
        self.nameFiltersChanged.emit(list(nameFilters))
        super()._supportedFeaturesChanged(featureset, nameFilters)

    def scrollToCurrent(self):
        """
        Scrolls to the current item in the browser

        :return:
        """
        assertMainThread()
        c = self.browser.current()
        if c is not None:
            self.browser.scrollTo(c)

    def _sequenceOpened(self, filename, begin, end, streams):
        """
        Notifies about an opened sequence.

        :param filename: the filename which has been opened
        :param begin: timestamp of sequence's first sample
        :param end: timestamp of sequence's last sample
        :param streams: list of streams in the sequence
        :return: None
        """
        assertMainThread()
        self.beginTime = begin
        self.preventSeek = True
        self.positionSlider.setRange(0, (end - begin) // 1000000)
        self.preventSeek = False
        self.beginLabel.setText(self._timeToString(0))
        self.endLabel.setText(self._timeToString((end - begin) // 1000000))
        self._currentTimestampChanged(begin)
        try:
            self.browser.blockSignals(True)
            self.browser.setActive(filename)
            self.browser.scrollTo(filename)
        finally:
            self.browser.blockSignals(False)
        self._selectedStream = None
        for a in self.actGroupStream.actions():
            logger.debug("Remove stream group action: %s", a.data())
            self.actGroupStream.removeAction(a)
        for stream in streams:
            act = QAction(stream, self.actGroupStream)
            act.triggered.connect(
                lambda cstream=stream: self.setSelectedStream(cstream))
            act.setCheckable(True)
            act.setChecked(False)
            logger.debug("Add stream group action: %s", act.data())
            self.actGroupStreamMenu.addAction(act)
        QTimer.singleShot(250, self.scrollToCurrent)
        super()._sequenceOpened(filename, begin, end, streams)

    @staticmethod
    def _splitTime(milliseconds):
        hours = milliseconds // (60 * 60 * 1000)
        milliseconds -= hours * (60 * 60 * 1000)
        minutes = milliseconds // (60 * 1000)
        milliseconds -= minutes * (60 * 1000)
        seconds = milliseconds // 1000
        milliseconds -= seconds * 1000
        return hours, minutes, seconds, milliseconds

    @staticmethod
    def _timeToString(milliseconds):
        return "%02d:%02d:%02d.%03d" % (
            MVCPlaybackControlGUI._splitTime(milliseconds))

    def _currentTimestampChanged(self, currentTime):
        """
        Notifies about a changed timestamp

        :param currentTime: the new current timestamp
        :return: None
        """
        assertMainThread()
        if self.beginTime is None:
            self.currentLabel.setText("")
        else:
            sliderVal = (currentTime - self.beginTime
                         ) // 1000000  # nanoseconds to milliseconds
            self.preventSeek = True
            self.positionSlider.setValue(sliderVal)
            self.preventSeek = False
            self.positionSlider.blockSignals(False)
            self.currentLabel.setEnabled(True)
            self.currentLabel.setText(self._timeToString(sliderVal))
        super()._currentTimestampChanged(currentTime)

    def onSliderValueChanged(self, value):
        """
        Slot called whenever the slider value is changed.

        :param value: the new slider value
        :return:
        """
        assertMainThread()
        if self.beginTime is None or self.preventSeek:
            return
        if self.actStart.isEnabled():
            ts = self.beginTime + value * 1000000
            self.seekTime(ts)
        else:
            logger.warning("Can't seek while playing.")

    def displayPosition(self, value):
        """
        Slot called when the slider is moved. Displays the position without actually seeking to it.

        :param value: the new slider value.
        :return:
        """
        assertMainThread()
        if self.beginTime is None:
            return
        if self.positionSlider.isSliderDown():
            ts = self.beginTime // 1000000 + value
            self.currentLabel.setEnabled(False)
            self.currentLabel.setText(self._timeToString(ts))

    def _playbackStarted(self):
        """
        Notifies about starting playback

        :return: None
        """
        assertMainThread()
        self.actStart.setEnabled(False)
        if "pausePlayback" in self.featureset:
            self.actPause.setEnabled(True)
        super()._playbackStarted()

    def _playbackPaused(self):
        """
        Notifies about pause playback

        :return: None
        """
        assertMainThread()
        logger.debug("playbackPaused received")
        if "startPlayback" in self.featureset:
            self.actStart.setEnabled(True)
        self.actPause.setEnabled(False)
        super()._playbackPaused()

    def openRecent(self):
        """
        Called when the user clicks on a recent sequence.

        :return:
        """
        assertMainThread()
        action = self.sender()
        self.browser.setActive(action.data())

    def browserActivated(self, filename):
        """
        Called when the user activated a file.

        :param filename: the new filename
        :return:
        """
        assertMainThread()
        if filename is not None and Path(filename).is_file():
            foundIdx = None
            for i, a in enumerate(self.recentSeqs):
                if a.data() == filename:
                    foundIdx = i
            if foundIdx is None:
                foundIdx = len(self.recentSeqs) - 1
            for i in range(foundIdx, 0, -1):
                self.recentSeqs[i].setText(self.recentSeqs[i - 1].text())
                self.recentSeqs[i].setData(self.recentSeqs[i - 1].data())
                logger.debug("%d data: %s", i, self.recentSeqs[i - 1].data())
                self.recentSeqs[i].setVisible(
                    self.recentSeqs[i - 1].data() is not None)
            self.recentSeqs[0].setText(self.compressFileName(filename))
            self.recentSeqs[0].setData(filename)
            self.recentSeqs[0].setVisible(True)
            self.setSequence(filename)

    def _timeRatioChanged(self, newRatio):
        """
        Notifies about a changed playback time ratio,

        :param newRatio the new playback ratio as a float
        :return: None
        """
        assertMainThread()
        self.timeRatio = newRatio
        logger.debug("new timeRatio: %f", newRatio)
        for r in [1 / 8, 1 / 4, 1 / 2, 1, 2, 4, 8]:
            if abs(newRatio / r - 1) < 0.01:
                self.timeRatioLabel.setText(("x 1/%d" %
                                             (1 / r)) if r < 1 else ("x %d" %
                                                                     r))
                return
        self.timeRatioLabel.setText("%.2f" % newRatio)
        super()._timeRatioChanged(newRatio)

    def selectedStream(self):
        """
        Returns the user-selected stream (for forward/backward stepping)

        :return:
        """
        return self._selectedStream

    def setSelectedStream(self, stream):
        """
        Sets the user-selected stream (for forward/backward stepping)

        :param stream the stream name.
        :return:
        """
        self._selectedStream = stream

    def _defineProperties(self):
        propertyCollection = self.config.guiState()
        propertyCollection.defineProperty("PlaybackControl_showAllFiles", 0,
                                          "show all files setting")
        propertyCollection.defineProperty("PlaybackControl_folder", "",
                                          "current folder name")
        propertyCollection.defineProperty("PlaybackControl_recent", "",
                                          "recent opened sequences")

    def saveState(self):
        """
        Saves the state of the playback control

        :return:
        """
        assertMainThread()
        self._defineProperties()
        propertyCollection = self.config.guiState()
        showAllFiles = self.actShowAllFiles.isChecked()
        folder = self.browser.folder()
        logger.debug("Storing current folder: %s", folder)
        try:
            propertyCollection.setProperty("PlaybackControl_showAllFiles",
                                           int(showAllFiles))
            propertyCollection.setProperty("PlaybackControl_folder", folder)
            recentFiles = [
                a.data() for a in self.recentSeqs if a.data() is not None
            ]
            propertyCollection.setProperty("PlaybackControl_recent",
                                           "|".join(recentFiles))
        except PropertyCollectionPropertyNotFound:
            pass

    def restoreState(self):
        """
        Restores the state of the playback control from the given property collection

        :param propertyCollection: a PropertyCollection instance
        :return:
        """
        assertMainThread()
        self._defineProperties()
        propertyCollection = self.config.guiState()
        showAllFiles = propertyCollection.getProperty(
            "PlaybackControl_showAllFiles")
        self.actShowAllFiles.setChecked(bool(showAllFiles))
        folder = propertyCollection.getProperty("PlaybackControl_folder")
        if Path(folder).is_dir():
            logger.debug("Setting current file: %s", folder)
            self.browser.setFolder(folder)
        recentFiles = propertyCollection.getProperty("PlaybackControl_recent")
        idx = 0
        for f in recentFiles.split("|"):
            if f != "" and Path(f).is_file():
                self.recentSeqs[idx].setData(f)
                self.recentSeqs[idx].setText(self.compressFileName(f))
                self.recentSeqs[idx].setVisible(True)
                self.recentSeqs[idx].setEnabled(False)
                idx += 1
                if idx >= len(self.recentSeqs):
                    break
        for a in self.recentSeqs[idx:]:
            a.setData(None)
            a.setText("")
            a.setVisible(False)

    @staticmethod
    def compressFileName(filename):
        """
        Compresses long path names with an ellipsis (...)

        :param filename: the original path name as a Path or string instance
        :return: the compressed path name as a string instance
        """
        p = Path(filename)
        parts = tuple(p.parts)
        if len(parts) >= 6:
            p = Path(*parts[:2]) / "..." / Path(*parts[-2:])
        return str(p)
Ejemplo n.º 6
0
class SystemTray(QSystemTrayIcon):
    def __init__(self, parent):
        super().__init__(QIcon("resources/translate-icon.svg"), )
        self.parent = parent
        self.show()

        self.clear_action = QAction("Clear", self)

        self.enable_action = QAction("Enable clipboard translation", self)
        self.enable_action.setCheckable(True)

        self.show_panel_action = QAction("Show panel", self)
        self.show_panel_action.setCheckable(True)

        self.on_top_action = QAction("Always on top", self)
        self.on_top_action.setCheckable(True)

        self.not_fix_action = QAction("Move to avoid mouse", self)
        self.not_fix_action.setCheckable(True)

        self.follow_cursor_action = QAction("Move to follow mouse", self)
        self.follow_cursor_action.setCheckable(True)

        close_action = QAction("Exit", self)

        QObject.connect(self.clear_action, SIGNAL("triggered()"),
                        self.parent.clear_button, SLOT("click()"))

        QObject.connect(self.on_top_action, SIGNAL("triggered(bool)"),
                        self.parent, SLOT("set_on_top(bool)"))

        QObject.connect(self.show_panel_action, SIGNAL("triggered(bool)"),
                        self.parent, SLOT("show_interface(bool)"))

        QObject.connect(self.not_fix_action, SIGNAL("triggered(bool)"),
                        self.parent, SLOT("set_not_fix(bool)"))

        QObject.connect(self.enable_action, SIGNAL("triggered(bool)"),
                        self.parent, SLOT("set_enable(bool)"))

        QObject.connect(self.follow_cursor_action, SIGNAL("triggered(bool)"),
                        self.parent, SLOT("set_follow_cursor(bool)"))

        QObject.connect(close_action, SIGNAL("triggered()"), self.parent,
                        SLOT("close()"))

        menu = QMenu()
        menu.addActions([
            self.clear_action, self.enable_action, self.show_panel_action,
            self.on_top_action, self.not_fix_action, self.show_panel_action,
            self.follow_cursor_action, close_action
        ])
        self.setContextMenu(menu)

        QObject.connect(menu, SIGNAL("aboutToShow()"), self, SLOT("refresh()"))

    def refresh(self):
        self.enable_action.setChecked(self.parent.is_enable)
        self.on_top_action.setChecked(self.parent.is_on_top)
        self.not_fix_action.setChecked(self.parent.is_not_fixed)
        self.show_panel_action.setChecked(self.parent.is_show_panel)
Ejemplo n.º 7
0
class mainWindow(QObject):

    signalRun = Signal(SpiderThread)
    signalRunApi = Signal(apiTester)
    def __init__(self):
        QObject.__init__(self)  # must init parent QObject,if you want to use signal
        self.widget = QWidget()
        self.ipLabel = QLabel(self.widget)
        self.thread = QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.thread)
        self.man = SpiderThread()
        self.api = apiTester()
        # 1 2:loop 3: time
        self.testStatus = [False,1,0,"ip","mac"]

        # advance config
        self.findCoreStop = True
        self.cleanCacheSet = False
        self.useApiTest = False
        self.showTestProgress = True
        self.saveTestLog = False
        self.saveLogPath = ""
        self.chromePath =  ""
        self.showChrome = False
        self.coreDumpPath = ""

        # ui form
        self.passwordLabel = QLabel(self.widget)

        self.ipLineEdit = QLineEdit(self.widget)
        self.passwordLineEdit = QLineEdit(self.widget)

        self.startBtn = QPushButton(self.widget)
        self.stopBtn = QPushButton(self.widget)

        self.messageBox = QTextEdit(self.widget)
        self.messageBox.setReadOnly(True)

        self.userLabel = QLabel(self.widget)
        self.userLineEdit = QLineEdit(self.widget)

        self.intervalLabel = QLabel(self.widget)
        self.intervalSpinBox = QSpinBox(self.widget)

        self.loopLabel = QLabel(self.widget)
        self.loopSpinBox = QSpinBox(self.widget)

        self.intervalSpinBox.setRange(0,9999)
        self.loopSpinBox.setRange(1,9999)

        self.radioReboot = QRadioButton(self.widget)
        self.radioProvision = QRadioButton(self.widget)
        self.radioFactory = QRadioButton(self.widget)

        # self.apiCheckBox = QCheckBox(self.widget)

        self.menu = QMenu()
        self.gxpAction = QAction("Classic UI")
        self.grp2602Action = QAction("Ant Design UI")
        self.gxpAction.setCheckable(True)
        self.grp2602Action.setCheckable(True)
        self.menu.addAction(self.gxpAction)
        self.menu.addAction(self.grp2602Action)
        self.webLabel = QLabel(self.widget)
        self.webBtn = QPushButton(self.widget)
        self.webBtn.setMenu(self.menu)
        self.clearBtn = QPushButton(self.widget)
        self.messageList = deque()
        self.timer = QTimer()


        self.advanceBtn = QPushButton(self.widget)
        self.infoLabel = QLabel(self.widget)

        # provision widget
        self.provWidget = QWidget(self.widget)
        self.ver1Label = QLabel(self.provWidget)
        self.ver2Label = QLabel(self.provWidget)
        self.ver3Label = QLabel(self.provWidget)
        self.ver1LineEdit = QLineEdit(self.provWidget)
        self.ver2LineEdit = QLineEdit(self.provWidget)
        self.ver3LineEdit = QLineEdit(self.provWidget)

        self.dir1Label = QLabel(self.provWidget)
        self.dir2Label = QLabel(self.provWidget)
        self.dir3Label = QLabel(self.provWidget)
        self.dir1LineEdit = QLineEdit(self.provWidget)
        self.dir2LineEdit = QLineEdit(self.provWidget)
        self.dir3LineEdit = QLineEdit(self.provWidget)

        self.radioHttp = QRadioButton(self.provWidget)
        self.radioHttps = QRadioButton(self.provWidget)
        self.radioTftp = QRadioButton(self.provWidget)
        self.radioFtp = QRadioButton(self.provWidget)
        self.radioFtps = QRadioButton(self.provWidget)
        self.radioWindow = QRadioButton(self.provWidget)

        # advance widget
        self.advanceWidget = QWidget()
        self.checkCoreBox = QCheckBox(self.advanceWidget)
        self.cleanCache = QCheckBox(self.advanceWidget)
        self.checkSaveLogBox = QCheckBox(self.advanceWidget)
        self.selectDirBtn = QPushButton(self.advanceWidget)
        self.saveDirLabel = QLabel(self.advanceWidget)
        self.saveDirLabel.setStyleSheet("background:white")
        self.checkProgressBox = QCheckBox(self.advanceWidget)
        self.advanceOkBtn = QPushButton(self.advanceWidget)
        self.selectChromeBtn = QPushButton(self.advanceWidget)
        self.chromePathLabel = QLabel(self.advanceWidget)
        self.chromePathLabel.setStyleSheet("background:white")
        self.checkShowChromeBox = QCheckBox(self.advanceWidget)
        self.chromeLabel = QLabel(self.advanceWidget)
        self.pcapLabel = QLabel(self.advanceWidget)
        self.apiCheckBox = QCheckBox(self.advanceWidget)
        self.corePathLabel = QLabel(self.advanceWidget)
        self.corePathLabel.setStyleSheet("background:white")
        self.corePathBtn = QPushButton(self.advanceWidget)

        self.interfaceMenu = QComboBox(self.advanceWidget)
        self.interfaceMenu.addItem('Default')

        self.aiOptionBox= QCheckBox(self.advanceWidget)

        a = IFACES
        print(a)
        for i in a.keys():
            print(a[i].description)
            self.interfaceMenu.addItem(a[i].description)

        # connect singal and slot
        self.startBtn.clicked.connect(self.clickedStarBtn)
        self.radioProvision.clicked.connect(self.clickedProvision)
        self.radioReboot.clicked.connect(self.clickedOthers)
        self.radioFactory.clicked.connect(self.clickedOthers)
        self.stopBtn.clicked.connect(self.clickedStopBtn)
        self.grp2602Action.triggered.connect(self.clickedGrp2602)
        self.gxpAction.triggered.connect(self.clickedGxpType)
        self.timer.timeout.connect(self.updateMessage)
        self.apiCheckBox.stateChanged.connect(self.apiTestBoxCheck)
        self.clearBtn.clicked.connect(self.clickedClearBtn)

        self.advanceBtn.clicked.connect(self.clickedAdvanceBtn)
        self.advanceOkBtn.clicked.connect(self.clickedAdvanceOkBtn)
        self.checkSaveLogBox.stateChanged.connect(self.saveLogBoxCheck)
        self.selectChromeBtn.clicked.connect(self.clickedSelectChromeBtn)
        self.selectDirBtn.clicked.connect(self.clickedSelectDirBtn)
        self.corePathBtn.clicked.connect(self.clickedCorePathBtn)

        self.worker.signalJobEnd.connect(self.slotTestStoped)
        self.worker.apiTestFinished.connect(self.slotTestStoped)
        self.signalRun.connect(self.worker.dowork)
        self.signalRunApi.connect(self.worker.doworkApi)

        # self.man.signalUpdateMessage.connect(self.pushMessage)

    def setupUI(self):
        # set text content /value
        self.widget.setWindowTitle("自动重启升降级测试工具")
        self.ipLabel.setText("初始IP:")
        self.passwordLabel.setText("密码:")
        self.startBtn.setText("开始测试")
        self.stopBtn.setText("停止测试")
        self.userLabel.setText("用户名:")
        self.intervalLabel.setText("间隔时间:")
        self.loopLabel.setText("测试次数:")
        self.intervalSpinBox.setValue(130)
        self.radioFactory.setText("恢复出厂")
        self.radioProvision.setText("升降级")
        self.radioReboot.setText("重启")
        self.ver1Label.setText("版本 1:")
        self.ver2Label.setText("版本 2:")
        self.ver3Label.setText("版本 3:")
        self.dir1Label.setText("路径 1:")
        self.dir2Label.setText("路径 2:")
        self.dir3Label.setText("路径 3:")
        self.radioHttp.setText("Http")
        self.radioHttps.setText("Https")
        self.radioTftp.setText("Tftp")
        self.radioFtp.setText("Ftp")
        self.radioFtps.setText("Ftps")
        self.apiCheckBox.setText("使用API测试,配置CoreDump下载路径")
        self.webLabel.setText("网页类型:")
        self.webBtn.setText("请选择UI类型")
        self.clearBtn.setText("清空输入")

        self.advanceWidget.setWindowTitle("高级设置")
        self.advanceBtn.setText("高级设置")
        self.checkCoreBox.setText("发现Core Dump时停止测试")
        self.cleanCache.setText("清除页面cache")
        self.checkSaveLogBox.setText("保存测试日志")
        self.selectDirBtn.setText("浏览")
        self.checkProgressBox.setText("显示底部状态条")
        self.advanceOkBtn.setText("OK")
        self.checkShowChromeBox.setText("测试时显示Chrome浏览器")
        self.selectChromeBtn.setText("浏览")
        self.chromeLabel.setText("Chrome浏览器路径")
        self.infoLabel.setText("未开始测试")
        self.pcapLabel.setText("Net Interface")
        self.corePathBtn.setText("浏览")
        self.radioWindow.setText("网页拖拽文件")
        # self.aiOptionBox.setText("AI")

        #init value
        self.saveDirLabel.hide()
        self.selectDirBtn.hide()

        self.gxpAction.setChecked(True)
        self.radioReboot.click()
        self.radioHttp.click()
        self.stopBtn.setEnabled(False)
        self.passwordLineEdit.setEchoMode(QLineEdit.PasswordEchoOnEdit)

        # set position-------------------------------
        xPos = 20
        yPos = 30
        colum2 = xPos +200

        # line 1
        self.ipLabel.move(xPos,yPos)
        self.intervalLabel.move(colum2,yPos)
        self.intervalSpinBox.move(colum2+60,yPos-2)
        self.ipLineEdit.move(xPos+50,yPos-2)

        # line 2
        line2 = yPos +40
        self.passwordLabel.move(xPos,line2)
        self.passwordLineEdit.move(xPos+50,line2-2)
        self.loopLabel.move(colum2,line2)
        self.loopSpinBox.move(colum2+60,line2-2)

        # line3
        line3 = yPos +80
        self.userLabel.move(xPos,line3)
        self.userLineEdit.move(xPos+50,line3-2)

        self.radioReboot.move(colum2,line3)
        self.radioFactory.move(colum2+60,line3)
        self.radioProvision.move(colum2,line3+30)

        self.webLabel.move(xPos,line3+40)
        self.webBtn.move(xPos+60,line3+35)

        # provWidget
        self.provWidget.resize(400,130)
        self.provWidget.move(xPos,line3+70)
        spaceY = 30
        x = 0
        y = 0
        cl = 200
        self.ver1Label.move(x,y)
        self.ver1LineEdit.move(x+50,y)
        self.ver2Label.move(x,y+spaceY)
        self.ver2LineEdit.move(x+50,y+spaceY)
        self.ver3Label.move(x,y+spaceY*2)
        self.ver3LineEdit.move(x+50,y+spaceY*2)

        self.dir1Label.move(cl,y)
        self.dir1LineEdit.move(cl+50,y)
        self.dir2Label.move(cl,y+spaceY)
        self.dir2LineEdit.move(cl+50,y+spaceY)
        self.dir3Label.move(cl,y+spaceY*2)
        self.dir3LineEdit.move(cl+50,y+spaceY*2)

        self.radioHttp.move(x,y+spaceY*3)
        self.radioHttps.move(x+50,y+spaceY*3)
        self.radioTftp.move(x+110,y+spaceY*3)
        self.radioFtp.move(x+160,y+spaceY*3)
        self.radioFtps.move(x+210,y+spaceY*3)
        self.radioWindow.move(x+265,y+spaceY*3)

        # advance widget
        self.advanceWidget.resize(300,400)
        x = 20
        y = 20
        space = 30

        self.checkCoreBox.move(x,y)
        self.cleanCache.move(x,y+space)
        self.checkProgressBox.move(x,y+space*2)
        self.checkShowChromeBox.move(x,y+space*3)
        self.apiCheckBox.move(x,y+space*4)
        self.corePathBtn.move(x-2,y+space*5-8)
        self.corePathLabel.move(x+35,y+space*5-8)

        y += 40
        self.chromeLabel.move(x,y+space*4+10)
        self.selectChromeBtn.move(x-2,y+space*5)
        self.chromePathLabel.move(x+35,y+space*5+2)

        self.checkSaveLogBox.move(x,y+space*6+10)
        self.selectDirBtn.move(x-2,y+space*7)
        self.saveDirLabel.move(x+35,y+space*7+2)
        self.advanceOkBtn.move(x+170,y+space*10+10)
        self.interfaceMenu.move(x-5,y+space*8+10)
        self.pcapLabel.move(x,y+space*8-2)
        # self.aiOptionBox.move(x, y+space*9+8)
        # set size
        self.messageBox.resize(373,155)
        # self.widget.resize(410,400)
        self.loopSpinBox.resize(60,25)
        self.intervalSpinBox.resize(60,25)
        self.webBtn.resize(100,25)

        self.saveDirLabel.resize(185,22)
        self.selectDirBtn.resize(32,24)
        self.selectChromeBtn.resize(32,24)
        self.chromePathLabel.resize(185,22)
        self.infoLabel.resize(400, 25)
        self.corePathBtn.resize(32,24)
        self.corePathLabel.resize(185,22)
        #
        self.provWidget.hide()
        self.changePosition(True)
        self.widget.show()
        self.loadCache()
    # ----------------end of setupUI ---------------------


    def changePosition(self,hide):
        xPos = 20
        if hide:
            buttonLine = 200
            self.widget.resize(420,415)
        else:
            buttonLine = 310
            self.widget.resize(420,524)

        self.startBtn.move(xPos,buttonLine)
        self.stopBtn.move(xPos+90,buttonLine)
        self.clearBtn.move(xPos+180,buttonLine)
        self.advanceBtn.move(xPos+270,buttonLine)
        self.messageBox.move(xPos,buttonLine+30)
        boxH = self.messageBox.height()
        self.infoLabel.move(xPos,buttonLine+boxH+35)

    def setItemEnable(self,enable):
        self.provWidget.setEnabled(enable)
        self.ipLineEdit.setEnabled(enable)
        self.passwordLineEdit.setEnabled(enable)
        self.userLineEdit.setEnabled(enable)
        self.intervalSpinBox.setEnabled(enable)
        self.loopSpinBox.setEnabled(enable)
        self.radioFactory.setEnabled(enable)
        self.radioReboot.setEnabled(enable)
        self.radioProvision.setEnabled(enable)
        self.advanceBtn.setEnabled(enable)
        self.startBtn.setEnabled(enable)
        self.clearBtn.setEnabled(enable)
        if self.useApiTest:
            self.webBtn.setEnabled(False)
        else:
            self.webBtn.setEnabled(enable)
        self.stopBtn.setEnabled(not enable)

    def outputError(self,str):
        appstr = "<span style=\"color:red\">"
        appstr += str + "</span>"
        self.messageBox.append(appstr)

    def outputWarning(self,str):
        appstr = "<span style=\"color:orange\">"
        appstr += str + "</span>"
        self.messageBox.append(appstr)

    def loadCache(self):
        file = QFile("cache")
        if not file.open(QIODevice.ReadOnly | QIODevice.Text):
            return

        inStream = QTextStream(file)

        # ip
        self.ipLineEdit.setText(inStream.readLine())
        # passwordLabel
        self.passwordLineEdit.setText(inStream.readLine())
        # user
        self.userLineEdit.setText(inStream.readLine())
        # ver1
        self.ver1LineEdit.setText(inStream.readLine())
        self.dir1LineEdit.setText(inStream.readLine())
        # ver2
        self.ver2LineEdit.setText(inStream.readLine())
        self.dir2LineEdit.setText(inStream.readLine())
        # ver3
        self.ver3LineEdit.setText(inStream.readLine())
        self.dir3LineEdit.setText(inStream.readLine())

        self.intervalSpinBox.setValue(int(inStream.readLine()))
        self.loopSpinBox.setValue(int(inStream.readLine()))

        # web type button
        webType = inStream.readLine()
        if webType == "gxpAction":
            self.grp2602Action.setChecked(False)
            self.gxpAction.setChecked(True)
            self.webBtn.setText(self.gxpAction.text())
        else:
            self.grp2602Action.setChecked(True)
            self.gxpAction.setChecked(False)
            self.webBtn.setText(self.grp2602Action.text())

        testType = inStream.readLine()
        if testType == "reboot":
            self.radioReboot.setChecked(True)
        elif testType == "provision":
            self.radioProvision.setChecked(True)
            self.changePosition(False)
            self.provWidget.show()
        else:
            self.radioFactory.setChecked(True)

        serverType = inStream.readLine()
        if serverType == "Http":
            self.radioHttp.setChecked(True)
        elif serverType == "Https":
            self.radioHttps.setChecked(True)
        elif serverType == "Tftp":
            self.radioTftp.setChecked(True)
        elif serverType == "Ftp":
            self.radioFtp.setChecked(True)
        elif serverType == "Ftps":            
            self.radioFtps.setChecked(True)
        else:
            self.radioWindow.setChecked(True)

        if inStream.readLine() == "True":
            self.findCoreStop = True
        else:
            self.findCoreStop = False

        if inStream.readLine() == "True":
            self.cleanCacheSet = True
        else:
            self.cleanCacheSet = False

        if inStream.readLine() == "True":
            self.useApiTest = True
            self.webBtn.setEnabled(False)
        else:
            self.useApiTest = False
            self.corePathBtn.hide()
            self.corePathLabel.hide()

        if inStream.readLine() == "True":
            self.showTestProgress = True
        else:
            self.showTestProgress = False
            self.infoLabel.hide()

        if inStream.readLine() == "True":
            self.showChrome = True
        else:
            self.showChrome = False

        self.chromePath = inStream.readLine()

        if inStream.readLine() == "True":
            self.saveTestLog = True
        else:
            self.saveTestLog = False

        self.saveLogPath = inStream.readLine()

        self.coreDumpPath = inStream.readLine()

        file.close()

    def saveCache(self):
        file = QFile("cache")
        if not file.open(QIODevice.WriteOnly):
            return

        content = self.ipLineEdit.text() + "\n"
        content += self.passwordLineEdit.text() + "\n"
        content += self.userLineEdit.text() + "\n"
        content += self.ver1LineEdit.text() + "\n"
        content += self.dir1LineEdit.text() + "\n"
        content += self.ver2LineEdit.text() + "\n"
        content += self.dir2LineEdit.text() + "\n"
        content += self.ver3LineEdit.text() + "\n"
        content += self.dir3LineEdit.text() + "\n"

        content += str(self.intervalSpinBox.value()) + "\n"
        content += str(self.loopSpinBox.value()) + "\n"

        if self.gxpAction.isChecked():
            content += "gxpAction\n"
        else:
            content += "grp2602Action\n"

        if self.radioReboot.isChecked():
            content += "reboot\n"
        elif self.radioProvision.isChecked():
            content += "provision\n"
        else:
            content += "factory\n"

        if self.radioHttp.isChecked():
            content += "Http\n"
        elif self.radioHttps.isChecked():
            content += "Https\n"
        elif self.radioTftp.isChecked():
            content += "Tftp\n"
        elif self.radioFtp.isChecked():
            content += "Ftp\n"
        elif self.radioFtps.isChecked():
            content += "Ftps\n"
        else :
            content += "Window\n"

        content += str(self.findCoreStop) + "\n"
        content += str(self.cleanCacheSet) + "\n"
        content += str(self.useApiTest) + "\n"
        content += str(self.showTestProgress) + "\n"
        content += str(self.showChrome) + "\n"
        content += self.chromePath +"\n"
        content += str(self.saveTestLog) +"\n"
        content += self.saveLogPath +"\n"
        content += self.coreDumpPath +"\n"

        byteArr = bytes(content,"utf-8")
        file.write(QByteArray(byteArr))
        file.close()


    def checkBeforeRun(self):
        containError = False
        #---------check Ip address--------------
        if self.ipLineEdit.text() == "":
            containError = True
            self.outputError("IP地址不能为空!")
        else:
            pattern = re.compile("^((1[0-9][0-9]\.)|(2[0-4][0-9]\.)|(25[0-5]\.)|([1-9][0-9]\.)|([0-9]\.)){3}((1[0-9][0-9])|(2[0-4][0-9])|(25[0-5])|([1-9][0-9])|([0-9]))$")
            if not pattern.search(self.ipLineEdit.text()):
                containError = True
                self.outputError("IP地址格式错误,检查是否含有多余空格!(仅支持IPV4)")

        #------------------------
        if self.passwordLineEdit.text() == "":
            containError = True
            self.outputError("密码不能为空!")
        if self.userLineEdit.text() == "":
            containError = True
            self.outputError("用户名不能为空!")
        if self.intervalSpinBox.value() <= 40:
            self.outputWarning("间隔时间过短,可能对测试造成影响")
        if not self.radioProvision.isChecked() and not self.radioReboot.isChecked() and \
           not self.radioFactory.isChecked():
            containError = True
            self.outputError("必须选择测试方式(重启,升降级,恢复出厂)")

        # check provision ----------
        if self.radioProvision.isChecked():
            if self.ver1LineEdit.text() == "" or self.ver2LineEdit.text() == "" or \
               self.dir1LineEdit.text() == "" or self.dir2LineEdit.text() == "":
                containError = True
                self.outputError("升降级测试至少填上前两个版本及其路径")

            bin_name = ""
            if os.path.exists(os.path.abspath("config.ini") ):
                f = open(os.path.abspath("config.ini") , "r")
                line = f.readline()
                while line:
                    option = line.split("=")
                    if option[0] == "firmbinname":
                        if option[1].strip('"') != "":
                            filenamebin = option[1].strip()
                            bin_name = filenamebin.strip('"')
                        pass
                    line = f.readline()
                f.close()

            filename = os.path.join(self.dir1LineEdit.text(), bin_name)
            if not os.path.exists(filename) and self.radioWindow.isChecked():
                containError = True
                self.outputError("firmware1 文件不存在!" + filename)
            filename = os.path.join(self.dir2LineEdit.text(), bin_name)
            if not os.path.exists(filename) and self.radioWindow.isChecked():
                containError = True
                self.outputError("firmware2 文件不存在!" + filename)
           

            filename = os.path.join(self.dir3LineEdit.text(), bin_name)
            if self.ver3LineEdit.text() != "" and self.dir3LineEdit.text() == "":
                containError = True
                self.outputError("填写了版本3,但对应路径为空!")
            if self.dir3LineEdit.text() != "" and self.ver3LineEdit.text() == "":
                containError = True
                self.outputError("填写了路径3,但对应版本为空!")
            elif self.dir3LineEdit.text() != "" and self.radioWindow.isChecked() and not os.path.exists(filename):
                containError = True
                self.outputError("firmware3 文件不存在!" + filename)

            if not self.radioFtp.isChecked() and not self.radioFtps.isChecked() and \
               not self.radioHttp.isChecked() and not self.radioHttps.isChecked() and \
               not self.radioTftp.isChecked() and not self.radioWindow.isChecked():
                containError = True
                self.outputError("升降级测试必须选择服务器类型(Tftp,Ftp,Ftps,Http,Https)")
        return containError



    def startTest(self):
        ip = self.ipLineEdit.text()
        passwd = self.passwordLineEdit.text()
        username = self.userLineEdit.text()
        ptime = self.intervalSpinBox.value()
        loop = self.loopSpinBox.value()
        modelType = self.webBtn.text()
        if self.gxpAction.isChecked():
            device_type = "GXP21XX"
        elif self.grp2602Action.isChecked():
            device_type = "GRP260X"

        if self.radioReboot.isChecked():
            task_type = "reboot"
        elif self.radioProvision.isChecked():
            task_type = "provision"
            text_ver1 = self.ver1LineEdit.text()
            text_ver2 = self.ver2LineEdit.text()
            text_ver3 = self.ver3LineEdit.text()
            text_dir1 = self.dir1LineEdit.text()
            text_dir2 = self.dir2LineEdit.text()
            text_dir3 = self.dir3LineEdit.text()
            prov_dict = {"ver1": text_ver1.strip(), "dir1": text_dir1.strip(), "ver2": text_ver2.strip(),
                        "dir2": text_dir2.strip(), "ver3": text_ver3.strip(), "dir3": text_dir3.strip()}

            if self.radioHttp.isChecked():
                self.man.update_prov_setting("HTTP", prov_dict)
            elif self.radioHttps.isChecked():
                self.man.update_prov_setting("HTTPS", prov_dict)
            elif self.radioTftp.isChecked():
                self.man.update_prov_setting("TFTP", prov_dict)
            elif self.radioFtp.isChecked():
                self.man.update_prov_setting("FTP", prov_dict)
            elif self.radioFtps.isChecked():
                self.man.update_prov_setting("FTPS", prov_dict)
            elif self.radioWindow.isChecked():
                self.man.update_prov_setting("browser", prov_dict)

        else:
            task_type = "reset"

        coredump_stop = True
        headless_flag = False
        clean_cache = False
        if self.checkCoreBox.isChecked() == False:
            self.messageBox.append("Find core dump will not stop")
            coredump_stop = False
        if self.cleanCache.isChecked() == True:
            clean_cache = True
            
        if self.checkShowChromeBox.isChecked() == True or self.radioWindow.isChecked() == True:
            headless_flag = False
        else:
            headless_flag = True

        # ai_mode = False
        # if self.aiOptionBox.isChecked() == True:
        #     ai_mode = True

        browser_path = ""
        if self.chromePathLabel.text() != "":
            browser_path = self.chromePathLabel.text()

        self.testStatus = [True,1,0,"ip",""]
        print(self.interfaceMenu.currentText())
        self.man.setStatus(self.testStatus)
        self.man.setMessageList(self.messageList)
        self.man.update_setting(ip.strip(), username.strip(), passwd.strip(), device_type, \
                                task_type, loop, ptime, coredump_stop, headless_flag, browser_path, \
                                clean_cache, self.interfaceMenu.currentText(), False)
    
    def startApiTest(self):
        ip = self.ipLineEdit.text()
        passwd = self.passwordLineEdit.text()
        username = self.userLineEdit.text()
        ptime = self.intervalSpinBox.value()
        loop = self.loopSpinBox.value()
        
        testType = "Reboot"
        if self.radioProvision.isChecked():
            testType = "Provision"
        self.api.setValue(ip,username,passwd,ptime,loop,testType)

        v1 = self.ver1LineEdit.text()
        v2 = self.ver2LineEdit.text()
        v3 = self.ver3LineEdit.text()
        d1 = self.dir1LineEdit.text()
        d2 = self.dir2LineEdit.text()
        d3 = self.dir3LineEdit.text()
        self.api.setVersion(v1,v2,v3,d1,d2,d3)

        self.api.setTestStatus(self.testStatus,self.messageList,self.coreDumpPath)

        if self.radioHttp.isChecked():
            self.api.setServerType("http")
        elif self.radioHttps.isChecked():
            self.api.setServerType("https")
        elif self.radioTftp.isChecked():
            self.api.setServerType("tftp")
        elif self.radioFtp.isChecked():
            self.api.setServerType("ftp")
        else: #self.radioFtps.isChecked()
            self.api.setServerType("ftps")
        
        self.api.setFoundCoreStop(self.findCoreStop)


    # slot ---------------------------------
    def apiTestBoxCheck(self,state):
        if state == 2:
            self.corePathBtn.show()
            self.corePathLabel.show()
        else:
            self.corePathBtn.hide()
            self.corePathLabel.hide()

    def clickedCorePathBtn(self):
        dir = QFileDialog.getExistingDirectory(self.advanceWidget,"选择Core Dump存放路径","/home")
        if dir != "":
            self.corePathLabel.setText(dir)
            self.coreDumpPath = dir

    def clickedSelectDirBtn(self):
        dir = QFileDialog.getExistingDirectory(self.advanceWidget,"选择日志存放路径","/home")
        if dir != "":
            self.saveDirLabel.setText(dir)
            self.saveLogPath = dir

    def clickedSelectChromeBtn(self):
        fileName = QFileDialog.getOpenFileName(self.advanceWidget,"选择谷歌浏览器","/home","Chrome (*.exe)")
        if fileName != "":
            self.chromePathLabel.setText(fileName[0])
            self.chromePath = fileName[0]

    def saveLogBoxCheck(self,state):
        if state == 2: # checked
            self.selectDirBtn.show()
            self.saveDirLabel.show()
        else:
            self.selectDirBtn.hide()
            self.saveDirLabel.hide()

    def clickedAdvanceOkBtn(self):
        self.findCoreStop = self.checkCoreBox.isChecked()
        self.cleanCacheSet = self.cleanCache.isChecked()
        self.useApiTest = self.apiCheckBox.isChecked()
        self.showTestProgress = self.checkProgressBox.isChecked()
        self.saveTestLog = self.checkSaveLogBox.isChecked()
        self.saveLogPath = self.saveDirLabel.text()
        self.showChrome = self.checkShowChromeBox.isChecked()
        self.chromePath = self.chromePathLabel.text()
        self.coreDumpPath = self.corePathLabel.text()

        if self.useApiTest:
            self.webBtn.setEnabled(False)
            self.corePathBtn.show()
            self.corePathLabel.show()
        else:
            self.webBtn.setEnabled(True)
            self.corePathBtn.hide()
            self.corePathLabel.hide()

        if self.showTestProgress:
            self.infoLabel.show()
        else:
            self.infoLabel.hide()
                
        self.saveCache()
        self.advanceWidget.hide()


    def clickedAdvanceBtn(self):
        self.advanceWidget.hide()
        self.checkCoreBox.setChecked(self.findCoreStop)
        self.cleanCache.setChecked(self.cleanCacheSet)
        self.apiCheckBox.setChecked(self.useApiTest)
        self.checkProgressBox.setChecked(self.showTestProgress)
        self.checkSaveLogBox.setChecked(self.saveTestLog)
        self.saveDirLabel.setText(self.saveLogPath)
        self.checkShowChromeBox.setChecked(self.showChrome)
        self.chromePathLabel.setText(self.chromePath)
        self.corePathLabel.setText(self.coreDumpPath)
        self.advanceWidget.show()

    def slotTestStoped(self):
        self.testStatus[0] = False
        self.setItemEnable(True)
        self.timer.stop()
        self.updateMessage()
        self.thread.quit()

        # save Test log
        if self.saveTestLog:
            fileName = time.strftime("%Y_%m_%d.%H_%M_%S.",time.localtime())
            if self.radioReboot.isChecked():
                fileName += "reboot"
            elif self.radioProvision:
                fileName += "provision"
            else:
                fileName += "factoryReset"
            fileName += ".htm"
            if self.saveLogPath == "":
                self.outputWarning("日志地址没有设置,无法保存")
            else:
                fileName = self.saveLogPath + "\\" + fileName
                print(fileName)

                file = QFile(fileName)
                if not file.open(QIODevice.WriteOnly):
                    self.outputError("打开文件错误,保存日志失败")
                    return

                byteArr = bytes(self.messageBox.toHtml(),"utf-8")
                file.write(QByteArray(byteArr))
                file.close()

    def clickedClearBtn(self):
        self.ipLineEdit.setText("")
        self.passwordLineEdit.setText("")
        self.userLineEdit.setText("")
        self.ver1LineEdit.setText("")
        self.dir1LineEdit.setText("")
        self.ver2LineEdit.setText("")
        self.dir2LineEdit.setText("")
        self.ver3LineEdit.setText("")
        self.dir3LineEdit.setText("")

    def clickedStarBtn(self):
        if self.checkBeforeRun():
            return
        self.messageBox.clear()
        self.saveCache()
        self.messageBox.append("Init Setting...")
        self.setItemEnable(False)
        self.timer.start(500)
        self.thread.start()

        # deside use what to test
        if self.useApiTest:
            if self.radioFactory.isChecked():
                self.outputWarning("Api not support Factory Reset, will test as Gxp type web driver")	
                self.clickedGxpType()
                self.startTest()
                self.signalRun.emit(self.man)
            else:
                self.startApiTest()
                self.signalRunApi.emit(self.api)
        else:
            self.startTest()
            self.signalRun.emit(self.man)

    def clickedStopBtn(self):
        self.stopBtn.setEnabled(False)
        self.testStatus[0] = False
        self.man.quit()
        self.outputWarning("正在停止...")

    def clickedProvision(self):
        self.provWidget.show()
        self.changePosition(False)

    def clickedOthers(self):
        self.provWidget.hide()
        self.changePosition(True)

    def clickedGxpType(self):
        self.gxpAction.setChecked(True)
        self.grp2602Action.setChecked(False)
        self.webBtn.setText(self.gxpAction.text())

    def clickedGrp2602(self):
        self.gxpAction.setChecked(False)
        self.grp2602Action.setChecked(True)
        self.webBtn.setText(self.grp2602Action.text())

    def updateMessage(self):
        while len(self.messageList) >0:
            info = self.messageList.popleft()
            self.messageBox.append(info)
        if self.testStatus[0] == False:
            self.infoLabel.setText("未开始测试")
        else:
            info = "第" + str(self.testStatus[1]) + "次测试   "
            if self.testStatus[2] > 0:
                info += "等待:{} 秒".format( self.testStatus[2] )
            else:
                info += "运行中"
            
            info += "  " + self.testStatus[3]
            info += "  " + self.testStatus[4]
            self.infoLabel.setText(info)
Ejemplo n.º 8
0
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.resize(1280, 720)
        self.central_widget = QWidget(MainWindow)

        self.splitter = QSplitter(self.central_widget)
        self.splitter.setChildrenCollapsible(False)
        self.splitter.setOpaqueResize(True)

        self.main_grid_layout = QGridLayout(self.central_widget)
        self.main_grid_layout.addWidget(self.splitter)
        self.main_grid_layout.setSizeConstraint(QLayout.SetDefaultConstraint)

        self.tab_widget = QTabWidget(self.central_widget)
        self.tab_widget.setMinimumSize(QSize(500, 0))
        self._set_up_component_tree_view()
        self.splitter.addWidget(self.tab_widget)

        self._set_up_3d_view()

        MainWindow.setCentralWidget(self.central_widget)

        self._set_up_menus(MainWindow)
        self.tab_widget.setCurrentIndex(0)
        QMetaObject.connectSlotsByName(MainWindow)
        self.splitter.setStretchFactor(0, 0)
        self.splitter.setStretchFactor(1, 1)

    def _set_up_3d_view(self):
        self.sceneWidget.setMinimumSize(QSize(600, 0))
        self.splitter.addWidget(self.sceneWidget)

    def _set_up_component_tree_view(self):
        self.sceneWidget = InstrumentView(self.splitter)
        self.component_tree_view_tab = ComponentTreeViewTab(
            scene_widget=self.sceneWidget, parent=self
        )
        self.tab_widget.addTab(self.component_tree_view_tab, "")

    def _set_up_menus(self, MainWindow: QObject):
        self.menu_bar = QMenuBar()
        self.menu_bar.setGeometry(QRect(0, 0, 1280, 720))
        self.file_menu = QMenu(self.menu_bar)
        MainWindow.setMenuBar(self.menu_bar)
        self.status_bar = QStatusBar(MainWindow)
        MainWindow.setStatusBar(self.status_bar)
        self.open_json_file_action = QAction(MainWindow)
        self.open_json_file_action.setShortcut(QKeySequence("Ctrl+O"))
        self.export_to_filewriter_JSON_action = QAction(MainWindow)
        self.export_to_filewriter_JSON_action.setShortcut(QKeySequence("Ctrl+S"))
        self.file_menu.addAction(self.open_json_file_action)
        self.file_menu.addAction(self.export_to_filewriter_JSON_action)

        self.view_menu = QMenu(self.menu_bar)
        self.show_action_labels = QAction(MainWindow)
        self.show_action_labels.setCheckable(True)
        self.show_action_labels.setChecked(True)
        self.simple_tree_view = QAction(MainWindow)
        self.simple_tree_view.setCheckable(True)
        self.about_window = QAction(MainWindow)
        self.view_menu.addAction(self.about_window)
        self.view_menu.addAction(self.show_action_labels)
        self.view_menu.addAction(self.simple_tree_view)

        self.menu_bar.addAction(self.file_menu.menuAction())
        self.menu_bar.addAction(self.view_menu.menuAction())
        self._set_up_titles(MainWindow)

    def _set_up_titles(self, MainWindow):
        MainWindow.setWindowTitle("NeXus Constructor")
        self.tab_widget.setTabText(
            self.tab_widget.indexOf(self.component_tree_view_tab), "Nexus Structure"
        )
        self.file_menu.setTitle("File")
        self.open_json_file_action.setText("Open File writer JSON file")
        self.export_to_filewriter_JSON_action.setText("Export to File writer JSON")

        self.view_menu.setTitle("View")
        self.show_action_labels.setText("Show Button Labels")
        self.simple_tree_view.setText("Use Simple Tree Model View")
        self.about_window.setText("About")

        self.menu_bar.setNativeMenuBar(False)
Ejemplo n.º 9
0
class MineSweeperWindow(QMainWindow):
    def __init__(self, mode):
        super().__init__()
        self.ms = mode
        self.init_ui()
        self.set_menu()

    def init_ui(self):
        """初始化游戏界面"""
        # 1.确定游戏界面的标题,大小和背景颜色
        self.setObjectName('MainWindow')
        self.setWindowTitle('扫雷')
        self.setWindowIcon(QIcon(':/minesweeper.ico'))
        self.setFixedSize(50 * self.ms.length + 100, 50 * self.ms.width + 180)
        self.setStyleSheet('#MainWindow{background-color: #f6edd2}')
        self.remain_boom = QLCDNumber(2, self)
        self.remain_boom.move(50, 50)
        self.remain_boom.setFixedSize(60, 50)
        self.remain_boom.setStyleSheet(
            "border: 2px solid blue; color: red; background: black;")
        self.remain_boom.display(
            '{:>02d}'.format(self.ms.b_num if self.ms.b_num >= 0 else 0))
        self.timer = QBasicTimer()
        self.second = 0
        self.time = QLCDNumber(3, self)
        self.time.move(50 * self.ms.length - 40, 50)
        self.time.setFixedSize(90, 50)
        self.time.setStyleSheet(
            "border: 2px solid blue; color: red; background: black;")
        self.time.display('{:>03d}'.format(self.second))
        self.btn = QPushButton(self)
        self.btn.move(25 * self.ms.length + 20, 50)
        self.btn.setFixedSize(50, 50)
        self.btn.setIcon(QIcon(':/普通.png'))
        self.btn.setIconSize(QSize(45, 45))
        self.btn.setStyleSheet('QPushButton{border:None}')
        self.btn.clicked.connect(self.restart)
        self.over_signal = 0
        self.rank = sqlite3.connect('rank.db')
        self.c = self.rank.cursor()

    def set_menu(self):
        bar = self.menuBar()
        game = bar.addMenu('游戏(&G)')
        more_info = bar.addMenu('更多(&M)')

        new_game = QAction('新游戏(&N)', self)
        new_game.setShortcut('Ctrl+N')
        new_game.triggered.connect(self.start)
        game.addAction(new_game)
        restart = QAction('重玩(&R)', self)
        restart.setShortcut('Ctrl+R')
        restart.triggered.connect(self.restart)
        game.addAction(restart)
        game.addSeparator()
        self.modes = QActionGroup(self)
        self.easy = QAction('简单(E)', self)
        self.easy.setCheckable(True)
        game.addAction(self.modes.addAction(self.easy))
        self.medium = QAction('中等(M)', self)
        self.medium.setCheckable(True)
        game.addAction(self.modes.addAction(self.medium))
        self.hard = QAction('困难(H)', self)
        self.hard.setCheckable(True)
        game.addAction(self.modes.addAction(self.hard))
        self.modes.triggered.connect(
            lambda: self.set_mode(self.modes.checkedAction()))
        if isinstance(self.ms, EasyMode):
            self.easy.setChecked(True)
        elif isinstance(self.ms, MediumMode):
            self.medium.setChecked(True)
        elif isinstance(self.ms, HardMode):
            self.hard.setChecked(True)

        rank = QAction('排行耪(&R)', self)
        rank.triggered.connect(self.show_rank)
        more_info.addAction(rank)

    def paintEvent(self, e):
        """绘制游戏内容"""
        qp = QPainter()

        def draw_map():
            """绘制版面"""
            # background = QPixmap(':/背景2.png')
            # qp.drawPixmap(self.rect(), background)
            # qp.setBrush(QColor('#e8ff9d'))
            # qp.drawRect(50, 130, 50 * self.ms.length, 50 * self.ms.width)
            for x in range(0, self.ms.length, 2):
                for y in range(0, self.ms.width, 2):
                    qp.setBrush(QColor('#007a15'))
                    qp.drawRect(50 * (x + 1), 50 * (y + 1) + 80, 50, 50)
                for y in range(1, self.ms.width, 2):
                    qp.setBrush(QColor('#00701c'))
                    qp.drawRect(50 * (x + 1), 50 * (y + 1) + 80, 50, 50)
            for x in range(1, self.ms.length, 2):
                for y in range(0, self.ms.width, 2):
                    qp.setBrush(QColor('#00701c'))
                    qp.drawRect(50 * (x + 1), 50 * (y + 1) + 80, 50, 50)
                for y in range(1, self.ms.width, 2):
                    qp.setBrush(QColor('#007a15'))
                    qp.drawRect(50 * (x + 1), 50 * (y + 1) + 80, 50, 50)
            # qp.setPen(QPen(QColor(111, 108, 108), 2, Qt.SolidLine))
            # for x in range(self.ms.length + 1):
            #     qp.drawLine(50 * (x + 1), 130, 50 * (x + 1), 50 * self.ms.width + 130)
            # for y in range(self.ms.width + 1):
            #     qp.drawLine(50, 50 * (y + 1) + 80, 50 * self.ms.length + 50, 50 * (y + 1) + 80)

        def draw_blanks():
            qp.setBrush(QColor('#f4f4f4'))
            for x in range(self.ms.length):
                for y in range(self.ms.width):
                    if isinstance(self.ms.g_map[y][x], str):
                        if self.ms.g_map[y][x] == '0$' or self.ms.g_map[y][
                                x] == '1$':
                            # qp.setPen(QPen(QColor(219, 58, 58), 1, Qt.SolidLine))
                            # qp.setFont(QFont('Kai', 15))
                            flag = QPixmap(':/雷旗.png').scaled(50, 50)
                            qp.drawPixmap(
                                QRect(50 * (x + 1), 50 * (y + 1) + 80, 50, 50),
                                flag)
                            # qp.drawText(50 * (x + 1) + 18, 50 * (y + 1) + 115, '$')
                            continue
                        qp.setPen(QPen(QColor('black'), 1, Qt.SolidLine))
                        qp.setFont(QFont('Kai', 15))
                        qp.drawRect(50 * (x + 1), 50 * (y + 1) + 80, 50, 50)
                        if self.ms.g_map[y][x] == '0':
                            continue
                        if self.ms.g_map[y][x] == '*':
                            flag = QPixmap(':/土豆雷.png').scaled(50, 50)
                            qp.drawPixmap(
                                QRect(50 * (x + 1), 50 * (y + 1) + 80, 50, 50),
                                flag)
                            continue
                        qp.setPen(QPen(QColor('black'), 5, Qt.SolidLine))
                        qp.drawText(50 * (x + 1) + 18, 50 * (y + 1) + 115,
                                    '{}'.format(self.ms.g_map[y][x]))

        qp.begin(self)
        draw_map()
        draw_blanks()
        qp.end()

    def mousePressEvent(self, e):
        """根据鼠标的动作,确定落子位置"""
        if self.over_signal == 1:
            return
        if e.button() in (Qt.LeftButton, Qt.RightButton):
            mouse_x = e.windowPos().x()
            mouse_y = e.windowPos().y()
            if 50 <= mouse_x <= 50 * self.ms.length + 50 and 130 <= mouse_y <= 50 * self.ms.width + 130:
                if self.ms.step == 0:
                    self.timer.start(1000, self)
                    self.tic = time_ns()
                game_x = int(mouse_x // 50) - 1
                game_y = int((mouse_y - 80) // 50) - 1
            else:
                return
            if e.buttons() == Qt.LeftButton | Qt.RightButton:
                self.ms.click_around(game_x, game_y)
            elif e.buttons() == Qt.LeftButton:
                self.ms.click(game_x, game_y)
            else:
                self.ms.mark_mine(game_x, game_y)
        if self.ms.boom:
            self.timer.stop()
            self.btn.setIcon(QIcon(':/哭脸.png'))
            self.btn.setIconSize(QSize(45, 45))
            self.repaint(0, 0, 50 * self.ms.length + 100,
                         50 * self.ms.width + 180)
            self.over_signal = 1
            return
        elif self.ms.game_judge():
            self.timer.stop()
            self.toc = time_ns()
            self.btn.setIconSize(QSize(45, 45))
            self.btn.setIcon(QIcon(':/笑脸.png'))
            self.repaint(0, 0, 50 * self.ms.length + 100,
                         50 * self.ms.width + 180)
            self.check_rank()
            self.over_signal = 1
            return
        self.repaint(0, 0, 50 * self.ms.length + 100, 50 * self.ms.width + 180)
        self.remain_boom.display(
            '{:>02d}'.format(self.ms.b_num if self.ms.b_num >= 0 else 0))

    def timerEvent(self, e) -> None:
        self.second += 1
        self.time.display('{:>03d}'.format(self.second))

    def set_mode(self, action: QAction):
        if action == self.easy:
            self.close()
            self.msw = MineSweeperWindow(EasyMode())
            self.msw.show()
        elif action == self.medium:
            self.close()
            self.msw = MineSweeperWindow(MediumMode())
            self.msw.show()
        elif action == self.hard:
            self.close()
            self.msw = MineSweeperWindow(HardMode())
            self.msw.show()

    def show_rank(self):
        self.sk = ShowRank()
        self.sk.show()

    def start(self):
        self.close()
        self.a = Start()
        self.a.show()

    def restart(self):
        self.ms.refresh()
        self.repaint()
        self.btn.setIcon(QIcon(':/普通.png'))
        self.remain_boom.display(
            '{:>02d}'.format(self.ms.b_num if self.ms.b_num >= 0 else 0))
        self.second = 0
        self.timer.stop()
        self.time.display('{:>03d}'.format(self.second))
        self.over_signal = 0

    def check_rank(self):
        a_num = (self.toc - self.tic) / 10**9
        out = subprocess.check_output("whoami").decode("gbk")
        name = re.search(r"\\(.+)\r\n", out)
        a_user = name.group(1)
        for i in range(5, 0, -1):
            if isinstance(self.ms, EasyMode):
                mode = "Easy"
            elif isinstance(self.ms, MediumMode):
                mode = "Medium"
            elif isinstance(self.ms, HardMode):
                mode = "Hard"
            else:
                return
            self.c.execute("SELECT * FROM {} WHERE id=?;".format(mode), (i, ))
            feedback = self.c.fetchone()
            if i == 5:
                if (not feedback[2]) or (feedback[2] > a_num):
                    a_user, _ = QInputDialog.getText(self,
                                                     "用户名",
                                                     "请输入用户名:",
                                                     QLineEdit.Normal,
                                                     text=a_user)
                    self.c.execute(
                        "UPDATE {} SET user=?, time=? WHERE id=?;".format(
                            mode), (a_user, a_num, i))
                    self.rank.commit()
                    continue
                else:
                    return
            else:
                if (not feedback[2]) or (feedback[2] > a_num):
                    self.c.execute(
                        "UPDATE {0} "
                        "SET user = (SELECT user FROM {0} WHERE id=?), "
                        "time = (SELECT time FROM {0} WHERE id=?)"
                        "WHERE id=? ;".format(mode), (i, i, i + 1))
                    self.c.execute(
                        "UPDATE {} SET user=?, time=? WHERE id=? ;".format(
                            mode), (a_user, a_num, i))
                    self.rank.commit()
                else:
                    return

    def closeEvent(self, e):
        self.rank.commit()
        self.rank.close()
Ejemplo n.º 10
0
class ConsoleWidget(QTextEdit):
    def __init__(self):
        super().__init__()

        self.setReadOnly(True)
        self.setWordWrapMode(QTextOption.NoWrap)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setStyleSheet('''
            QTextEdit {
                background-color: #2b2b2b;
                font-family: "Consolas";
                font-size: 10pt;
                color: #bbbbbb;
                border: 0;
                white-space: pre;
            }''')

        self.handlerObj = RichTextHandlerObject()
        self.handler = RichTextHandler(self.handlerObj)
        self.handler.setFormatter(ConsoleFormatter())
        self.handlerObj.wroteLine.connect(self.write)
        g.log.addHandler(self.handler)

        self.actionCopy = QAction(
            '&Copy',
            self,
            shortcut=QKeySequence.Copy,
            statusTip='Copy selected text to the clipboard',
            triggered=self.copy)
        self.actionSelectAll = QAction(
            'Select &All',
            self,
            shortcut=QKeySequence.SelectAll,
            statusTip='Select all text in the output window',
            triggered=self.selectAll)
        self.actionScrollToEnd = QAction(
            'Scroll to &End',
            self,
            statusTip='Move the cursor to the end of the output',
            triggered=self.scrollToEnd)
        self.actionWordWrap = QAction('&Word Wrap',
                                      self,
                                      statusTip='Toggle word wrap',
                                      checkable=True,
                                      triggered=self.toggleWordWrap)
        self.actionClear = QAction('C&lear',
                                   self,
                                   statusTip='Clear the output window',
                                   triggered=self.clear)

    @Slot(str)
    def write(self, line):
        self.append(line)
        self.scrollToEnd()

    def scrollToEnd(self):
        self.moveCursor(QTextCursor.End)
        self.moveCursor(QTextCursor.StartOfLine)

    def toggleWordWrap(self):
        if self.wordWrapMode() == QTextOption.NoWrap:
            self.setWordWrapMode(QTextOption.WordWrap)
        else:
            self.setWordWrapMode(QTextOption.NoWrap)

    def clear(self):
        self.setText('')
        self.scrollToEnd()

    def contextMenuEvent(self, event):
        menu = QMenu(self)
        menu.addAction(self.actionCopy)
        menu.addAction(self.actionSelectAll)
        menu.addAction(self.actionScrollToEnd)
        menu.addSeparator()
        self.actionWordWrap.setChecked(
            self.wordWrapMode() != QTextOption.NoWrap)
        menu.addAction(self.actionWordWrap)
        menu.addAction(self.actionClear)
        menu.exec_(event.globalPos())
Ejemplo n.º 11
0
    def buttonActions(self, action: str) -> QAction:
        addAct = QAction(QIcon().fromTheme("list-add"), "&Add to collection...", self)
        addAct.setShortcut("Ctrl+A")
        addAct.setToolTip("Add to collection")
        addAct.triggered.connect(self.addToCollection)

        delText = "&Delete row"
        currentTab = self.tab.currentIndex()
        if 0 < currentTab < 4:
            if len(self.tableViewList[currentTab-1].selectedIndexes()) > 1:
                delText += "s"
        delAct = QAction(QIcon().fromTheme("edit-delete"), delText, self)
        delAct.setToolTip("Delete from collection")
        delAct.triggered.connect(self.deleteFromCollection)

        detAct = QAction(QIcon.fromTheme("text-x-generic-template"), "Details...", self)
        detAct.setToolTip("Open details side-panel")
        detAct.triggered.connect(self.tableViewList[currentTab-1].rowData)

        expAct = QAction(QIcon.fromTheme("text-x-generic-template"), "&Export as csv...", self)
        expAct.setShortcut("Ctrl+E")
        expAct.setToolTip("Export table as CSV file")
        expAct.triggered.connect(self.exportToCSV)

        impAct = QAction(QIcon.fromTheme("insert-object"), "&Import platform template...", self)
        impAct.setShortcut("Ctrl+I")
        impAct.setToolTip("Import games to database")
        impAct.triggered.connect(self.importToDatabase)

        stmAct = QAction(QIcon.fromTheme("insert-object"), "Import Steam Library...", self)
        stmAct.triggered.connect(self.importSteamLibrary)

        ownAct = QAction("Hide games not in collection", self)
        ownAct.setCheckable(True)
        ownAct.setChecked(True)
        ownAct.triggered.connect(self.toggleOwnedFilter)

        delNotOwned = QAction(QIcon().fromTheme("edit-delete"), "Remove items not in collection", self)
        delNotOwned.setToolTip("Remove items that are not owned from database")
        delNotOwned.triggered.connect(self.deleteNotOwned)

        aboutAct = QAction(QIcon.fromTheme("help-about"), "Abou&t", self)
        aboutAct.setToolTip("About Game Collection Manager")
        aboutAct.triggered.connect(self.about)

        exitAct = QAction(QIcon.fromTheme("application-exit"), "&Exit", self)
        exitAct.setShortcut("Ctrl+Q")
        exitAct.setToolTip("Exit application")
        exitAct.triggered.connect(self.close)

        infoAct = QAction("Debug: Print row info", self)
        infoAct.triggered.connect(self.info)

        fetchAct = QAction("Fetch info for all games...", self)
        fetchAct.setToolTip("Tries to fetch info for all games from MobyGames")
        fetchAct.triggered.connect(self.fetchInfo)

        valAct = QAction("Total value of collection", self)
        valAct.setToolTip("Rough estimate of the total value of collection")
        valAct.triggered.connect(self.totalValue)

        act = {"add": addAct, "del": delAct, "det": detAct, "export": expAct,
               "import": impAct, "steam": stmAct, "owned": ownAct,
               "delnotowned": delNotOwned, "about": aboutAct, "exit": exitAct,
               "info": infoAct, "fetch": fetchAct, "value": valAct}

        return act.get(action)
Ejemplo n.º 12
0
def main():
    logging.info('main')

    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(False)

    appctxt = AppContext(app)

    sentry_sdk.init(
        "https://[email protected]/5210435",
        shutdown_timeout=5,
        default_integrations=False,
        # Either pyqt or pyinstaller do weird things with sentry,
        # need to explicitely specify these else sentry fails
        integrations=[
            LoggingIntegration(),
            StdlibIntegration(),
            ExcepthookIntegration(),
            DedupeIntegration(),
            AtexitIntegration(),
            ModulesIntegration(),
            ArgvIntegration(),
            ThreadingIntegration(),
        ])

    instance = SingleInstance()
    print('instance', instance)

    logger = get_logging(appctxt.build_settings['debug'])
    build_msg = "Production" if appctxt.is_frozen else "Development"
    logger.info(
        f"PWUploader, version: {appctxt.build_settings['version']}, {build_msg} build"
    )
    logging.debug(f'config {CONFIG.as_dict()}')

    signal.signal(signal.SIGINT, signal.SIG_DFL)

    logo_path = appctxt.get_resource('logo.png')
    logging.debug(f'logo_path: {logo_path}')
    icon = QIcon(logo_path)
    tray = QSystemTrayIcon()
    tray.setIcon(icon)
    logging.debug('tray: %s', tray)
    tray.show()

    menu = QMenu()

    # left-click should just open the menu too
    def on_systray_activated(reason):
        if reason == 3:
            menu.popup(QCursor.pos())

    tray.activated.connect(on_systray_activated)

    action0 = QAction(f"Version: v{appctxt.build_settings['version']}")
    menu.addAction(action0)

    action2 = QAction('settings')
    action2.triggered.connect(on_settings(appctxt))
    menu.addAction(action2)

    action3 = QAction('resync files')

    def connect_missing_files():
        upload_missing_files(appctxt, remote_config)

    action3.triggered.connect(connect_missing_files)
    menu.addAction(action3)

    action4 = QAction('open log dir')
    action4.triggered.connect(on_open_logdir)
    menu.addAction(action4)

    def toggle_always_running(state):
        if state:
            CONFIG.set('always_running', True)
            start_guardian_detached()
        else:
            CONFIG.set('always_running', False)
            kill_guardian()
        with open(CONFIG_FILE, 'w') as f:
            f.write(json.dumps(CONFIG.as_dict(), indent=2))
        logging.info('config saved')

    action5 = QAction('always running', checkable=True)
    if CONFIG.get('always_running'):
        action5.setChecked(True)
    action5.triggered.connect(toggle_always_running)
    menu.addAction(action5)

    action1 = QAction("quit")
    action1.triggered.connect(on_quit)
    menu.addAction(action1)

    tray.setContextMenu(menu)

    # FIXME get this after app display if possible
    for i in range(10):
        api = PWAPI(appctxt, appctxt.build_settings['api_url'],
                    CONFIG.get('api_token'), CONFIG.get('account_id'))
        remote_config = api.get_config()

        if 'detail' in remote_config:
            logging.error('Invalid remote config %s', remote_config)
            message = 'Unable to reach Pathology Watch API for authentication, are your API Token & Lab ID correct? Click ok to open settings.'
            response = QtWidgets.QMessageBox.question(
                None, 'API Error', message, QtWidgets.QMessageBox.Ok,
                QtWidgets.QMessageBox.Cancel)
            if response == QtWidgets.QMessageBox.Cancel:
                sys.exit(0)
            settings_dialog = SettingsDialog(appctxt, CONFIG, CONFIG_FILE)
            settings_dialog.ui.setWindowModality(QtCore.Qt.ApplicationModal)
            settings_dialog.ui.exec_()
        else:
            break
        time.sleep(1)

    if remote_config is not None:
        clean_remote_config = {
            k: v
            for k, v in remote_config.items() if 'secret' not in k
        }
        logging.debug(f'remote_config {clean_remote_config}')
        # TODO verify remote_config if it's not set, check api token or pw connectivity
    else:
        logging.error(
            'Uploader settings invalid or server isn\'t configured, contact [email protected]'
        )
        sys.exit(1)

    # FIXME need to validate remote_config, config

    logging.info('Starting upload watcher')
    watcher_thread = WatcherThread(CONFIG.get('watch_dir'), trigger_upload)
    watcher_thread.finished.connect(app.exit)
    watcher_thread.start()

    logging.info('Starting heartbeat thread')
    heartbeat_thread = HeartbeatThread(appctxt, remote_config, CONFIG,
                                       upload_missing_files)
    heartbeat_thread.finished.connect(app.exit)
    heartbeat_thread.start()

    worker_threads = []
    for i in range(appctxt.build_settings['n_upload_worker_threads']):
        logging.info(f'Starting worker {i}')
        worker_thread = WorkerThread(appctxt, remote_config, CONFIG,
                                     UPLOAD_QUEUE)
        worker_thread.finished.connect(app.exit)
        worker_thread.start()
        worker_threads.append(worker_thread)

    #def excepthook(exc_type, exc_value, exc_tb):
    #    import traceback
    #    tb = "".join(traceback.format_exception(exc_type, exc_value, exc_tb))
    #    logging.error("error caught: %s", str(tb))
    #    capture_exception(exc_type)
    #sys.excepthook = excepthook

    exit_code = -1
    delay = 2
    for i in range(5):
        logging.info('Starting')
        exit_code = app.exec_()
        if exit_code == 0:
            break
        logging.info(f'Exit loop {exit_code}, sleeping {delay}')
        time.sleep(delay)
        delay = delay**2

    logging.info(f'Exited: {exit_code}')
    sys.exit(exit_code)
Ejemplo n.º 13
0
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        view = QGraphicsView()
        self.scene = QGraphicsScene()
        self.scene.setSceneRect(QRectF(0, 0, *WINDOW_SIZE))

        felt = QBrush(QPixmap(os.path.join('images', 'felt.png')))
        self.scene.setBackgroundBrush(felt)

        name = QGraphicsPixmapItem()
        name.setPixmap(QPixmap(os.path.join('images', 'ronery.png')))
        name.setPos(QPointF(170, 375))
        self.scene.addItem(name)

        view.setScene(self.scene)

        # Timer for the win animation only.
        self.timer = QTimer()
        self.timer.setInterval(5)
        self.timer.timeout.connect(self.win_animation)

        self.animation_event_cover = AnimationCover()
        self.scene.addItem(self.animation_event_cover)

        menu = self.menuBar().addMenu("&Game")

        deal_action = QAction(
            QIcon(os.path.join('images', 'playing-card.png')), "Deal...", self)
        deal_action.triggered.connect(self.restart_game)
        menu.addAction(deal_action)

        menu.addSeparator()

        deal1_action = QAction("1 card", self)
        deal1_action.setCheckable(True)
        deal1_action.triggered.connect(lambda: self.set_deal_n(1))
        menu.addAction(deal1_action)

        deal3_action = QAction("3 card", self)
        deal3_action.setCheckable(True)
        deal3_action.setChecked(True)
        deal3_action.triggered.connect(lambda: self.set_deal_n(3))

        menu.addAction(deal3_action)

        dealgroup = QActionGroup(self)
        dealgroup.addAction(deal1_action)
        dealgroup.addAction(deal3_action)
        dealgroup.setExclusive(True)

        menu.addSeparator()

        rounds3_action = QAction("3 rounds", self)
        rounds3_action.setCheckable(True)
        rounds3_action.setChecked(True)
        rounds3_action.triggered.connect(lambda: self.set_rounds_n(3))
        menu.addAction(rounds3_action)

        rounds5_action = QAction("5 rounds", self)
        rounds5_action.setCheckable(True)
        rounds5_action.triggered.connect(lambda: self.set_rounds_n(5))
        menu.addAction(rounds5_action)

        roundsu_action = QAction("Unlimited rounds", self)
        roundsu_action.setCheckable(True)
        roundsu_action.triggered.connect(lambda: self.set_rounds_n(None))
        menu.addAction(roundsu_action)

        roundgroup = QActionGroup(self)
        roundgroup.addAction(rounds3_action)
        roundgroup.addAction(rounds5_action)
        roundgroup.addAction(roundsu_action)
        roundgroup.setExclusive(True)

        menu.addSeparator()

        quit_action = QAction("Quit", self)
        quit_action.triggered.connect(self.quit)
        menu.addAction(quit_action)

        self.deck = []
        self.deal_n = 3  # Number of cards to deal each time
        self.rounds_n = 3  # Number of rounds (restacks) before end.

        for suit in SUITS:
            for value in range(1, 14):
                card = Card(value, suit)
                self.deck.append(card)
                self.scene.addItem(card)
                card.signals.doubleclicked.connect(
                    lambda card=card: self.auto_drop_card(card))

        self.setCentralWidget(view)
        self.setFixedSize(*WINDOW_SIZE)

        self.deckstack = DeckStack()
        self.deckstack.setPos(OFFSET_X, OFFSET_Y)
        self.scene.addItem(self.deckstack)

        # Set up the working locations.
        self.works = []
        for n in range(7):
            stack = WorkStack()
            stack.setPos(OFFSET_X + CARD_SPACING_X * n, WORK_STACK_Y)
            self.scene.addItem(stack)
            self.works.append(stack)

        self.drops = []
        # Set up the drop locations.
        for n in range(4):
            stack = DropStack()
            stack.setPos(OFFSET_X + CARD_SPACING_X * (3 + n), OFFSET_Y)
            stack.signals.complete.connect(self.check_win_condition)

            self.scene.addItem(stack)
            self.drops.append(stack)

        # Add the deal location.
        self.dealstack = DealStack()
        self.dealstack.setPos(OFFSET_X + CARD_SPACING_X, OFFSET_Y)
        self.scene.addItem(self.dealstack)

        # Add the deal click-trigger.
        dealtrigger = DealTrigger()
        dealtrigger.signals.clicked.connect(self.deal)
        self.scene.addItem(dealtrigger)

        self.shuffle_and_stack()

        self.setWindowTitle("Ronery")
        self.show()
Ejemplo n.º 14
0
class ViewMenu(QMenu):
    font_size_setting = 0  # 0, 1, 2 Small, Standard, Big

    def __init__(self, ui, menu_name: str = _('Ansicht')):
        super(ViewMenu, self).__init__(menu_name, ui)
        self.ui = ui

        # --- App style ---
        self.addSeparator().setText(_('Anwendungs-Stil'))
        style_grp = QActionGroup(self)
        self.default_style = QAction(_('Standard'), style_grp)
        self.default_style.setCheckable(True)
        self.default_style.triggered.connect(self.switch_default_style)

        self.dark_style = QAction(_('Dunkel'), style_grp)
        self.dark_style.setCheckable(True)
        self.dark_style.triggered.connect(self.switch_dark_style)

        self.addActions([self.default_style, self.dark_style])

        # --- Font Size ---
        self.addSeparator().setText(_('Schrifgröße'))
        font_grp = QActionGroup(self)
        self.small_font = QAction(_('Klein'), font_grp)
        self.small_font.setCheckable(True)
        self.default_font = QAction(_('Standard'), font_grp)
        self.default_font.setCheckable(True)
        self.big_font = QAction(_('Groß'), font_grp)
        self.big_font.setCheckable(True)

        font_grp.triggered.connect(self.switch_font_size)
        self.addActions([self.small_font, self.default_font, self.big_font])

        self.display_current_style()

    def display_current_style(self):
        """ Set action checked according to KnechtSettings """

        if KnechtSettings.app.get('app_style') == 'fusion-dark':
            self.dark_style.setChecked(True)
        else:
            self.default_style.setChecked(True)

        if KnechtSettings.app['font_size'] == FontRsc.small_pixel_size:
            self.small_font.setChecked(True)
            self.font_size_setting = 0
        elif KnechtSettings.app['font_size'] == FontRsc.regular_pixel_size:
            self.default_font.setChecked(True)
            self.font_size_setting = 1
        elif KnechtSettings.app['font_size'] == FontRsc.big_pixel_size:
            self.big_font.setChecked(True)
            self.font_size_setting = 2

    def switch_default_style(self):
        self.ui.app.set_default_style()
        self.set_app_font(self.font_size_setting)

    def switch_dark_style(self):
        self.ui.app.set_dark_style()
        self.set_app_font(self.font_size_setting)

    def switch_font_size(self, action: QAction):
        action.setChecked(True)

        if action is self.small_font:
            self.set_app_font(0)
        elif action is self.default_font:
            self.set_app_font(1)
        elif action is self.big_font:
            self.set_app_font(2)

    def set_app_font(self, size: int=0):
        self.font_size_setting = size

        if size == 0:
            font_size = FontRsc.small_pixel_size
        elif size == 1:
            font_size = FontRsc.regular_pixel_size
        elif size == 2:
            font_size = FontRsc.big_pixel_size

        KnechtSettings.app['font_size'] = font_size

        FontRsc.init(font_size)
        self.ui.app.setFont(FontRsc.regular)
        title = _('Neustart')
        msg = _('Anwendungstil geändert. Für eine vollständige Übernahme muss die Anwendung neu gestartet werden.<br>'
                'Anwendung jetzt neustarten?')
        ok_btn = _('Neustarten')
        no_btn = _('Später neustarten..')

        msg_box = AskToContinue(self.ui)
        if msg_box.ask(title, msg, ok_btn, no_btn):
            restart_knecht_app(self.ui)
Ejemplo n.º 15
0
    def init_ui(self):

        self.setWindowTitle('Trace Event Window')
        self.setGeometry(100, 100, 800, 600)

        bar = self.menuBar()

        file_ = bar.addMenu('File')
        export_log = QAction('Save to File',
                             self,
                             triggered=lambda: self.save_log())

        options = bar.addMenu('Options')
        auto_refresh = QAction(
            'Auto Refresh',
            self,
            checkable=True,
            triggered=lambda: self.timer.start(100)
            if auto_refresh.isChecked() else self.timer.stop())
        auto_refresh.setChecked(True)

        options.addAction(auto_refresh)
        file_.addAction(export_log)

        vgrid = QVBoxLayout()
        grid = QHBoxLayout()

        self.tree = QTreeWidget()
        self.tree.setHeaderLabels(['Name'])

        self.top = []
        self.lst = []

        for n, event in enumerate(self.trace_events):
            word = event.split('_')[0]
            if word not in self.top:
                self.top.append(word)
                item = QTreeWidgetItem(self.tree)
                self.lst.append(item)
                item.setText(0, word)
            subitem = QTreeWidgetItem(item)
            subitem.setText(0, '    ' + event.split(' : ')[0])
            # subitem.setCheckState(0, Qt.Unchecked)
            cbox = QCheckBox()
            cbox.stateChanged.connect(lambda state, text=subitem.text(0): self.
                                      handle_checked(state, text))
            self.tree.setItemWidget(subitem, 0, cbox)

        # self.tree.setColumnWidth(0, 25)

        self.tracelist = QLabel()
        self.disp_output()

        self.traceview = QScrollArea()
        self.traceview.setWidget(self.tracelist)
        self.traceview.setWidgetResizable(True)

        search = QHBoxLayout()

        self.search_bar = QLineEdit(self)

        self.completer = QCompleter(self.top, self)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)

        self.search_bar.setCompleter(self.completer)

        search_button = QPushButton('Search')
        search_button.clicked.connect(lambda: self.tree.setCurrentItem(
            self.lst[self.top.index(self.search_bar.text())]))

        expand = QPushButton('▼')
        expand.setFixedSize(QSize(25, 25))
        expand.clicked.connect(lambda: self.tree.expandAll())

        collapse = QPushButton('▲')
        collapse.setFixedSize(QSize(25, 25))
        collapse.clicked.connect(lambda: self.tree.collapseAll())

        self.search_bar.returnPressed.connect(lambda: search_button.click())

        search.addWidget(self.search_bar)
        search.addWidget(search_button)
        search.addWidget(expand)
        search.addWidget(collapse)

        self.digest = QLabel()

        vgrid.addLayout(search)
        vgrid.addWidget(self.tree)

        vgridwid = QWidget()
        vgridwid.setLayout(vgrid)

        split = QSplitter(Qt.Horizontal)

        split.addWidget(vgridwid)
        split.addWidget(self.traceview)

        split.setStretchFactor(1, 1)

        # grid.addLayout(vgrid)
        grid.addWidget(split)
        # grid.addWidget(self.tracelist)

        self.disp_output()

        center = QWidget()
        center.setLayout(grid)
        self.setCentralWidget(center)
        self.show()
Ejemplo n.º 16
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None, flags=None):
        super().__init__(parent)
        self.project_filename = None

        self.project_widget = ProjectWidget(self)
        self.setCentralWidget(self.project_widget)
        self.project_widget.project.curves_collection_changed.connect(
            self.curvesCollectionChanged)

        self.createActions()
        self.createToolBars()
        self.createStatusBar()
        self.createMenus()
        self.createDockWindows()

        self.setWindowTitle("WD Wrapper")

        self.readWindowSettings()
        self.readAppState()

        # open last fits
        # try:
        #     self.openLastFits()
        # except FileNotFoundError:
        #     print('Can not open last file')

    @Slot(Container)
    def currentItemChanged(self, item: Container):
        if isinstance(item, ParentColumnContainer):
            item = item.parent()
        self.delCurveAct.setEnabled(isinstance(item, CurveContainer))

    @Slot(CurveContainer)
    def curvesCollectionChanged(self, curves_model: CurvesModel):
        self.createPlotMenu(source=curves_model)
        # QMessageBox.information(self, 'collection changed', 'DEBUG: collection changed')

    @Slot(CurveContainer)
    def curvesPlotChanged(self, curves_model: CurvesModel):
        self.checkPlotInPlotMenu(source=curves_model)
        # QMessageBox.information(self, 'collection changed', 'DEBUG: collection changed')

    def closeEvent(self, event: PySide2.QtGui.QCloseEvent):
        self.writeAppState()
        self.writeWindowSettings()
        super().closeEvent(event)

    def keyPressEvent(self, e):
        # if e.key() == Qt.Key_Delete:
        #     self.deleteSelected()
        pass

    def print_(self):
        document = self.textEdit.document()
        printer = QPrinter()

        dlg = QPrintDialog(printer, self)
        if dlg.exec_() != QDialog.Accepted:
            return

        document.print_(printer)

        self.statusBar().showMessage("Ready", 2000)

    @Slot()
    def open_lcin(self):
        file_name, _ = QFileDialog.getOpenFileName(self.centralWidget(),
                                                   "Open lc.in", "./",
                                                   "lc.in (*)")
        if file_name:
            try:
                self.project_widget.project.load_bundle(file_name)
                logger().info(f'lc.in file opened, path: {file_name}')
            except (ValueError, FileFormatNotSupportedError,
                    FileFormatMultipleSetsError) as e:
                logger().exception(
                    f'lc.in file f{file_name} loading failed. Input file format error',
                    exc_info=e)
                msg = QMessageBox()
                msg.setWindowTitle('File loading failed')
                msg.setText('Input file format error:')
                msg.setInformativeText(str(e))
                msg.exec_()

    @Slot()
    def save_lcin(self):
        file_name, _ = QFileDialog.getSaveFileName(self, "Save lc.in", "lc.in",
                                                   "lc.in (*)")
        if file_name:
            self.project_widget.project.save_bundle(file_name)
            logger().info(f'lc.in file saved, path: {file_name}')

    @Slot()
    def open_prj(self):
        filename, _ = QFileDialog.getOpenFileName(
            self, 'Open Project', './', 'WD Wrapper Project (*.wdw)')
        if filename:
            if self.open_prj_from_file(filename):
                self.setWindowTitle(os.path.basename(filename))
                self.project_filename = filename

    @Slot()
    def save_prj_as(self):
        filename, _ = QFileDialog.getSaveFileName(
            self, "Save Project", './project.wdw',
            "WD Wrapper Project (*.wdw)")
        if filename:
            self.project_filename = filename
            self.setWindowTitle(os.path.basename(filename))
            self.save_prj_to_file(self.project_filename, mode='gui save as')

    @Slot()
    def save_prj(self):
        if self.project_filename is None:
            self.save_prj_as()
        else:
            self.save_prj_to_file(self.project_filename, mode='gui save')

    def save_prj_to_file(self, filename, mode):
        self.project_widget.project.save_project(filename, mode=mode)
        logger().info(f'Project saved, path: {filename}')

    def open_prj_from_file(self, filename):
        if self.project_widget.project.open_project(filename):
            logger().info(f'Project opened, path: {filename}')
            return True
        else:
            logger().error(f'Project opening failed, path: {filename}')
            return False

    def save(self):
        filename, _ = QFileDialog.getSaveFileName(self, "Choose a file name",
                                                  '.', "HTML (*.html *.htm)")
        if not filename:
            return

        file = QFile(filename)
        if not file.open(QFile.WriteOnly | QFile.Text):
            QMessageBox.warning(
                self, "Dock Widgets",
                "Cannot write file %s:\n%s." % (filename, file.errorString()))
            return

        out = QTextStream(file)
        QApplication.setOverrideCursor(Qt.WaitCursor)
        out << self.textEdit.toHtml()
        QApplication.restoreOverrideCursor()

        self.statusBar().showMessage("Saved '%s'" % filename, 2000)

    def readAppState(self):
        # if self.tedaCommandLine.ignoreSettings:
        #     return
        settings = QSettings()
        self.project_widget.restore_session(settings)
        # settings.beginGroup("WCS")
        # self.wcsSexAct.setChecked(bool(settings.value("sexagesimal", True)))
        # self.wcsGridAct.setChecked(bool(settings.value("grid", False)))
        # settings.endGroup()

    def writeAppState(self):
        # if self.tedaCommandLine.ignoreSettings:
        #     return
        settings = QSettings()
        self.project_widget.save_session(settings)
        # settings.beginGroup("WCS")
        # settings.setValue("sexagesimal", self.wcsSexAct.isChecked())
        # settings.setValue("grid", self.wcsGridAct.isChecked())
        # settings.endGroup()

    def undo(self):
        document = self.textEdit.document()
        document.undo()

    def about(self):
        QMessageBox.about(
            self, "WD Wrapper", f"WD Wrapper  {__version__} <br/>"
            "Authors: <ul> "
            "<li>Mikołaj Kałuszyński</li>"
            "</ul>"
            "Created by <a href='https://akond.com'>Akond Lab</a> for The Araucaria Project"
        )

    # def on_console_show(self):
    #     self.console.show(window=self, )

    def createActions(self):
        self.openlcinAct = QAction(IconFactory.getIcon('open_lc'),
                                   "&Open lc.in",
                                   self,
                                   shortcut=QKeySequence.Open,
                                   statusTip="Open lc.in file",
                                   triggered=self.open_lcin)
        self.savelcinAct = QAction(IconFactory.getIcon('save_lc'),
                                   "&Save lc.in as",
                                   self,
                                   shortcut=QKeySequence.Save,
                                   statusTip="Save lc.in file",
                                   triggered=self.save_lcin)
        self.openProjectAct = QAction(IconFactory.getIcon('open_prj'),
                                      "Open &project",
                                      self,
                                      statusTip="Open project",
                                      triggered=self.open_prj)
        self.saveProjectAct = QAction(IconFactory.getIcon('save_prj'),
                                      "S&ave project",
                                      self,
                                      statusTip="Save project",
                                      triggered=self.save_prj)
        self.saveProjectAsAct = QAction(IconFactory.getIcon('save_prj'),
                                        "S&ave project as...",
                                        self,
                                        statusTip="Save project to new file",
                                        triggered=self.save_prj_as)
        self.autoSaveProjectAct = QAction(
            None,
            "Auto save project",
            self,
            statusTip="Automatically save project")
        self.autoSaveProjectAct.setCheckable(True)
        self.autoSaveProjectAct.setChecked(False)

        self.addLightCurveAct = QAction(IconFactory.getIcon('note_add'),
                                        "Add &LC",
                                        self,
                                        statusTip="Add light curve",
                                        triggered=self.project_widget.add_lc)
        self.addRvCurveAct = QAction(IconFactory.getIcon('note_add'),
                                     "Add &RV",
                                     self,
                                     statusTip="Add radial velocity curve",
                                     triggered=self.project_widget.add_rv)
        self.delCurveAct = QAction(IconFactory.getIcon('note_del'),
                                   "Delete Curve",
                                   self,
                                   statusTip="Delete selected curve",
                                   triggered=self.project_widget.del_curve)
        self.delCurveAct.setEnabled(False)

        self.quitAct = QAction("&Quit",
                               self,
                               shortcut="Ctrl+Q",
                               statusTip="Quit the application",
                               triggered=self.close)
        self.aboutAct = QAction("&About",
                                self,
                                statusTip="Show the application's About box",
                                triggered=self.about)
        self.aboutQtAct = QAction("About &Qt",
                                  self,
                                  statusTip="Show the Qt library's About box",
                                  triggered=QApplication.instance().aboutQt)

        # self.qtConsoleAct = QAction('Python Console', self,
        #                             statusTip="Open IPython console window", triggered=self.on_console_show)

        # self.wcsSexAct = QAction('Sexagesimal', self,
        #                          statusTip="Format WCS coordinates as sexagesimal (RA in hour angle) instead of decimal deg")
        # self.wcsSexAct.toggled.connect(self.on_sex_toggle)
        # self.wcsSexAct.setCheckable(True)

    def createMenus(self):
        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenu.addAction(self.openlcinAct)
        self.fileMenu.addAction(self.savelcinAct)

        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.openProjectAct)
        self.fileMenu.addAction(self.saveProjectAct)
        self.fileMenu.addAction(self.saveProjectAsAct)
        self.fileMenu.addAction(self.autoSaveProjectAct)

        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.quitAct)

        self.curvesMenu = self.menuBar().addMenu("&Curves")
        self.curvesMenu.addAction(self.addLightCurveAct)
        self.curvesMenu.addAction(self.addRvCurveAct)

        self.plotMenu = self.menuBar().addMenu("&Plot")

        self.viewMenu = self.menuBar().addMenu("&View")
        # self.viewMenu.addAction(self.qtConsoleAct)
        # self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.fileToolBar.toggleViewAction())
        self.viewMenu.addAction(self.curvesToolBar.toggleViewAction())

        self.menuBar().addSeparator()

        self.helpMenu = self.menuBar().addMenu("&Help")
        self.helpMenu.addAction(self.aboutAct)
        self.helpMenu.addAction(self.aboutQtAct)

    def createToolBars(self):
        self.fileToolBar = self.addToolBar("File Toolbar")
        self.fileToolBar.setObjectName("FILE TOOLBAR")
        self.fileToolBar.addAction(self.openProjectAct)
        self.fileToolBar.addAction(self.saveProjectAct)
        self.fileToolBar.addAction(self.openlcinAct)
        self.fileToolBar.addAction(self.savelcinAct)

        self.curvesToolBar = self.addToolBar("Curves Toolbar")
        self.curvesToolBar.setObjectName("CURVES TOOLBAR")
        self.curvesToolBar.addAction(self.addLightCurveAct)
        self.curvesToolBar.addAction(self.addRvCurveAct)
        self.curvesToolBar.addAction(self.delCurveAct)

    def createStatusBar(self):
        self.statusBar().showMessage("Ready")

    def createDockWindows(self):
        # Info
        dock = QDockWidget('Details', self)
        dock.setObjectName("DETAILS")
        dock.setAllowedAreas(Qt.AllDockWidgetAreas)
        self.detailsWidget = InfoPanelWidget(self)
        self.project_widget.treeCurrentItemChanged.connect(
            self.detailsWidget.setItem)
        self.project_widget.treeCurrentItemChanged.connect(
            self.currentItemChanged)
        dock.setWidget(self.detailsWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, dock)
        self.viewMenu.addAction(dock.toggleViewAction())
        # dock.setFloating(True)
        # dock.hide()

        # Scale
        # dock = QDockWidget("Dynamic Scale", self)
        # dock.setObjectName("SCALE")
        # dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea | Qt.TopDockWidgetArea)
        # self.scaleWidget = ScaleWidget(self, scales_model=self.scales_model, cmap_model=self.cmaps)
        # dock.setWidget(self.scaleWidget)
        # self.addDockWidget(Qt.RightDockWidgetArea, dock)
        # self.viewMenu.addAction(dock.toggleViewAction())
        # dock.setFloating(True)
        # dock.hide()

        # #radial profiles
        # dock = QDockWidget("Radial Profile Fit", self)
        # dock.setObjectName("RADIAL_PROFILE_IRAF")
        # dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea | Qt.TopDockWidgetArea)
        # self.radial_profile_iraf_widget = IRAFRadialProfileWidget(self.fits_image.data)
        # dock.setWidget(self.radial_profile_iraf_widget)
        # self.addDockWidget(Qt.RightDockWidgetArea, dock)
        # self.viewMenu.addAction(dock.toggleViewAction())
        # self.dockRadialFit = dock

    def createPlotMenu(self, source: CurvesModel):
        self.plotMenu.clear()
        light_curves = []
        rv_curves = []
        for c in source.curves_iter():
            if c.is_rv():
                rv_curves.append(c)
            else:
                light_curves.append(c)
        for c in light_curves + [None] + rv_curves:
            if c is None:
                self.plotMenu.addSeparator()
            else:
                action = ConnectedCheckableAction(c.objectName())
                connector = TraitletsModelConnector('plot')
                action.model_connector = connector
                connector.connect_model(c.content)
                self.plotMenu.addAction(action)
                # a = self.plotMenu.addAction(c.objectName())
                # a.setData(id(c))
                # a.setCheckable(True)
                # c.content.observe(lambda change: self.curvesPlotChanged(source))
        # self.checkPlotInPlotMenu(source)

    # def _plotMenuCurvesActions(self) -> Mapping[int, QAction]:
    #     """plotMenu actions indexed by Data: CurveContainer's id """
    #     return {a.data(): a for a in  self.plotMenu.actions()}

    # def checkPlotInPlotMenu(self, source: CurvesModel):
    #     actions = self._plotMenuCurvesActions()
    #     for c in source.curves_iter():
    #         try:
    #             menu_action = actions[id(c)]
    #             menu_action.setChecked(c.plot)
    #         except KeyError:
    #             pass

    # noinspection PyTypeChecker
    def readWindowSettings(self):
        # if self.tedaCommandLine.ignoreSettings:
        #     return
        settings = QSettings()
        settings.beginGroup("MainWindow")
        size, pos = settings.value("size"), settings.value("pos")
        settings.endGroup()
        if size is not None and pos is not None:
            print('settings: resize to {} and move to {}', size, pos)
            self.move(pos)
            # self.resize(size)
            print('Size reported ', self.size())
            print('Size set ', size)
            self.resize(size)
            print('Size reported ', self.size())
        else:
            self.resize(800, 600)

        geometry = settings.value("geometry")
        if geometry is not None:
            self.restoreGeometry(geometry)
            self.restoreState(settings.value("windowState"))

    def writeWindowSettings(self):
        # if self.tedaCommandLine.ignoreSettings:
        #     return
        settings = QSettings()
        settings.beginGroup("MainWindow")
        settings.setValue("size", self.size())
        settings.setValue("pos", self.pos())
        settings.endGroup()

        settings.setValue('geometry', self.saveGeometry())
        settings.setValue('windowState', self.saveState())
Ejemplo n.º 17
0
class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowIcon(QIcon(":/icons/apps/16/tabulator.svg"))

        self._recentDocuments = []
        self._actionRecentDocuments = []
        self._keyboardShortcutsDialog = None

        self._preferences = Preferences()
        self._preferences.loadSettings()

        self._createActions()
        self._createMenus()
        self._createToolBars()

        self._loadSettings()

        self._updateActions()
        self._updateActionFullScreen()
        self._updateMenuOpenRecent()

        # Central widget
        self._documentArea = QMdiArea()
        self._documentArea.setViewMode(QMdiArea.TabbedView)
        self._documentArea.setTabsMovable(True)
        self._documentArea.setTabsClosable(True)
        self.setCentralWidget(self._documentArea)
        self._documentArea.subWindowActivated.connect(self._onDocumentWindowActivated)


    def closeEvent(self, event):

        if True:
            # Store application properties and preferences
            self._saveSettings()
            self._preferences.saveSettings()

            event.accept()
        else:
            event.ignore()


    def _loadSettings(self):

        settings = QSettings()

        # Recent documents
        size = settings.beginReadArray("RecentDocuments")
        for idx in range(size-1, -1, -1):
            settings.setArrayIndex(idx)
            canonicalName = QFileInfo(settings.value("Document")).canonicalFilePath()
            self._updateRecentDocuments(canonicalName)
        settings.endArray()

        # Application properties: Geometry
        geometry = settings.value("Application/Geometry", QByteArray()) if self._preferences.restoreApplicationGeometry() else QByteArray()
        if not geometry.isEmpty():
            self.restoreGeometry(geometry)
        else:
            availableGeometry = self.screen().availableGeometry()
            self.resize(availableGeometry.width() * 2/3, availableGeometry.height() * 2/3)
            self.move((availableGeometry.width() - self.width()) / 2, (availableGeometry.height() - self.height()) / 2)

        # Application properties: State
        state = settings.value("Application/State", QByteArray()) if self._preferences.restoreApplicationState() else QByteArray()
        if not state.isEmpty():
            self.restoreState(state)
        else:
            self._toolbarApplication.setVisible(True)
            self._toolbarDocument.setVisible(True)
            self._toolbarEdit.setVisible(True)
            self._toolbarTools.setVisible(True)
            self._toolbarView.setVisible(False)
            self._toolbarHelp.setVisible(False)


    def _saveSettings(self):

        settings = QSettings()

        # Recent documents
        if not self._preferences.restoreRecentDocuments():
            self._recentDocuments.clear()
        settings.remove("RecentDocuments")
        settings.beginWriteArray("RecentDocuments")
        for idx in range(len(self._recentDocuments)):
            settings.setArrayIndex(idx)
            settings.setValue("Document", self._recentDocuments[idx])
        settings.endArray()

        # Application properties: Geometry
        geometry = self.saveGeometry() if self._preferences.restoreApplicationGeometry() else QByteArray()
        settings.setValue("Application/Geometry", geometry)

        # Application properties: State
        state = self.saveState() if self._preferences.restoreApplicationState() else QByteArray()
        settings.setValue("Application/State", state)


    def _createActions(self):

        #
        # Actions: Application

        self._actionAbout = QAction(self.tr("About {0}").format(QApplication.applicationName()), self)
        self._actionAbout.setObjectName("actionAbout")
        self._actionAbout.setIcon(QIcon(":/icons/apps/16/tabulator.svg"))
        self._actionAbout.setIconText(self.tr("About"))
        self._actionAbout.setToolTip(self.tr("Brief description of the application"))
        self._actionAbout.triggered.connect(self._onActionAboutTriggered)

        self._actionColophon = QAction(self.tr("Colophon"), self)
        self._actionColophon.setObjectName("actionColophon")
        self._actionColophon.setToolTip(self.tr("Lengthy description of the application"))
        self._actionColophon.triggered.connect(self._onActionColophonTriggered)

        self._actionPreferences = QAction(self.tr("Preferences…"), self)
        self._actionPreferences.setObjectName("actionPreferences")
        self._actionPreferences.setIcon(QIcon.fromTheme("configure", QIcon(":/icons/actions/16/application-configure.svg")))
        self._actionPreferences.setToolTip(self.tr("Customize the appearance and behavior of the application"))
        self._actionPreferences.triggered.connect(self._onActionPreferencesTriggered)

        self._actionQuit = QAction(self.tr("Quit"), self)
        self._actionQuit.setObjectName("actionQuit")
        self._actionQuit.setIcon(QIcon.fromTheme("application-exit", QIcon(":/icons/actions/16/application-exit.svg")))
        self._actionQuit.setShortcut(QKeySequence.Quit)
        self._actionQuit.setToolTip(self.tr("Quit the application"))
        self._actionQuit.triggered.connect(self.close)

        #
        # Actions: Document

        self._actionNew = QAction(self.tr("New"), self)
        self._actionNew.setObjectName("actionNew")
        self._actionNew.setIcon(QIcon.fromTheme("document-new", QIcon(":/icons/actions/16/document-new.svg")))
        self._actionNew.setShortcut(QKeySequence.New)
        self._actionNew.setToolTip(self.tr("Create new document"))
        self._actionNew.triggered.connect(self._onActionNewTriggered)

        self._actionOpen = QAction(self.tr("Open…"), self)
        self._actionOpen.setObjectName("actionOpen")
        self._actionOpen.setIcon(QIcon.fromTheme("document-open", QIcon(":/icons/actions/16/document-open.svg")))
        self._actionOpen.setShortcut(QKeySequence.Open)
        self._actionOpen.setToolTip(self.tr("Open an existing document"))
        self._actionOpen.triggered.connect(self._onActionOpenTriggered)

        self._actionOpenRecentClear = QAction(self.tr("Clear List"), self)
        self._actionOpenRecentClear.setObjectName("actionOpenRecentClear")
        self._actionOpenRecentClear.setToolTip(self.tr("Clear document list"))
        self._actionOpenRecentClear.triggered.connect(self._onActionOpenRecentClearTriggered)

        self._actionSave = QAction(self.tr("Save"), self)
        self._actionSave.setObjectName("actionSave")
        self._actionSave.setIcon(QIcon.fromTheme("document-save", QIcon(":/icons/actions/16/document-save.svg")))
        self._actionSave.setShortcut(QKeySequence.Save)
        self._actionSave.setToolTip(self.tr("Save document"))
        self._actionSave.triggered.connect(self._onActionSaveTriggered)

        self._actionSaveAs = QAction(self.tr("Save As…"), self)
        self._actionSaveAs.setObjectName("actionSaveAs")
        self._actionSaveAs.setIcon(QIcon.fromTheme("document-save-as", QIcon(":/icons/actions/16/document-save-as.svg")))
        self._actionSaveAs.setShortcut(QKeySequence.SaveAs)
        self._actionSaveAs.setToolTip(self.tr("Save document under a new name"))
        self._actionSaveAs.triggered.connect(self._onActionSaveAsTriggered)

        self._actionSaveAsDelimiterColon = QAction(self.tr("Colon"), self)
        self._actionSaveAsDelimiterColon.setObjectName("actionSaveAsDelimiterColon")
        self._actionSaveAsDelimiterColon.setCheckable(True)
        self._actionSaveAsDelimiterColon.setToolTip(self.tr("Save document with colon as delimiter under a new name"))
        self._actionSaveAsDelimiterColon.setData("colon")
        self._actionSaveAsDelimiterColon.triggered.connect(lambda: self._onActionSaveAsDelimiterTriggered("colon") )

        self._actionSaveAsDelimiterComma = QAction(self.tr("Comma"), self)
        self._actionSaveAsDelimiterComma.setObjectName("actionSaveAsDelimiterComma")
        self._actionSaveAsDelimiterComma.setCheckable(True)
        self._actionSaveAsDelimiterComma.setToolTip(self.tr("Save document with comma as delimiter under a new name"))
        self._actionSaveAsDelimiterComma.setData("comma")
        self._actionSaveAsDelimiterComma.triggered.connect(lambda: self._onActionSaveAsDelimiterTriggered("comma") )

        self._actionSaveAsDelimiterSemicolon = QAction(self.tr("Semicolon"), self)
        self._actionSaveAsDelimiterSemicolon.setObjectName("actionSaveAsDelimiterSemicolon")
        self._actionSaveAsDelimiterSemicolon.setCheckable(True)
        self._actionSaveAsDelimiterSemicolon.setToolTip(self.tr("Save document with semicolon as delimiter under a new name"))
        self._actionSaveAsDelimiterSemicolon.setData("semicolon")
        self._actionSaveAsDelimiterSemicolon.triggered.connect(lambda: self._onActionSaveAsDelimiterTriggered("semicolon") )

        self._actionSaveAsDelimiterTab = QAction(self.tr("Tab"), self)
        self._actionSaveAsDelimiterTab.setObjectName("actionSaveAsDelimiterTab")
        self._actionSaveAsDelimiterTab.setCheckable(True)
        self._actionSaveAsDelimiterTab.setToolTip(self.tr("Save document with tab as delimiter under a new name"))
        self._actionSaveAsDelimiterTab.setData("tab")
        self._actionSaveAsDelimiterTab.triggered.connect(lambda: self._onActionSaveAsDelimiterTriggered("tab") )

        self._actionSaveAsDelimiter = QActionGroup(self)
        self._actionSaveAsDelimiter.setObjectName("actionSaveAsDelimiter")
        self._actionSaveAsDelimiter.addAction(self._actionSaveAsDelimiterColon)
        self._actionSaveAsDelimiter.addAction(self._actionSaveAsDelimiterComma)
        self._actionSaveAsDelimiter.addAction(self._actionSaveAsDelimiterSemicolon)
        self._actionSaveAsDelimiter.addAction(self._actionSaveAsDelimiterTab)

        self._actionSaveCopyAs = QAction(self.tr("Save Copy As…"), self)
        self._actionSaveCopyAs.setObjectName("actionSaveCopyAs")
        self._actionSaveCopyAs.setIcon(QIcon.fromTheme("document-save-as", QIcon(":/icons/actions/16/document-save-as.svg")))
        self._actionSaveCopyAs.setToolTip(self.tr("Save copy of document under a new name"))
        self._actionSaveCopyAs.triggered.connect(self._onActionSaveCopyAsTriggered)

        self._actionSaveAll = QAction(self.tr("Save All"), self)
        self._actionSaveAll.setObjectName("actionSaveAll")
        self._actionSaveAll.setIcon(QIcon.fromTheme("document-save-all", QIcon(":/icons/actions/16/document-save-all.svg")))
        self._actionSaveAll.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L))
        self._actionSaveAll.setToolTip(self.tr("Save all documents"))
        self._actionSaveAll.triggered.connect(self._onActionSaveAllTriggered)

        self._actionClose = QAction(self.tr("Close"), self)
        self._actionClose.setObjectName("actionClose")
        self._actionClose.setIcon(QIcon.fromTheme("document-close", QIcon(":/icons/actions/16/document-close.svg")))
        self._actionClose.setShortcut(QKeySequence.Close)
        self._actionClose.setToolTip(self.tr("Close document"))
        self._actionClose.triggered.connect(self._onActionCloseTriggered)

        self._actionCloseOther = QAction(self.tr("Close Other"), self)
        self._actionCloseOther.setObjectName("actionCloseOther")
        self._actionCloseOther.setToolTip(self.tr("Close all other documents"))
        self._actionCloseOther.triggered.connect(self._onActionCloseOtherTriggered)

        self._actionCloseAll = QAction(self.tr("Close All"), self)
        self._actionCloseAll.setObjectName("actionCloseAll")
        self._actionCloseAll.setShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_W))
        self._actionCloseAll.setToolTip(self.tr("Close all documents"))
        self._actionCloseAll.triggered.connect(self._onActionCloseAllTriggered)

        #
        # Actions: View

        self._actionFullScreen = QAction(self)
        self._actionFullScreen.setObjectName("actionFullScreen")
        self._actionFullScreen.setIconText(self.tr("Full Screen"))
        self._actionFullScreen.setCheckable(True)
        self._actionFullScreen.setShortcuts([QKeySequence(Qt.Key_F11), QKeySequence.FullScreen])
        self._actionFullScreen.triggered.connect(self._onActionFullScreenTriggered)

        self._actionTitlebarFullPath = QAction(self.tr("Show Path in Titlebar"), self)
        self._actionTitlebarFullPath.setObjectName("actionTitlebarFullPath")
        self._actionTitlebarFullPath.setCheckable(True)
        self._actionTitlebarFullPath.setChecked(True)
        self._actionTitlebarFullPath.setToolTip(self.tr("Display the full path of the document in the titlebar"))
        self._actionTitlebarFullPath.triggered.connect(self._onActionTitlebarFullPathTriggered)

        self._actionToolbarApplication = QAction(self.tr("Show Application Toolbar"), self)
        self._actionToolbarApplication.setObjectName("actionToolbarApplication")
        self._actionToolbarApplication.setCheckable(True)
        self._actionToolbarApplication.setToolTip(self.tr("Display the Application toolbar"))
        self._actionToolbarApplication.toggled.connect(lambda checked: self._toolbarApplication.setVisible(checked))

        self._actionToolbarDocument = QAction(self.tr("Show Document Toolbar"), self)
        self._actionToolbarDocument.setObjectName("actionToolbarDocument")
        self._actionToolbarDocument.setCheckable(True)
        self._actionToolbarDocument.setToolTip(self.tr("Display the Document toolbar"))
        self._actionToolbarDocument.toggled.connect(lambda checked: self._toolbarDocument.setVisible(checked))

        self._actionToolbarEdit = QAction(self.tr("Show Edit Toolbar"), self)
        self._actionToolbarEdit.setObjectName("actionToolbarEdit")
        self._actionToolbarEdit.setCheckable(True)
        self._actionToolbarEdit.setToolTip(self.tr("Display the Edit toolbar"))
        self._actionToolbarEdit.toggled.connect(lambda checked: self._toolbarEdit.setVisible(checked))

        self._actionToolbarTools = QAction(self.tr("Show Tools Toolbar"), self)
        self._actionToolbarTools.setObjectName("actionToolbarTools")
        self._actionToolbarTools.setCheckable(True)
        self._actionToolbarTools.setToolTip(self.tr("Display the Tools toolbar"))
        self._actionToolbarTools.toggled.connect(lambda checked: self._toolbarTools.setVisible(checked))

        self._actionToolbarView = QAction(self.tr("Show View Toolbar"), self)
        self._actionToolbarView.setObjectName("actionToolbarView")
        self._actionToolbarView.setCheckable(True)
        self._actionToolbarView.setToolTip(self.tr("Display the View toolbar"))
        self._actionToolbarView.toggled.connect(lambda checked: self._toolbarView.setVisible(checked))

        self._actionToolbarHelp = QAction(self.tr("Show Help Toolbar"), self)
        self._actionToolbarHelp.setObjectName("actionToolbarHelp")
        self._actionToolbarHelp.setCheckable(True)
        self._actionToolbarHelp.setToolTip(self.tr("Display the Help toolbar"))
        self._actionToolbarHelp.toggled.connect(lambda checked: self._toolbarHelp.setVisible(checked))

        #
        # Actions: Help

        self._actionKeyboardShortcuts = QAction(self.tr("Keyboard Shortcuts"), self)
        self._actionKeyboardShortcuts.setObjectName("actionKeyboardShortcuts")
        self._actionKeyboardShortcuts.setIcon(QIcon.fromTheme("help-keyboard-shortcuts", QIcon(":/icons/actions/16/help-keyboard-shortcuts.svg")))
        self._actionKeyboardShortcuts.setIconText(self.tr("Shortcuts"))
        self._actionKeyboardShortcuts.setToolTip(self.tr("List of all keyboard shortcuts"))
        self._actionKeyboardShortcuts.triggered.connect(self._onActionKeyboardShortcutsTriggered)


    def _createMenus(self):

        # Menu: Application
        menuApplication = self.menuBar().addMenu(self.tr("Application"))
        menuApplication.setObjectName("menuApplication")
        menuApplication.addAction(self._actionAbout)
        menuApplication.addAction(self._actionColophon)
        menuApplication.addSeparator()
        menuApplication.addAction(self._actionPreferences)
        menuApplication.addSeparator()
        menuApplication.addAction(self._actionQuit)

        #
        # Menu: Document

        self._menuOpenRecent = QMenu(self.tr("Open Recent"), self)
        self._menuOpenRecent.setObjectName("menuOpenRecent")
        self._menuOpenRecent.setIcon(QIcon.fromTheme("document-open-recent", QIcon(":/icons/actions/16/document-open-recent.svg")))
        self._menuOpenRecent.setToolTip(self.tr("Open a document which was recently opened"))

        self._menuSaveAsDelimiter = QMenu(self.tr("Save As with Delimiter…"), self)
        self._menuSaveAsDelimiter.setObjectName("menuSaveAsDelimiter")
        self._menuSaveAsDelimiter.setIcon(QIcon.fromTheme("document-save-as", QIcon(":/icons/actions/16/document-save-as.svg")))
        self._menuSaveAsDelimiter.setToolTip(self.tr("Save document with specific delimiter under a new name"))
        self._menuSaveAsDelimiter.addActions(self._actionSaveAsDelimiter.actions())

        menuDocument = self.menuBar().addMenu(self.tr("Document"))
        menuDocument.setObjectName("menuDocument")
        menuDocument.addAction(self._actionNew)
        menuDocument.addSeparator()
        menuDocument.addAction(self._actionOpen)
        menuDocument.addMenu(self._menuOpenRecent)
        menuDocument.addSeparator()
        menuDocument.addAction(self._actionSave)
        menuDocument.addAction(self._actionSaveAs)
        menuDocument.addMenu(self._menuSaveAsDelimiter)
        menuDocument.addAction(self._actionSaveCopyAs)
        menuDocument.addAction(self._actionSaveAll)
        menuDocument.addSeparator()
        menuDocument.addAction(self._actionClose)
        menuDocument.addAction(self._actionCloseOther)
        menuDocument.addAction(self._actionCloseAll)

        # Menu: Edit
        menuEdit = self.menuBar().addMenu(self.tr("Edit"))
        menuEdit.setObjectName("menuEdit")

        # Menu: Tools
        menuTools = self.menuBar().addMenu(self.tr("Tools"))
        menuTools.setObjectName("menuTools")

        # Menu: View
        menuView = self.menuBar().addMenu(self.tr("View"))
        menuView.setObjectName("menuView")
        menuView.addAction(self._actionFullScreen)
        menuView.addSeparator()
        menuView.addAction(self._actionTitlebarFullPath)
        menuView.addSeparator()
        menuView.addAction(self._actionToolbarApplication)
        menuView.addAction(self._actionToolbarDocument)
        menuView.addAction(self._actionToolbarEdit)
        menuView.addAction(self._actionToolbarTools)
        menuView.addAction(self._actionToolbarView)
        menuView.addAction(self._actionToolbarHelp)

        # Menu: Help
        menuHelp = self.menuBar().addMenu(self.tr("Help"))
        menuHelp.setObjectName("menuHelp")
        menuHelp.addAction(self._actionKeyboardShortcuts)


    def _createToolBars(self):

        # Toolbar: Application
        self._toolbarApplication = self.addToolBar(self.tr("Application Toolbar"))
        self._toolbarApplication.setObjectName("toolbarApplication")
        self._toolbarApplication.addAction(self._actionAbout)
        self._toolbarApplication.addAction(self._actionPreferences)
        self._toolbarApplication.addSeparator()
        self._toolbarApplication.addAction(self._actionQuit)
        self._toolbarApplication.visibilityChanged.connect(lambda visible: self._actionToolbarApplication.setChecked(visible))

        # Toolbar: Document
        self._toolbarDocument = self.addToolBar(self.tr("Document Toolbar"))
        self._toolbarDocument.setObjectName("toolbarDocument")
        self._toolbarDocument.addAction(self._actionNew)
        self._toolbarDocument.addAction(self._actionOpen)
        self._toolbarDocument.addSeparator()
        self._toolbarDocument.addAction(self._actionSave)
        self._toolbarDocument.addAction(self._actionSaveAs)
        self._toolbarDocument.addSeparator()
        self._toolbarDocument.addAction(self._actionClose)
        self._toolbarDocument.visibilityChanged.connect(lambda visible: self._actionToolbarDocument.setChecked(visible))

        # Toolbar: Edit
        self._toolbarEdit = self.addToolBar(self.tr("Edit Toolbar"))
        self._toolbarEdit.setObjectName("toolbarEdit")
        self._toolbarEdit.visibilityChanged.connect(lambda visible: self._actionToolbarEdit.setChecked(visible))

        # Toolbar: Tools
        self._toolbarTools = self.addToolBar(self.tr("Tools Toolbar"))
        self._toolbarTools.setObjectName("toolbarTools")
        self._toolbarTools.visibilityChanged.connect(lambda visible: self._actionToolbarTools.setChecked(visible))

        # Toolbar: View
        self._toolbarView = self.addToolBar(self.tr("View Toolbar"))
        self._toolbarView.setObjectName("toolbarView")
        self._toolbarView.addAction(self._actionFullScreen)
        self._toolbarView.visibilityChanged.connect(lambda visible: self._actionToolbarView.setChecked(visible))

        # Toolbar: Help
        self._toolbarHelp = self.addToolBar(self.tr("Help Toolbar"))
        self._toolbarHelp.setObjectName("toolbarHelp")
        self._toolbarHelp.addAction(self._actionKeyboardShortcuts)
        self._toolbarHelp.visibilityChanged.connect(lambda visible: self._actionToolbarHelp.setChecked(visible))


    def _updateActions(self, subWindowCount=0):

        hasDocument = subWindowCount >= 1
        hasDocuments = subWindowCount >= 2

        # Actions: Document
        self._actionSave.setEnabled(hasDocument)
        self._actionSaveAs.setEnabled(hasDocument)
        self._menuSaveAsDelimiter.setEnabled(hasDocument)
        self._actionSaveCopyAs.setEnabled(hasDocument)
        self._actionSaveAll.setEnabled(hasDocument)
        self._actionClose.setEnabled(hasDocument)
        self._actionCloseOther.setEnabled(hasDocuments)
        self._actionCloseAll.setEnabled(hasDocument)


    def _updateActionFullScreen(self):

        if not self.isFullScreen():
            self._actionFullScreen.setText(self.tr("Full Screen Mode"))
            self._actionFullScreen.setIcon(QIcon.fromTheme("view-fullscreen", QIcon(":/icons/actions/16/view-fullscreen.svg")))
            self._actionFullScreen.setChecked(False)
            self._actionFullScreen.setToolTip(self.tr("Display the window in full screen"))
        else:
            self._actionFullScreen.setText(self.tr("Exit Full Screen Mode"))
            self._actionFullScreen.setIcon(QIcon.fromTheme("view-restore", QIcon(":/icons/actions/16/view-restore.svg")))
            self._actionFullScreen.setChecked(True)
            self._actionFullScreen.setToolTip(self.tr("Exit the full screen mode"))


    def _updateActionRecentDocuments(self):

        # Add items to the list, if necessary
        for idx in range(len(self._actionRecentDocuments)+1, self._preferences.maximumRecentDocuments()+1):

            actionRecentDocument = QAction(self)
            actionRecentDocument.setObjectName(f"actionRecentDocument_{idx}")
            actionRecentDocument.triggered.connect(lambda data=actionRecentDocument.data(): self._onActionOpenRecentDocumentTriggered(data))

            self._actionRecentDocuments.append(actionRecentDocument)

        # Remove items from the list, if necessary
        while len(self._actionRecentDocuments) > self._preferences.maximumRecentDocuments():
            self._actionRecentDocuments.pop()

        # Update items
        for idx in range(len(self._actionRecentDocuments)):
            text = None
            data = None
            show = False

            if idx < len(self._recentDocuments):
                text = self.tr("{0} [{1}]").format(QFileInfo(self._recentDocuments[idx]).fileName(), self._recentDocuments[idx])
                data = self._recentDocuments[idx]
                show = True

            self._actionRecentDocuments[idx].setText(text)
            self._actionRecentDocuments[idx].setData(data)
            self._actionRecentDocuments[idx].setVisible(show)


    def _updateMenuOpenRecent(self):

        self._menuOpenRecent.clear()

        if self._preferences.maximumRecentDocuments() > 0:
            # Document list wanted; show the menu
            self._menuOpenRecent.menuAction().setVisible(True)

            if len(self._recentDocuments) > 0:
                # Document list has items; enable the menu
                self._menuOpenRecent.setEnabled(True)

                self._menuOpenRecent.addActions(self._actionRecentDocuments)
                self._menuOpenRecent.addSeparator()
                self._menuOpenRecent.addAction(self._actionOpenRecentClear)
            else:
                # Document list is empty; disable the menu
                self._menuOpenRecent.setEnabled(False)
        else:
            # No document list wanted; hide the menu
            self._menuOpenRecent.menuAction().setVisible(False)


    def _updateTitleBar(self):

        title = None

        document = self._activeDocument()
        if document:
            title = document.canonicalName() if self._actionTitlebarFullPath.isChecked() and document.canonicalName() else document.documentTitle()

        self.setWindowTitle(title)


    def _onActionAboutTriggered(self):

        dialog = AboutDialog(self)
        dialog.exec_()


    def _onActionColophonTriggered(self):

        dialog = ColophonDialog(self)
        dialog.exec_()


    def _onActionPreferencesTriggered(self):

        dialog = PreferencesDialog(self)
        dialog.setPreferences(self._preferences)
        dialog.exec_()

        self._preferences = dialog.preferences()

        self._updateRecentDocuments(None)
        self._updateMenuOpenRecent()


    def _onActionNewTriggered(self):

        self._loadDocument("")


    def _onActionOpenTriggered(self):

        fileNames = QFileDialog.getOpenFileNames(self, self.tr("Open Document"),
                        QStandardPaths.writableLocation(QStandardPaths.HomeLocation),
                        self.tr("CSV Files (*.csv);;All Files (*.*)"))[0]

        for fileName in fileNames:
            self._openDocument(fileName)


    def _onActionOpenRecentDocumentTriggered(self, canonicalName):
        pass

#        self.openDocument(canonicalName)


    def _onActionOpenRecentClearTriggered(self):

        self._recentDocuments.clear()

        self._updateRecentDocuments(None)
        self._updateMenuOpenRecent()


    def _onActionSaveTriggered(self):
        pass


    def _onActionSaveAsTriggered(self):
        pass


    def _onActionSaveAsDelimiterTriggered(self, delimiter):
        pass


    def _onActionSaveCopyAsTriggered(self):
        pass


    def _onActionSaveAllTriggered(self):
        pass


    def _onActionCloseTriggered(self):

        self._documentArea.closeActiveSubWindow()


    def _onActionCloseOtherTriggered(self):

        for subWindow in self._documentArea.subWindowList():
            if subWindow != self._documentArea.activeSubWindow():
                subWindow.close()


    def _onActionCloseAllTriggered(self):

        self._documentArea.closeAllSubWindows()


    def _onActionFullScreenTriggered(self):

        if not self.isFullScreen():
            self.setWindowState(self.windowState() | Qt.WindowFullScreen)
        else:
            self.setWindowState(self.windowState() & ~Qt.WindowFullScreen)

        self._updateActionFullScreen()


    def _onActionTitlebarFullPathTriggered(self):

        self._updateTitleBar()


    def _onActionKeyboardShortcutsTriggered(self):

        if not self._keyboardShortcutsDialog:
            self._keyboardShortcutsDialog = KeyboardShortcutsDialog(self)

        self._keyboardShortcutsDialog.show()
        self._keyboardShortcutsDialog.raise_()
        self._keyboardShortcutsDialog.activateWindow()


    def _onDocumentWindowActivated(self, subWindow):

        # Update the application window
        self._updateActions(len(self._documentArea.subWindowList()))
        self._updateTitleBar()

        if not subWindow:
            return


    def _onDocumentAboutToClose(self, canonicalName):

        # Workaround to show subwindows always maximized
        for subWindow in self._documentArea.subWindowList():
            if not subWindow.isMaximized():
                subWindow.showMaximized()

        # Update menu items without the emitter
        self._updateActions(len(self._documentArea.subWindowList()) - 1)


    def _createDocument(self):

        document = Document()
        document.setPreferences(self._preferences)
        document.aboutToClose.connect(self._onDocumentAboutToClose)

        subWindow = self._documentArea.addSubWindow(document)
        subWindow.setWindowIcon(QIcon())
        subWindow.showMaximized()

        return document


    def _createDocumentIndex(self, canonicalName):

        fileName = QFileInfo(canonicalName).fileName()
        canonicalIndex = 0

        for subWindow in self._documentArea.subWindowList():
            if QFileInfo(subWindow.widget().canonicalName()).fileName() == fileName:
                if subWindow.widget().canonicalIndex() > canonicalIndex:
                    canonicalIndex = subWindow.widget().canonicalIndex()

        return canonicalIndex + 1


    def _findDocumentWindow(self, canonicalName):

        for subWindow in self._documentArea.subWindowList():
            if subWindow.widget().canonicalName() == canonicalName:
                return subWindow

        return None


    def _activeDocument(self):

        subWindow = self._documentArea.activeSubWindow()

        return subWindow.widget() if subWindow else None


    def _openDocument(self, fileName):

        canonicalName = QFileInfo(fileName).canonicalFilePath()

        subWindow = self._findDocumentWindow(canonicalName)
        if subWindow:
            # Given document is already loaded; activate the subwindow
            self._documentArea.setActiveSubWindow(subWindow)

            # Update list of recent documents
            self._updateRecentDocuments(canonicalName)
            self._updateMenuOpenRecent()
            return True

        return self._loadDocument(canonicalName);


    def _loadDocument(self, canonicalName):

        document = self._createDocument()

        succeeded = document.load(canonicalName)
        if succeeded:
            document.setCanonicalIndex(self._createDocumentIndex(canonicalName))
            document.updateDocumentTitle()
            document.show()

            # Update list of recent documents
            self._updateRecentDocuments(canonicalName)
            self._updateMenuOpenRecent()

            # Update the application window
            self._updateActions(len(self._documentArea.subWindowList()))
            self._updateTitleBar()
        else:
            document.close()

        return succeeded


    def _updateRecentDocuments(self, canonicalName):

        if canonicalName:
            while canonicalName in self._recentDocuments:
                self._recentDocuments.remove(canonicalName)
            self._recentDocuments.insert(0, canonicalName)

        # Remove items from the list, if necessary
        while len(self._recentDocuments) > self._preferences.maximumRecentDocuments():
            self._recentDocuments.pop()

        self._updateActionRecentDocuments()
Ejemplo n.º 18
0
    def __init__(self):
        QMainWindow.__init__(self)
        signal.signal(signal.SIGINT, self.exit_app)
        self.setWindowTitle("Steam Account Switcher")
        self.setMinimumSize(300, 200)
        self.resize(300, 300)

        # Logo
        self.switcher_logo = QIcon("logo.png")
        self.setWindowIcon(self.switcher_logo)
        if platform.system() == "Windows":  # windows taskbar app icon fix
            import ctypes
            win_appid = 'github.tommis.steam_account_switcher'
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
                win_appid)

        from steamswitcher import SteamSwitcher

        self.switcher = SteamSwitcher()
        self.args = self.switcher.args
        self.main_widget = QWidget()

        if self.args.gui or self.switcher.settings.get(
                "show_on_startup", True) and not self.args.no_gui:
            self.show()
        elif self.args.no_gui and self.args.no_tray:
            self.exit_app()

        self.menu_bar = self.menuBar()
        self.file_menu = self.menu_bar.addMenu(_("File"))
        self.settings_menu = self.menu_bar.addMenu(_("Settings"))
        self.size_menu = self.menu_bar.addMenu(_("Size"))

        refresh_action = QAction(_("Refresh"), self)
        import_action = QAction(_("Import accounts"), self)
        open_skinsdir_action = QAction(_("Skins dir"), self)
        about_action = QAction(_("About"), self)
        exit_action = QAction(_("Exit"), self)

        refresh_action.triggered.connect(Accounts.steamapi_refresh)
        import_action.triggered.connect(
            lambda: DialogImportAccount.import_accounts_dialog(self))
        open_skinsdir_action.triggered.connect(self.open_skinsdir)
        about_action.triggered.connect(lambda: DialogAbout.about_dialog(self))
        exit_action.triggered.connect(self.exit_app)

        refresh_action.setShortcut("F5")
        exit_action.setShortcut("Ctrl+Q")

        self.file_menu.addActions([
            refresh_action, import_action, open_skinsdir_action, about_action
        ])
        self.file_menu.addSeparator()
        self.file_menu.addAction(exit_action)

        set_steamapi_key = QAction(_("Set steamapi key"), self)
        show_avatars = QAction(_("Show avatars"), self, checkable=True)
        use_systemtray = QAction(_("Use systemtray"), self, checkable=True)

        after_login_menu = QMenu(_("After login"))

        after_login_behaviour_group = QActionGroup(after_login_menu)
        nothing_behaviour = QAction(_('Nothing'),
                                    after_login_behaviour_group,
                                    checkable=True,
                                    data="nothing")
        close_behaviour = QAction(_('Close'),
                                  after_login_behaviour_group,
                                  checkable=True,
                                  data="close")
        minimize_behaviour = QAction(_('Minimize to taskbar'),
                                     after_login_behaviour_group,
                                     checkable=True,
                                     data="minimize")
        minimize_tray_behaviour = QAction(_('Minimize to tray'),
                                          after_login_behaviour_group,
                                          checkable=True,
                                          data="minimize_tray")

        after_login_menu.addActions([
            nothing_behaviour, close_behaviour, minimize_behaviour,
            minimize_tray_behaviour
        ])

        behaviour_switcher = {
            "close": lambda: close_behaviour.setChecked(True),
            "minimize": lambda: minimize_behaviour.setChecked(True),
            "minimize_tray": lambda: minimize_tray_behaviour.setChecked(True)
        }
        behaviour_switcher.get(self.switcher.settings["behavior_after_login"],
                               lambda: nothing_behaviour.setChecked(True))()

        after_login_menu.triggered.connect(self.set_after_login_action)

        self.systemtray(self.main_widget)

        set_steamapi_key.triggered.connect(lambda: self.steamapi_key_dialog())
        show_avatars.triggered.connect(lambda: self.set_show_avatars())
        use_systemtray.triggered.connect(lambda: self.set_use_systemtray())

        self.settings_menu.addAction(set_steamapi_key)
        self.settings_menu.addSeparator()
        self.settings_menu.addActions([show_avatars, use_systemtray])
        self.settings_menu.addMenu(after_login_menu)

        show_avatars.setChecked(self.switcher.settings.get("show_avatars"))
        use_systemtray.setChecked(self.switcher.settings.get("use_systemtray"))

        set_size_small = QAction(_("Small"), self)
        set_size_medium = QAction(_("Medium"), self)
        set_size_large = QAction(_("Large"), self)
        set_size_small.triggered.connect(lambda: self.set_size("small"))
        set_size_medium.triggered.connect(lambda: self.set_size("medium"))
        set_size_large.triggered.connect(lambda: self.set_size("large"))
        self.size_menu.addActions(
            [set_size_small, set_size_medium, set_size_large])

        set_size_small.setShortcut("Ctrl+1")
        set_size_medium.setShortcut("Ctrl+2")
        set_size_large.setShortcut("Ctrl+3")

        self.add_button = QPushButton(_("Add account"))
        self.edit_button = QPushButton(_("Edit account"))
        self.edit_button.setDisabled(True)

        self.buttons = QHBoxLayout()
        self.buttons.addWidget(self.add_button)
        self.buttons.addWidget(self.edit_button)

        self.layout = QVBoxLayout()
        self.main_widget.setLayout(self.layout)

        self.accounts_list = QListWidget()
        self.accounts_list.setDragDropMode(QAbstractItemView.InternalMove)
        self.layout.addWidget(self.accounts_list)
        self.layout.addLayout(self.buttons)

        self.layout.setSpacing(10)
        self.accounts_list.setSpacing(1)

        self.import_accounts_window = QDialog()

        self.load_accounts()

        def edit_button_enabled():
            if self.accounts_list.selectedItems():
                self.edit_button.setEnabled(True)
            else:
                self.edit_button.setEnabled(False)

        # Signals and Slots
        self.add_button.clicked.connect(lambda: self.account_dialog(True))
        self.edit_button.clicked.connect(lambda: self.account_dialog(False))
        self.accounts_list.itemSelectionChanged.connect(edit_button_enabled)
        self.accounts_list.doubleClicked.connect(lambda: self.steam_login(
            self.accounts_list.currentIndex().data(5)))
        self.accounts_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.accounts_list.customContextMenuRequested.connect(
            lambda: RightClickMenu.show_rightclick_menu(self))
        #self.accounts_list.layoutChanged.connect(lambda: self.account_reordered)
        #self.accounts_list.dropEvent(self.dropEvent(QDropEvent))

        self.setCentralWidget(self.main_widget)

        if self.args.no_tray:
            print("test")
        elif self.switcher.settings.get("use_systemtray") or self.args.tray:
            self.tray_icon.show()

        if self.switcher.first_run or self.args.first_run:
            self.steamapi_key_dialog()
        elif not self.switcher.first_run and \
             not self.is_valid_steampi_key(self.switcher.settings["steam_api_key"]):
            self.tray_icon.showMessage("No api key",
                                       "Set the steam web api key.",
                                       self.switcher_logo)
Ejemplo n.º 19
0
class PuppetMaster(QMainWindow):
    requestEditMode = Signal(bool)

    def __init__(self, parent=None, editMode=bool(False)):
        super(PuppetMaster, self).__init__(parent)
        self._parent = parent
        self._model = list()
        self.editMode = editMode

        self.setMouseTracking(True)

        self.setFocusPolicy(Qt.StrongFocus)

        self.setWindowTitle('PuppetMaster')

        self.setMinimumHeight(1)
        self.setMinimumWidth(1)

        self.setContextMenuPolicy(Qt.PreventContextMenu)

        # Main tabs
        self.tab = CanvasGraphicsViewTab(parent=self)
        self.tab.requestEditMode.connect(self.set_edit)
        self.setCentralWidget(self.tab)

        # Parameter Widget
        self.parameter = Parameters(parent=self)

        self.parameterDock = QDockWidget(": Parameters ::", self)
        self.parameterDock.setObjectName('Parameters')
        self.parameterDock.setFeatures(QDockWidget.DockWidgetClosable)
        self.parameterDock.setWidget(self.parameter)
        self.parameterDock.setTitleBarWidget(QWidget(self.parameterDock))
        self.parameterDock.setVisible(self.editMode)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.parameterDock)

        self.tab.onSelection.connect(self.update_parameters)
        self.parameter.onChangeBGColor.connect(self.tab.update_bg_color)
        self.parameter.onChangeFontColor.connect(self.tab.update_font_color)
        self.parameter.onChangeFontSize.connect(self.tab.update_font_size)
        self.parameter.onChangeText.connect(self.tab.update_text)
        self.parameter.onChangeShape.connect(self.tab.update_shape)

        # maya Signal on selection items
        self.idx = OpenMaya.MEventMessage.addEventCallback(
            "SelectionChanged", self.tab.maya_selection)

        # Menu
        self.setMenuBar(self.create_menu())

        self.set_edit(self.editMode)

    def update_parameters(self, node=PickNode):
        shape = node.Shape if isinstance(node, PickNode) else str()
        self.parameter.update_param(text=node.toPlainText(),
                                    fontSize=node.font().pointSize(),
                                    fontColor=node.defaultTextColor(),
                                    bgColor=node.Background,
                                    shapeName=shape)

    def create_menu(self):
        window_menu = QMenuBar(self)
        file_menu = window_menu.addMenu("&File")

        new_action = QAction("&New...", self)
        new_action.setShortcut('Ctrl+N')
        new_action.setShortcutContext(Qt.WidgetShortcut)
        new_action.setStatusTip('Create a new Set')
        new_action.triggered.connect(self.tab.new_tab)
        file_menu.addAction(new_action)

        open_action = QAction("&Open...", self)
        open_action.setShortcut('Ctrl+O')
        open_action.setShortcutContext(Qt.WidgetShortcut)
        open_action.setStatusTip('Open a new set')
        open_action.triggered.connect(self.tab.open_set)
        file_menu.addAction(open_action)

        refresh_action = QAction("&Refresh...", self)
        refresh_action.setStatusTip('Refresh the current sets')
        refresh_action.triggered.connect(self.tab.refresh_set)
        file_menu.addAction(refresh_action)

        file_menu.addSeparator()

        save_action = QAction("&Save...", self)
        save_action.setShortcut('Ctrl+S')
        save_action.setShortcutContext(Qt.WidgetShortcut)
        save_action.setStatusTip('Save the current tab')
        save_action.triggered.connect(self.tab.save_set)
        file_menu.addAction(save_action)

        saveAs_action = QAction("&Save As...", self)
        saveAs_action.setShortcut('Ctrl+Shift+S')
        saveAs_action.setShortcutContext(Qt.WidgetShortcut)
        saveAs_action.setStatusTip('Save the current tab as a new Set')
        saveAs_action.triggered.connect(self.tab.saveAs_set)
        file_menu.addAction(saveAs_action)

        saveAsTemp_action = QAction("&Save As Template...", self)
        saveAsTemp_action.setStatusTip(
            'Save the current tab as a new Template')
        saveAsTemp_action.triggered.connect(self.tab.saveAsTemplate_set)
        file_menu.addAction(saveAsTemp_action)

        file_menu.addSeparator()

        rename_action = QAction("&Rename Tab...", self)
        rename_action.setStatusTip('Rename the current Tab')
        rename_action.triggered.connect(self.tab.rename_set)
        file_menu.addAction(rename_action)

        close_action = QAction("&Close Tab...", self)
        close_action.setShortcut('Ctrl+Shift+W')
        close_action.setShortcutContext(Qt.WidgetShortcut)
        close_action.setStatusTip('Close the current Tab')
        close_action.triggered.connect(self.tab.closeCurrentTab)
        file_menu.addAction(close_action)

        picker_menu = window_menu.addMenu("&Picker")

        self.edit_action = QAction("&Edit Mode", self)
        self.edit_action.setStatusTip('Toggle between view and edit mode.')
        self.edit_action.triggered.connect(self.edit_toggle)
        self.edit_action.setCheckable(True)
        self.edit_action.setChecked(self.editMode)
        picker_menu.addAction(self.edit_action)

        picker_menu.addSeparator()

        self.background_action = QAction("&Change Background...", self)
        self.background_action.setEnabled(self.editMode)
        self.background_action.setStatusTip('Change the background.')
        self.background_action.triggered.connect(self.tab.set_background)
        picker_menu.addAction(self.background_action)

        self.namespace_action = QAction("&Change Namespace...", self)
        self.namespace_action.setEnabled(self.editMode)
        self.namespace_action.setStatusTip('Change the namespace.')
        self.namespace_action.triggered.connect(self.tab.set_namespace)
        picker_menu.addAction(self.namespace_action)

        help_menu = window_menu.addMenu("&Help")

        wiki_action = QAction("&About PuppetMaster...", self)
        wiki_action.setStatusTip('Open Wiki page')
        wiki_action.triggered.connect(self.wiki_open)
        help_menu.addAction(wiki_action)

        return window_menu

    def edit_toggle(self):
        self.set_edit(not self.editMode)

    def wiki_open(self):
        webbrowser.open_new_tab(
            'https://github.com/Bernardrouhi/PuppetMaster/wiki')

    def force_load(self, paths=list):
        self.tab.force_load(paths)

    def findAndLoad(self, names=list()):
        '''
        Find the names in PuppetMaster folder and load them

        Parameters
        ----------
        names: (list)
            List of dictionaries of name and namespace.
        '''
        if names:
            self.tab.findAndLoad(names)

    def destroyMayaSignals(self):
        # destroy the connection
        OpenMaya.MMessage.removeCallback(self.idx)

    def get_edit(self):
        return self.editMode

    def set_edit(self, value=bool):
        self.editMode = value
        self.background_action.setEnabled(self.editMode)
        self.namespace_action.setEnabled(self.editMode)
        self.parameterDock.setVisible(self.editMode)
        self.edit_action.setChecked(self.editMode)
        self.tab.Edit = self.editMode
        # Notification
        if not self.editMode:
            warningMes(
                "PUPPETMASTER-INFO: Out of 'Edit Mode' you won't be able to create/edit/move or delete any node."
            )
        else:
            warningMes(
                "PUPPETMASTER-INFO: In 'Edit Mode' command buttons won't run any commands."
            )

    Edit = property(get_edit, set_edit)

    def keyPressEvent(self, event):
        if event.modifiers() == (Qt.ControlModifier | Qt.ShiftModifier):
            if event.key() == Qt.Key_W:
                self.tab.closeCurrentTab()
            elif event.key() == Qt.Key_S:
                self.tab.saveAs_set()
        elif event.modifiers() == Qt.ControlModifier:
            if event.key() == Qt.Key_S:
                self.tab.save_set()
            elif event.key() == Qt.Key_N:
                self.tab.new_tab()
            elif event.key() == Qt.Key_O:
                self.tab.open_set()
        else:
            super(PuppetMaster, self).keyPressEvent(event)
Ejemplo n.º 20
0
    def __init__(self, bind_address: str, port: int, filesToRead: [str]):
        """
        :param bind_address: address to bind to when listening for live connections.
        :param port: port to bind to when listening for live connections.
        :param filesToRead: replay files to open.
        """
        super().__init__()

        # TODO : Rework into a class if we add more options later.
        self.options = {
            "focusNewTab": True,        # Useful whenever we are getting flooded with connections (or scanned), and we only want to monitor one at a time.
            "closeTabOnCtrlW": True     # Allow user to toggle Ctrl+W passthrough.
        }

        self.liveWindow = LiveWindow(bind_address, port, self.updateCountSignal, self.options)
        self.replayWindow = ReplayWindow(self.options)
        self.tabManager = QTabWidget()
        self.tabManager.addTab(self.liveWindow, "Live connections")
        self.tabManager.addTab(self.replayWindow, "Replays")
        self.setCentralWidget(self.tabManager)
        self.updateCountSignal.connect(self.updateTabConnectionCount)

        # File menu
        openAction = QAction("Open...", self)
        openAction.setShortcut("Ctrl+O")
        openAction.setStatusTip("Open a replay file")
        openAction.triggered.connect(self.onOpenFile)

        # Command menu
        windowsRAction = QAction("Windows+R", self)
        windowsRAction.setShortcut("Ctrl+Alt+R")
        windowsRAction.setStatusTip("Send a Windows+R key sequence")
        windowsRAction.triggered.connect(lambda: self.sendKeySequence([Qt.Key.Key_Meta, Qt.Key.Key_R]))

        windowsLAction = QAction("Windows+L", self)
        windowsLAction.setShortcut("Ctrl+Alt+L")
        windowsLAction.setStatusTip("Send a Windows+L key sequence")
        windowsLAction.triggered.connect(lambda: self.sendKeySequence([Qt.Key.Key_Meta, Qt.Key.Key_L]))

        windowsEAction = QAction("Windows+E", self)
        windowsEAction.setShortcut("Ctrl+Alt+E")
        windowsEAction.setStatusTip("Send a Windows+E key sequence")
        windowsEAction.triggered.connect(lambda: self.sendKeySequence([Qt.Key.Key_Meta, Qt.Key.Key_E]))

        typeTextAction = QAction("Type text...", self)
        typeTextAction.setShortcut("Ctrl+Alt+T")
        typeTextAction.setStatusTip("Simulate typing on the keyboard")
        typeTextAction.triggered.connect(self.sendText)

        # Options menu
        focusTabAction = QAction("Focus new connections", self)
        focusTabAction.setCheckable(True)
        focusTabAction.setChecked(self.options.get("focusNewTab"))
        focusTabAction.triggered.connect(lambda: self.toggleFocusNewTab())

        closeTabOnCtrlW = QAction("Close current tab on Ctrl+W", self)
        closeTabOnCtrlW.setCheckable(True)
        closeTabOnCtrlW.setChecked(self.options.get("closeTabOnCtrlW"))
        closeTabOnCtrlW.triggered.connect(lambda: self.toggleCloseTabOnCtrlW())

        # Create menu
        menuBar = self.menuBar()

        fileMenu = menuBar.addMenu("File")
        fileMenu.addAction(openAction)

        commandMenu = menuBar.addMenu("Command")
        commandMenu.addAction(windowsRAction)
        commandMenu.addAction(windowsLAction)
        commandMenu.addAction(windowsEAction)
        commandMenu.addAction(typeTextAction)

        optionsMenu = menuBar.addMenu("Options")
        optionsMenu.addAction(focusTabAction)
        optionsMenu.addAction(closeTabOnCtrlW)

        for fileName in filesToRead:
            self.replayWindow.openFile(fileName)
Ejemplo n.º 21
0
class MainWindow(QMainWindow):
    def __init__(self,
                 font=QtGui.QFontMetrics(QtGui.QFont()),
                 screen_size=QtCore.QSize()):
        super().__init__()

        self.screen = screen_size
        self.font_metric = font
        self.setWindowTitle('OpenMC Plot Explorer')

    def loadGui(self):

        self.pixmap = None
        self.zoom = 100

        self.loadModel()

        # Create viewing area
        self.frame = QScrollArea(self)
        cw = QWidget()
        self.frame.setCornerWidget(cw)
        self.frame.setAlignment(QtCore.Qt.AlignCenter)
        self.frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.setCentralWidget(self.frame)

        # connect pinch gesture (OSX)
        self.grabGesture(QtCore.Qt.PinchGesture)

        # Create plot image
        self.plotIm = PlotImage(self.model, self.frame, self)
        self.frame.setWidget(self.plotIm)

        # Dock
        self.dock = DomainDock(self.model, self.font_metric, self)
        self.dock.setObjectName("Domain Options Dock")
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock)

        # Tally Dock
        self.tallyDock = TallyDock(self.model, self.font_metric, self)
        self.tallyDock.update()
        self.tallyDock.setObjectName("Tally Options Dock")
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.tallyDock)

        # Color DialogtallyDock
        self.colorDialog = ColorDialog(self.model, self.font_metric, self)
        self.colorDialog.hide()

        # Tools
        self.exportDataDialog = ExportDataDialog(self.model, self.font_metric,
                                                 self)

        # Restore Window Settings
        self.restoreWindowSettings()

        # Create menubar
        self.createMenuBar()
        self.updateEditMenu()

        # Status Bar
        self.coord_label = QLabel()
        self.statusBar().addPermanentWidget(self.coord_label)
        self.coord_label.hide()

        # Keyboard overlay
        self.shortcutOverlay = ShortcutsOverlay(self)
        self.shortcutOverlay.hide()

        # Load Plot
        self.statusBar().showMessage('Generating Plot...')
        self.dock.updateDock()
        self.tallyDock.update()
        self.colorDialog.updateDialogValues()
        self.statusBar().showMessage('')

        # Timer allows GUI to render before plot finishes loading
        QtCore.QTimer.singleShot(0, self.plotIm.generatePixmap)
        QtCore.QTimer.singleShot(0, self.showCurrentView)

    def event(self, event):
        # use pinch event to update zoom
        if isinstance(event, QGestureEvent):
            pinch = event.gesture(QtCore.Qt.PinchGesture)
            self.editZoom(self.zoom * pinch.scaleFactor())
        if isinstance(event, QKeyEvent) and hasattr(self, "shortcutOverlay"):
            self.shortcutOverlay.event(event)
        return super().event(event)

    def show(self):
        super().show()
        self.plotIm._resize()

    def toggleShortcuts(self):
        if self.shortcutOverlay.isVisible():
            self.shortcutOverlay.close()
        else:
            self.shortcutOverlay.move(0, 0)
            self.shortcutOverlay.resize(self.width(), self.height())
            self.shortcutOverlay.show()

    # Create and update menus:
    def createMenuBar(self):
        self.mainMenu = self.menuBar()

        # File Menu
        self.reloadModelAction = QAction("&Reload model...", self)
        self.reloadModelAction.setShortcut("Ctrl+Shift+R")
        self.reloadModelAction.setToolTip("Reload current model")
        self.reloadModelAction.setStatusTip("Reload current model")
        reload_connector = partial(self.loadModel, reload=True)
        self.reloadModelAction.triggered.connect(reload_connector)

        self.saveImageAction = QAction("&Save Image As...", self)
        self.saveImageAction.setShortcut("Ctrl+Shift+S")
        self.saveImageAction.setToolTip('Save plot image')
        self.saveImageAction.setStatusTip('Save plot image')
        self.saveImageAction.triggered.connect(self.saveImage)

        self.saveViewAction = QAction("Save &View...", self)
        self.saveViewAction.setShortcut(QtGui.QKeySequence.Save)
        self.saveViewAction.setStatusTip('Save current view settings')
        self.saveViewAction.triggered.connect(self.saveView)

        self.openAction = QAction("&Open View...", self)
        self.openAction.setShortcut(QtGui.QKeySequence.Open)
        self.openAction.setToolTip('Open saved view settings')
        self.openAction.setStatusTip('Open saved view settings')
        self.openAction.triggered.connect(self.openView)

        self.quitAction = QAction("&Quit", self)
        self.quitAction.setShortcut(QtGui.QKeySequence.Quit)
        self.quitAction.setToolTip('Quit OpenMC Plot Explorer')
        self.quitAction.setStatusTip('Quit OpenMC Plot Explorer')
        self.quitAction.triggered.connect(self.close)

        self.exportDataAction = QAction('E&xport...', self)
        self.exportDataAction.setToolTip('Export model and tally data VTK')
        self.setStatusTip('Export current model and tally data to VTK')
        self.exportDataAction.triggered.connect(self.exportTallyData)
        if not _HAVE_VTK:
            self.exportDataAction.setEnabled(False)
            self.exportDataAction.setToolTip(
                "Disabled: VTK Python module is not installed")

        self.fileMenu = self.mainMenu.addMenu('&File')
        self.fileMenu.addAction(self.reloadModelAction)
        self.fileMenu.addAction(self.saveImageAction)
        self.fileMenu.addAction(self.exportDataAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.saveViewAction)
        self.fileMenu.addAction(self.openAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.quitAction)

        # Data Menu
        self.openStatePointAction = QAction("&Open statepoint...", self)
        self.openStatePointAction.setToolTip('Open statepoint file')
        self.openStatePointAction.triggered.connect(self.openStatePoint)

        self.dataMenu = self.mainMenu.addMenu('D&ata')
        self.dataMenu.addAction(self.openStatePointAction)
        self.updateDataMenu()

        # Edit Menu
        self.applyAction = QAction("&Apply Changes", self)
        self.applyAction.setShortcut("Ctrl+Return")
        self.applyAction.setToolTip('Generate new view with changes applied')
        self.applyAction.setStatusTip('Generate new view with changes applied')
        self.applyAction.triggered.connect(self.applyChanges)

        self.undoAction = QAction('&Undo', self)
        self.undoAction.setShortcut(QtGui.QKeySequence.Undo)
        self.undoAction.setToolTip('Undo')
        self.undoAction.setStatusTip('Undo last plot view change')
        self.undoAction.setDisabled(True)
        self.undoAction.triggered.connect(self.undo)

        self.redoAction = QAction('&Redo', self)
        self.redoAction.setDisabled(True)
        self.redoAction.setToolTip('Redo')
        self.redoAction.setStatusTip('Redo last plot view change')
        self.redoAction.setShortcut(QtGui.QKeySequence.Redo)
        self.redoAction.triggered.connect(self.redo)

        self.restoreAction = QAction("&Restore Default Plot", self)
        self.restoreAction.setShortcut("Ctrl+R")
        self.restoreAction.setToolTip('Restore to default plot view')
        self.restoreAction.setStatusTip('Restore to default plot view')
        self.restoreAction.triggered.connect(self.restoreDefault)

        self.editMenu = self.mainMenu.addMenu('&Edit')
        self.editMenu.addAction(self.applyAction)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.undoAction)
        self.editMenu.addAction(self.redoAction)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.restoreAction)
        self.editMenu.addSeparator()
        self.editMenu.aboutToShow.connect(self.updateEditMenu)

        # Edit -> Basis Menu
        self.xyAction = QAction('&xy  ', self)
        self.xyAction.setCheckable(True)
        self.xyAction.setShortcut('Alt+X')
        self.xyAction.setToolTip('Change to xy basis')
        self.xyAction.setStatusTip('Change to xy basis')
        xy_connector = partial(self.editBasis, 'xy', apply=True)
        self.xyAction.triggered.connect(xy_connector)

        self.xzAction = QAction('x&z  ', self)
        self.xzAction.setCheckable(True)
        self.xzAction.setShortcut('Alt+Z')
        self.xzAction.setToolTip('Change to xz basis')
        self.xzAction.setStatusTip('Change to xz basis')
        xz_connector = partial(self.editBasis, 'xz', apply=True)
        self.xzAction.triggered.connect(xz_connector)

        self.yzAction = QAction('&yz  ', self)
        self.yzAction.setCheckable(True)
        self.yzAction.setShortcut('Alt+Y')
        self.yzAction.setToolTip('Change to yz basis')
        self.yzAction.setStatusTip('Change to yz basis')
        yz_connector = partial(self.editBasis, 'yz', apply=True)
        self.yzAction.triggered.connect(yz_connector)

        self.basisMenu = self.editMenu.addMenu('&Basis')
        self.basisMenu.addAction(self.xyAction)
        self.basisMenu.addAction(self.xzAction)
        self.basisMenu.addAction(self.yzAction)
        self.basisMenu.aboutToShow.connect(self.updateBasisMenu)

        # Edit -> Color By Menu
        self.cellAction = QAction('&Cell', self)
        self.cellAction.setCheckable(True)
        self.cellAction.setShortcut('Alt+C')
        self.cellAction.setToolTip('Color by cell')
        self.cellAction.setStatusTip('Color plot by cell')
        cell_connector = partial(self.editColorBy, 'cell', apply=True)
        self.cellAction.triggered.connect(cell_connector)

        self.materialAction = QAction('&Material', self)
        self.materialAction.setCheckable(True)
        self.materialAction.setShortcut('Alt+M')
        self.materialAction.setToolTip('Color by material')
        self.materialAction.setStatusTip('Color plot by material')
        material_connector = partial(self.editColorBy, 'material', apply=True)
        self.materialAction.triggered.connect(material_connector)

        self.temperatureAction = QAction('&Temperature', self)
        self.temperatureAction.setCheckable(True)
        self.temperatureAction.setShortcut('Alt+T')
        self.temperatureAction.setToolTip('Color by temperature')
        self.temperatureAction.setStatusTip('Color plot by temperature')
        temp_connector = partial(self.editColorBy, 'temperature', apply=True)
        self.temperatureAction.triggered.connect(temp_connector)

        self.densityAction = QAction('&Density', self)
        self.densityAction.setCheckable(True)
        self.densityAction.setShortcut('Alt+D')
        self.densityAction.setToolTip('Color by density')
        self.densityAction.setStatusTip('Color plot by density')
        density_connector = partial(self.editColorBy, 'density', apply=True)
        self.densityAction.triggered.connect(density_connector)

        self.colorbyMenu = self.editMenu.addMenu('&Color By')
        self.colorbyMenu.addAction(self.cellAction)
        self.colorbyMenu.addAction(self.materialAction)
        self.colorbyMenu.addAction(self.temperatureAction)
        self.colorbyMenu.addAction(self.densityAction)

        self.colorbyMenu.aboutToShow.connect(self.updateColorbyMenu)

        self.editMenu.addSeparator()

        # Edit -> Other Options
        self.maskingAction = QAction('Enable &Masking', self)
        self.maskingAction.setShortcut('Ctrl+M')
        self.maskingAction.setCheckable(True)
        self.maskingAction.setToolTip('Toggle masking')
        self.maskingAction.setStatusTip('Toggle whether masking is enabled')
        masking_connector = partial(self.toggleMasking, apply=True)
        self.maskingAction.toggled.connect(masking_connector)
        self.editMenu.addAction(self.maskingAction)

        self.highlightingAct = QAction('Enable High&lighting', self)
        self.highlightingAct.setShortcut('Ctrl+L')
        self.highlightingAct.setCheckable(True)
        self.highlightingAct.setToolTip('Toggle highlighting')
        self.highlightingAct.setStatusTip('Toggle whether '
                                          'highlighting is enabled')
        highlight_connector = partial(self.toggleHighlighting, apply=True)
        self.highlightingAct.toggled.connect(highlight_connector)
        self.editMenu.addAction(self.highlightingAct)

        self.overlapAct = QAction('Enable Overlap Coloring', self)
        self.overlapAct.setShortcut('Ctrl+P')
        self.overlapAct.setCheckable(True)
        self.overlapAct.setToolTip('Toggle overlapping regions')
        self.overlapAct.setStatusTip('Toggle display of overlapping '
                                     'regions when enabled')
        overlap_connector = partial(self.toggleOverlaps, apply=True)
        self.overlapAct.toggled.connect(overlap_connector)
        self.editMenu.addAction(self.overlapAct)

        self.outlineAct = QAction('Enable Domain Outlines', self)
        self.outlineAct.setShortcut('Ctrl+U')
        self.outlineAct.setCheckable(True)
        self.outlineAct.setToolTip('Display Cell/Material Boundaries')
        self.outlineAct.setStatusTip('Toggle display of domain '
                                     'outlines when enabled')
        outline_connector = partial(self.toggleOutlines, apply=True)
        self.outlineAct.toggled.connect(outline_connector)
        self.editMenu.addAction(self.outlineAct)

        # View Menu
        self.dockAction = QAction('Hide &Dock', self)
        self.dockAction.setShortcut("Ctrl+D")
        self.dockAction.setToolTip('Toggle dock visibility')
        self.dockAction.setStatusTip('Toggle dock visibility')
        self.dockAction.triggered.connect(self.toggleDockView)

        self.tallyDockAction = QAction('Tally &Dock', self)
        self.tallyDockAction.setShortcut("Ctrl+T")
        self.tallyDockAction.setToolTip('Toggle tally dock visibility')
        self.tallyDockAction.setStatusTip('Toggle tally dock visibility')
        self.tallyDockAction.triggered.connect(self.toggleTallyDockView)

        self.zoomAction = QAction('&Zoom...', self)
        self.zoomAction.setShortcut('Alt+Shift+Z')
        self.zoomAction.setToolTip('Edit zoom factor')
        self.zoomAction.setStatusTip('Edit zoom factor')
        self.zoomAction.triggered.connect(self.editZoomAct)

        self.viewMenu = self.mainMenu.addMenu('&View')
        self.viewMenu.addAction(self.dockAction)
        self.viewMenu.addAction(self.tallyDockAction)
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.zoomAction)
        self.viewMenu.aboutToShow.connect(self.updateViewMenu)

        # Window Menu
        self.mainWindowAction = QAction('&Main Window', self)
        self.mainWindowAction.setCheckable(True)
        self.mainWindowAction.setToolTip('Bring main window to front')
        self.mainWindowAction.setStatusTip('Bring main window to front')
        self.mainWindowAction.triggered.connect(self.showMainWindow)

        self.colorDialogAction = QAction('Color &Options', self)
        self.colorDialogAction.setCheckable(True)
        self.colorDialogAction.setToolTip('Bring Color Dialog to front')
        self.colorDialogAction.setStatusTip('Bring Color Dialog to front')
        self.colorDialogAction.triggered.connect(self.showColorDialog)

        # Keyboard Shortcuts Overlay
        self.keyboardShortcutsAction = QAction("&Keyboard Shortcuts...", self)
        self.keyboardShortcutsAction.setShortcut("?")
        self.keyboardShortcutsAction.setToolTip("Display Keyboard Shortcuts")
        self.keyboardShortcutsAction.setStatusTip("Display Keyboard Shortcuts")
        self.keyboardShortcutsAction.triggered.connect(self.toggleShortcuts)

        self.windowMenu = self.mainMenu.addMenu('&Window')
        self.windowMenu.addAction(self.mainWindowAction)
        self.windowMenu.addAction(self.colorDialogAction)
        self.windowMenu.addAction(self.keyboardShortcutsAction)
        self.windowMenu.aboutToShow.connect(self.updateWindowMenu)

    def updateEditMenu(self):
        changed = self.model.currentView != self.model.defaultView
        self.restoreAction.setDisabled(not changed)

        self.maskingAction.setChecked(self.model.currentView.masking)
        self.highlightingAct.setChecked(self.model.currentView.highlighting)
        self.outlineAct.setChecked(self.model.currentView.outlines)

        num_previous_views = len(self.model.previousViews)
        self.undoAction.setText('&Undo ({})'.format(num_previous_views))
        num_subsequent_views = len(self.model.subsequentViews)
        self.redoAction.setText('&Redo ({})'.format(num_subsequent_views))

    def updateBasisMenu(self):
        self.xyAction.setChecked(self.model.currentView.basis == 'xy')
        self.xzAction.setChecked(self.model.currentView.basis == 'xz')
        self.yzAction.setChecked(self.model.currentView.basis == 'yz')

    def updateColorbyMenu(self):
        cv = self.model.currentView
        self.cellAction.setChecked(cv.colorby == 'cell')
        self.materialAction.setChecked(cv.colorby == 'material')
        self.temperatureAction.setChecked(cv.colorby == 'temperature')
        self.densityAction.setChecked(cv.colorby == 'density')

    def updateViewMenu(self):
        if self.dock.isVisible():
            self.dockAction.setText('Hide &Dock')
        else:
            self.dockAction.setText('Show &Dock')

    def updateWindowMenu(self):
        self.colorDialogAction.setChecked(self.colorDialog.isActiveWindow())
        self.mainWindowAction.setChecked(self.isActiveWindow())

    # Menu and shared methods
    def loadModel(self, reload=False):
        if reload:
            self.resetModels()
        else:
            # create new plot model
            self.model = PlotModel()
            self.restoreModelSettings()
            # update plot and model settings
            self.updateRelativeBases()

        self.cellsModel = DomainTableModel(self.model.activeView.cells)
        self.materialsModel = DomainTableModel(self.model.activeView.materials)

        if reload:
            loader_thread = Thread(target=_openmcReload)
            loader_thread.start()
            while loader_thread.is_alive():
                self.statusBar().showMessage("Reloading model...")
                QApplication.processEvents()

            self.plotIm.model = self.model
            self.applyChanges()

    def saveImage(self):
        filename, ext = QFileDialog.getSaveFileName(self, "Save Plot Image",
                                                    "untitled",
                                                    "Images (*.png)")
        if filename:
            if "." not in filename:
                filename += ".png"
            self.plotIm.figure.savefig(filename, transparent=True)
            self.statusBar().showMessage('Plot Image Saved', 5000)

    def saveView(self):
        filename, ext = QFileDialog.getSaveFileName(self, "Save View Settings",
                                                    "untitled",
                                                    "View Settings (*.pltvw)")
        if filename:
            if "." not in filename:
                filename += ".pltvw"

            saved = {
                'version': self.model.version,
                'current': self.model.currentView
            }
            with open(filename, 'wb') as file:
                pickle.dump(saved, file)

    def openView(self):
        filename, ext = QFileDialog.getOpenFileName(self, "Open View Settings",
                                                    ".", "*.pltvw")
        if filename:
            try:
                with open(filename, 'rb') as file:
                    saved = pickle.load(file)
            except Exception:
                message = 'Error loading plot settings'
                saved = {'version': None, 'current': None}
            if saved['version'] == self.model.version:
                self.model.activeView = saved['current']
                self.dock.updateDock()
                self.colorDialog.updateDialogValues()
                self.applyChanges()
                message = '{} settings loaded'.format(filename)
            else:
                message = 'Error loading plot settings. Incompatible model.'
            self.statusBar().showMessage(message, 5000)

    def openStatePoint(self):
        # check for an alread-open statepoint
        if self.model.statepoint:
            msg_box = QMessageBox()
            msg_box.setText("Please close the current statepoint file before "
                            "opening a new one.")
            msg_box.setIcon(QMessageBox.Information)
            msg_box.setStandardButtons(QMessageBox.Ok)
            msg_box.exec_()
            return
        filename, ext = QFileDialog.getOpenFileName(self, "Open StatePoint",
                                                    ".", "statepoint*.h5")
        if filename:
            try:
                self.model.openStatePoint(filename)
                message = 'Opened statepoint file: {}'
            except (FileNotFoundError, OSError):
                message = 'Error opening statepoint file: {}'
                msg_box = QMessageBox()
                msg = "Could open statepoint file: \n\n {} \n"
                msg_box.setText(msg.format(filename))
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setStandardButtons(QMessageBox.Ok)
                msg_box.exec_()
            finally:
                self.statusBar().showMessage(message.format(filename), 5000)
            self.updateDataMenu()
            self.tallyDock.update()

    def closeStatePoint(self):
        # remove the statepoint object and update the data menu
        filename = self.model.statepoint.filename
        self.model.statepoint = None
        self.model.currentView.selectedTally = None
        self.model.activeView.selectedTally = None

        msg = "Closed statepoint file {}".format(filename)
        self.statusBar().showMessage(msg)
        self.updateDataMenu()
        self.tallyDock.selectTally()
        self.tallyDock.update()
        self.plotIm.updatePixmap()

    def updateDataMenu(self):
        if self.model.statepoint:
            self.closeStatePointAction = QAction("&Close statepoint", self)
            self.closeStatePointAction.setToolTip("Close current statepoint")
            self.closeStatePointAction.triggered.connect(self.closeStatePoint)
            self.dataMenu.addAction(self.closeStatePointAction)
        elif hasattr(self, "closeStatePointAction"):
            self.dataMenu.removeAction(self.closeStatePointAction)

    def applyChanges(self):
        if self.model.activeView != self.model.currentView:
            self.statusBar().showMessage('Generating Plot...')
            QApplication.processEvents()
            self.model.storeCurrent()
            self.model.subsequentViews = []
            self.plotIm.generatePixmap()
            self.resetModels()
            self.showCurrentView()
            self.statusBar().showMessage('')
        else:
            self.statusBar().showMessage('No changes to apply.', 3000)

    def undo(self):
        self.statusBar().showMessage('Generating Plot...')
        QApplication.processEvents()

        self.model.undo()
        self.resetModels()
        self.showCurrentView()
        self.dock.updateDock()
        self.colorDialog.updateDialogValues()

        if not self.model.previousViews:
            self.undoAction.setDisabled(True)
        self.redoAction.setDisabled(False)
        self.statusBar().showMessage('')

    def redo(self):
        self.statusBar().showMessage('Generating Plot...')
        QApplication.processEvents()

        self.model.redo()
        self.resetModels()
        self.showCurrentView()
        self.dock.updateDock()
        self.colorDialog.updateDialogValues()

        if not self.model.subsequentViews:
            self.redoAction.setDisabled(True)
        self.undoAction.setDisabled(False)
        self.statusBar().showMessage('')

    def restoreDefault(self):
        if self.model.currentView != self.model.defaultView:

            self.statusBar().showMessage('Generating Plot...')
            QApplication.processEvents()

            self.model.storeCurrent()
            self.model.activeView.adopt_plotbase(self.model.defaultView)
            self.plotIm.generatePixmap()
            self.resetModels()
            self.showCurrentView()
            self.dock.updateDock()
            self.colorDialog.updateDialogValues()

            self.model.subsequentViews = []
            self.statusBar().showMessage('')

    def editBasis(self, basis, apply=False):
        self.model.activeView.basis = basis
        self.dock.updateBasis()
        if apply:
            self.applyChanges()

    def editColorBy(self, domain_kind, apply=False):
        self.model.activeView.colorby = domain_kind
        self.dock.updateColorBy()
        self.colorDialog.updateColorBy()
        if apply:
            self.applyChanges()

    def toggleOverlaps(self, state, apply=False):
        self.model.activeView.color_overlaps = bool(state)
        self.colorDialog.updateOverlap()
        if apply:
            self.applyChanges()

    def editColorMap(self, colormap_name, property_type, apply=False):
        self.model.activeView.colormaps[property_type] = colormap_name
        self.plotIm.updateColorMap(colormap_name, property_type)
        self.colorDialog.updateColorMaps()
        if apply:
            self.applyChanges()

    def editColorbarMin(self, min_val, property_type, apply=False):
        av = self.model.activeView
        current = av.user_minmax[property_type]
        av.user_minmax[property_type] = (min_val, current[1])
        self.colorDialog.updateColorMinMax()
        self.plotIm.updateColorMinMax(property_type)
        if apply:
            self.applyChanges()

    def editColorbarMax(self, max_val, property_type, apply=False):
        av = self.model.activeView
        current = av.user_minmax[property_type]
        av.user_minmax[property_type] = (current[0], max_val)
        self.colorDialog.updateColorMinMax()
        self.plotIm.updateColorMinMax(property_type)
        if apply:
            self.applyChanges()

    def toggleColorbarScale(self, state, property, apply=False):
        av = self.model.activeView
        av.color_scale_log[property] = bool(state)
        # temporary, should be resolved diferently in the future
        cv = self.model.currentView
        cv.color_scale_log[property] = bool(state)
        self.plotIm.updateColorbarScale()
        if apply:
            self.applyChanges()

    def toggleUserMinMax(self, state, property):
        av = self.model.activeView
        av.use_custom_minmax[property] = bool(state)
        if av.user_minmax[property] == (0.0, 0.0):
            av.user_minmax[property] = copy.copy(av.data_minmax[property])
        self.plotIm.updateColorMinMax('temperature')
        self.plotIm.updateColorMinMax('density')
        self.colorDialog.updateColorMinMax()

    def toggleDataIndicatorCheckBox(self, state, property, apply=False):
        av = self.model.activeView
        av.data_indicator_enabled[property] = bool(state)

        cv = self.model.currentView
        cv.data_indicator_enabled[property] = bool(state)

        self.plotIm.updateDataIndicatorVisibility()
        if apply:
            self.applyChanges()

    def toggleMasking(self, state, apply=False):
        self.model.activeView.masking = bool(state)
        self.colorDialog.updateMasking()
        if apply:
            self.applyChanges()

    def toggleHighlighting(self, state, apply=False):
        self.model.activeView.highlighting = bool(state)
        self.colorDialog.updateHighlighting()
        if apply:
            self.applyChanges()

    def toggleDockView(self):
        if self.dock.isVisible():
            self.dock.hide()
            if not self.isMaximized() and not self.dock.isFloating():
                self.resize(self.width() - self.dock.width(), self.height())
        else:
            self.dock.setVisible(True)
            if not self.isMaximized() and not self.dock.isFloating():
                self.resize(self.width() + self.dock.width(), self.height())
        self.resizePixmap()
        self.showMainWindow()

    def toggleTallyDockView(self):
        if self.tallyDock.isVisible():
            self.tallyDock.hide()
            if not self.isMaximized() and not self.tallyDock.isFloating():
                self.resize(self.width() - self.tallyDock.width(),
                            self.height())
        else:
            self.tallyDock.setVisible(True)
            if not self.isMaximized() and not self.tallyDock.isFloating():
                self.resize(self.width() + self.tallyDock.width(),
                            self.height())
        self.resizePixmap()
        self.showMainWindow()

    def editZoomAct(self):
        percent, ok = QInputDialog.getInt(self, "Edit Zoom", "Zoom Percent:",
                                          self.dock.zoomBox.value(), 25, 2000)
        if ok:
            self.dock.zoomBox.setValue(percent)

    def editZoom(self, value):
        self.zoom = value
        self.resizePixmap()
        self.dock.zoomBox.setValue(value)

    def showMainWindow(self):
        self.raise_()
        self.activateWindow()

    def showColorDialog(self):
        self.colorDialog.show()
        self.colorDialog.raise_()
        self.colorDialog.activateWindow()

    def showExportDialog(self):
        self.exportDataDialog.show()
        self.exportDataDialog.raise_()
        self.exportDataDialog.activateWindow()

    # Dock methods:

    def editSingleOrigin(self, value, dimension):
        self.model.activeView.origin[dimension] = value

    def editPlotAlpha(self, value):
        self.model.activeView.domainAlpha = value

    def editPlotVisibility(self, value):
        self.model.activeView.domainVisible = bool(value)

    def toggleOutlines(self, value, apply=False):
        self.model.activeView.outlines = bool(value)
        self.dock.updateOutlines()

        if apply:
            self.applyChanges()

    def editWidth(self, value):
        self.model.activeView.width = value
        self.onRatioChange()
        self.dock.updateWidth()

    def editHeight(self, value):
        self.model.activeView.height = value
        self.onRatioChange()
        self.dock.updateHeight()

    def toggleAspectLock(self, state):
        self.model.activeView.aspectLock = bool(state)
        self.onRatioChange()
        self.dock.updateAspectLock()

    def editVRes(self, value):
        self.model.activeView.v_res = value
        self.dock.updateVRes()

    def editHRes(self, value):
        self.model.activeView.h_res = value
        self.onRatioChange()
        self.dock.updateHRes()

    # Color dialog methods:

    def editMaskingColor(self):
        current_color = self.model.activeView.maskBackground
        dlg = QColorDialog(self)

        dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            self.model.activeView.maskBackground = new_color
            self.colorDialog.updateMaskingColor()

    def editHighlightColor(self):
        current_color = self.model.activeView.highlightBackground
        dlg = QColorDialog(self)

        dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            self.model.activeView.highlightBackground = new_color
            self.colorDialog.updateHighlightColor()

    def editAlpha(self, value):
        self.model.activeView.highlightAlpha = value

    def editSeed(self, value):
        self.model.activeView.highlightSeed = value

    def editOverlapColor(self, apply=False):
        current_color = self.model.activeView.overlap_color
        dlg = QColorDialog(self)
        dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            self.model.activeView.overlap_color = new_color
            self.colorDialog.updateOverlapColor()

        if apply:
            self.applyChanges()

    def editBackgroundColor(self, apply=False):
        current_color = self.model.activeView.domainBackground
        dlg = QColorDialog(self)

        dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            self.model.activeView.domainBackground = new_color
            self.colorDialog.updateBackgroundColor()

        if apply:
            self.applyChanges()

    def resetColors(self):
        self.model.resetColors()
        self.colorDialog.updateDialogValues()
        self.applyChanges()

    # Tally dock methods

    def editSelectedTally(self, event):
        av = self.model.activeView

        if event is None or event == "None" or event == "":
            av.selectedTally = None
        else:
            av.selectedTally = int(event.split()[1])
        self.tallyDock.selectTally(event)

    def editTallyValue(self, event):
        av = self.model.activeView
        av.tallyValue = event

    def updateScores(self, state):
        self.tallyDock.updateScores()

    def updateNuclides(self, state):
        self.tallyDock.updateNuclides()

    def toggleTallyVisibility(self, state, apply=False):
        av = self.model.activeView
        av.tallyDataVisible = bool(state)
        if apply:
            self.applyChanges()

    def toggleTallyLogScale(self, state, apply=False):
        av = self.model.activeView
        av.tallyDataLogScale = bool(state)
        if apply:
            self.applyChanges()

    def toggleTallyMaskZero(self, state):
        av = self.model.activeView
        av.tallyMaskZeroValues = bool(state)

    def editTallyAlpha(self, value, apply=False):
        av = self.model.activeView
        av.tallyDataAlpha = value
        if apply:
            self.applyChanges()

    def toggleTallyContours(self, state):
        av = self.model.activeView
        av.tallyContours = bool(state)

    def editTallyContourLevels(self, value):
        av = self.model.activeView
        av.tallyContourLevels = value

    def toggleTallyDataIndicator(self, state, apply=False):
        av = self.model.activeView
        av.tallyDataIndicator = bool(state)
        if apply:
            self.applyChanges()

    def toggleTallyDataClip(self, state):
        av = self.model.activeView
        av.clipTallyData = bool(state)

    def toggleTallyDataUserMinMax(self, state, apply=False):
        av = self.model.activeView
        av.tallyDataUserMinMax = bool(state)
        self.tallyDock.tallyColorForm.setMinMaxEnabled(bool(state))
        if apply:
            self.applyChanges()

    def editTallyDataMin(self, value, apply=False):
        av = self.model.activeView
        av.tallyDataMin = value
        if apply:
            self.applyChanges()

    def editTallyDataMax(self, value, apply=False):
        av = self.model.activeView
        av.tallyDataMax = value
        if apply:
            self.applyChanges()

    def editTallyDataColormap(self, cmap, apply=False):
        av = self.model.activeView
        av.tallyDataColormap = cmap
        if apply:
            self.applyChanges()

    def updateTallyMinMax(self):
        self.tallyDock.updateMinMax()

    # Plot image methods
    def editPlotOrigin(self, xOr, yOr, zOr=None, apply=False):
        if zOr is not None:
            self.model.activeView.origin = [xOr, yOr, zOr]
        else:
            origin = [None, None, None]
            origin[self.xBasis] = xOr
            origin[self.yBasis] = yOr
            origin[self.zBasis] = self.model.activeView.origin[self.zBasis]
            self.model.activeView.origin = origin

        self.dock.updateOrigin()

        if apply:
            self.applyChanges()

    def revertDockControls(self):
        self.dock.revertToCurrent()

    def editDomainColor(self, kind, id):
        if kind == 'Cell':
            domain = self.model.activeView.cells
        else:
            domain = self.model.activeView.materials

        current_color = domain[id].color
        dlg = QColorDialog(self)

        if isinstance(current_color, tuple):
            dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        elif isinstance(current_color, str):
            current_color = openmc.plots._SVG_COLORS[current_color]
            dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            domain[id].color = new_color

        self.applyChanges()

    def toggleDomainMask(self, state, kind, id):
        if kind == 'Cell':
            domain = self.model.activeView.cells
        else:
            domain = self.model.activeView.materials

        domain[id].masked = bool(state)
        self.applyChanges()

    def toggleDomainHighlight(self, state, kind, id):
        if kind == 'Cell':
            domain = self.model.activeView.cells
        else:
            domain = self.model.activeView.materials

        domain[id].highlight = bool(state)
        self.applyChanges()

    # Helper methods:

    def restoreWindowSettings(self):
        settings = QtCore.QSettings()

        self.resize(settings.value("mainWindow/Size", QtCore.QSize(800, 600)))
        self.move(
            settings.value("mainWindow/Position", QtCore.QPoint(100, 100)))
        self.restoreState(settings.value("mainWindow/State"))

        self.colorDialog.resize(
            settings.value("colorDialog/Size", QtCore.QSize(400, 500)))
        self.colorDialog.move(
            settings.value("colorDialog/Position", QtCore.QPoint(600, 200)))
        is_visible = settings.value("colorDialog/Visible", 0)
        # some versions of PySide will return None rather than the default value
        if is_visible is None:
            is_visible = False
        else:
            is_visible = bool(int(is_visible))

        self.colorDialog.setVisible(is_visible)

    def restoreModelSettings(self):
        if os.path.isfile("plot_settings.pkl"):

            with open('plot_settings.pkl', 'rb') as file:
                model = pickle.load(file)

            # do not replace model if the version is out of date
            if model.version != self.model.version:
                print("WARNING: previous plot settings are for a different "
                      "version of the GUI. They will be ignored.")
                wrn_msg = "Existing version: {}, Current GUI version: {}"
                print(wrn_msg.format(model.version, self.model.version))
                return

            try:
                self.model.statepoint = model.statepoint
            except OSError:
                msg_box = QMessageBox()
                msg = "Could open statepoint file: \n\n {} \n"
                msg_box.setText(msg.format(self.model.statepoint.filename))
                msg_box.setIcon(QMessageBox.Warning)
                msg_box.setStandardButtons(QMessageBox.Ok)
                msg_box.exec_()
                self.model.statepoint = None

            self.model.currentView = model.currentView
            self.model.activeView = copy.deepcopy(model.currentView)
            self.model.previousViews = model.previousViews
            self.model.subsequentViews = model.subsequentViews

    def resetModels(self):
        self.cellsModel = DomainTableModel(self.model.activeView.cells)
        self.materialsModel = DomainTableModel(self.model.activeView.materials)
        self.cellsModel.beginResetModel()
        self.cellsModel.endResetModel()
        self.materialsModel.beginResetModel()
        self.materialsModel.endResetModel()
        self.colorDialog.updateDomainTabs()

    def showCurrentView(self):
        self.updateScale()
        self.updateRelativeBases()
        self.plotIm.updatePixmap()

        if self.model.previousViews:
            self.undoAction.setDisabled(False)
        if self.model.subsequentViews:
            self.redoAction.setDisabled(False)
        else:
            self.redoAction.setDisabled(True)

        self.adjustWindow()

    def updateScale(self):
        cv = self.model.currentView
        self.scale = (cv.h_res / cv.width, cv.v_res / cv.height)

    def updateRelativeBases(self):
        cv = self.model.currentView
        self.xBasis = 0 if cv.basis[0] == 'x' else 1
        self.yBasis = 1 if cv.basis[1] == 'y' else 2
        self.zBasis = 3 - (self.xBasis + self.yBasis)

    def adjustWindow(self):
        self.setMaximumSize(self.screen.width(), self.screen.height())

    def onRatioChange(self):
        av = self.model.activeView
        if av.aspectLock:
            ratio = av.width / max(av.height, .001)
            av.v_res = int(av.h_res / ratio)
            self.dock.updateVRes()

    def showCoords(self, xPlotPos, yPlotPos):
        cv = self.model.currentView
        if cv.basis == 'xy':
            coords = ("({}, {}, {})".format(round(xPlotPos, 2),
                                            round(yPlotPos, 2),
                                            round(cv.origin[2], 2)))
        elif cv.basis == 'xz':
            coords = ("({}, {}, {})".format(round(xPlotPos, 2),
                                            round(cv.origin[1], 2),
                                            round(yPlotPos, 2)))
        else:
            coords = ("({}, {}, {})".format(round(cv.origin[0], 2),
                                            round(xPlotPos, 2),
                                            round(yPlotPos, 2)))
        self.coord_label.setText('{}'.format(coords))

    def resizePixmap(self):
        self.plotIm._resize()
        self.plotIm.adjustSize()

    def moveEvent(self, event):
        self.adjustWindow()

    def resizeEvent(self, event):
        self.plotIm._resize()
        self.adjustWindow()
        self.updateScale()
        if self.shortcutOverlay.isVisible():
            self.shortcutOverlay.resize(self.width(), self.height())

    def closeEvent(self, event):
        settings = QtCore.QSettings()
        settings.setValue("mainWindow/Size", self.size())
        settings.setValue("mainWindow/Position", self.pos())
        settings.setValue("mainWindow/State", self.saveState())

        settings.setValue("colorDialog/Size", self.colorDialog.size())
        settings.setValue("colorDialog/Position", self.colorDialog.pos())
        visible = int(self.colorDialog.isVisible())
        settings.setValue("colorDialog/Visible", visible)

        openmc.lib.finalize()

        self.saveSettings()

    def saveSettings(self):

        if len(self.model.previousViews) > 10:
            self.model.previousViews = self.model.previousViews[-10:]
        if len(self.model.subsequentViews) > 10:
            self.model.subsequentViews = self.model.subsequentViews[-10:]

        with open('plot_settings.pkl', 'wb') as file:
            if self.model.statepoint:
                self.model.statepoint.close()
            pickle.dump(self.model, file)

    def exportTallyData(self):
        # show export tool dialog
        self.showExportDialog()
Ejemplo n.º 22
0
class UIMainWindow(object):
    """Container class to hold all UI-related creation methods. Must be sublcassed.
    """

    def create_ui(self):
        """Setup main UI elements, dock widgets, UI-related elements, etc.
        """

        log.debug('Loading UI')

        # Undo Stack
        self.undo_stack = QUndoStack(self)
        self.undo_stack.setUndoLimit(100)

        # Object navigation history
        self.obj_history = deque([], config.MAX_OBJ_HISTORY)

        app = QApplication.instance()
        base_font = QFont()
        base_font.fromString(self.prefs['base_font'])
        app.setFont(base_font)

        # Object class table widget
        # classTable = QTableView(self)
        classTable = classtable.TableView(self)
        classTable.setObjectName("classTable")
        classTable.setAlternatingRowColors(True)
        classTable.setFrameShape(QFrame.StyledPanel)
        classTable_font = QFont()
        classTable_font.fromString(self.prefs['class_table_font'])
        classTable.setFont(classTable_font)
        fm = classTable.fontMetrics()
        classTable.setWordWrap(True)
        classTable.setEditTriggers(QAbstractItemView.EditKeyPressed |
                                   QAbstractItemView.DoubleClicked |
                                   QAbstractItemView.AnyKeyPressed |
                                   QAbstractItemView.SelectedClicked)
        # classTable.horizontalHeader().setMovable(True)
        # classTable.verticalHeader().setMovable(False)
        classTable.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
        classTable.verticalHeader().setSectionResizeMode(QHeaderView.Interactive)
        classTable.horizontalHeader().setDefaultSectionSize(self.prefs['default_column_width'])
        classTable.verticalHeader().setDefaultSectionSize(fm.height() + 0)
        classTable.setSelectionMode(QAbstractItemView.ExtendedSelection)
        classTable.setContextMenuPolicy(Qt.CustomContextMenu)
        classTable.customContextMenuRequested.connect(self.custom_table_context_menu)

        # Create table model and proxy layers for transposing and filtering
        self.classTableModel = classtable.IDFObjectTableModel(classTable)
        self.transposeableModel = classtable.TransposeProxyModel(self.classTableModel)
        self.transposeableModel.setSourceModel(self.classTableModel)
        self.sortableModel = classtable.SortFilterProxyModel(self.transposeableModel)
        self.sortableModel.setSourceModel(self.transposeableModel)

        # Assign model to table (enable sorting FIRST)
        # table.setSortingEnabled(True) # Disable for now, CRUD actions won't work!
        classTable.setModel(self.sortableModel)

        # Connect some signals
        selection_model = classTable.selectionModel()
        selection_model.selectionChanged.connect(self.table_selection_changed)
        scroll_bar = classTable.verticalScrollBar()
        scroll_bar.valueChanged.connect(self.scroll_changed)

        # These are currently broken
        # classTable.horizontalHeader().sectionMoved.connect(self.moveObject)
        # classTable.verticalHeader().sectionMoved.connect(self.moveObject)

        # Object class tree widget
        classTreeDockWidget = QDockWidget("Object Classes and Counts", self)
        classTreeDockWidget.setObjectName("classTreeDockWidget")
        classTreeDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)

        classTree = QTreeView(classTreeDockWidget)
        classTree.setUniformRowHeights(True)
        classTree.setAllColumnsShowFocus(True)
        classTree.setRootIsDecorated(False)
        classTree.setExpandsOnDoubleClick(True)
        classTree.setIndentation(15)
        classTree.setAnimated(True)
        classTree_font = QFont()
        classTree_font.fromString(self.prefs['class_tree_font'])
        classTree.setFont(classTree_font)
        classTree.setAlternatingRowColors(True)
        classTree.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        palette = classTree.palette()
        palette.setColor(QPalette.Highlight, Qt.darkCyan)
        classTree.setPalette(palette)

        class_tree_window = QWidget(classTreeDockWidget)
        class_tree_dock_layout_v = QVBoxLayout()
        class_tree_dock_layout_h = QHBoxLayout()
        class_tree_dock_layout_v.setContentsMargins(0, 8, 0, 0)
        class_tree_dock_layout_h.setContentsMargins(0, 0, 0, 0)

        class_tree_filter_edit = QLineEdit(classTreeDockWidget)
        class_tree_filter_edit.setPlaceholderText("Filter Classes")
        class_tree_filter_edit.textChanged.connect(self.treeFilterRegExpChanged)

        class_tree_filter_cancel = QPushButton("Clear", classTreeDockWidget)
        class_tree_filter_cancel.setMaximumWidth(45)
        class_tree_filter_cancel.clicked.connect(self.clearTreeFilterClicked)

        class_tree_dock_layout_h.addWidget(class_tree_filter_edit)
        class_tree_dock_layout_h.addWidget(class_tree_filter_cancel)
        class_tree_dock_layout_v.addLayout(class_tree_dock_layout_h)
        class_tree_dock_layout_v.addWidget(classTree)
        class_tree_window.setLayout(class_tree_dock_layout_v)

        classTreeDockWidget.setWidget(class_tree_window)
        classTreeDockWidget.setContentsMargins(0,0,0,0)

        # Comments widget
        commentDockWidget = QDockWidget("Comments", self)
        commentDockWidget.setObjectName("commentDockWidget")
        commentDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
        commentView = UndoRedoTextEdit(commentDockWidget, self)
        commentView.setLineWrapMode(QTextEdit.FixedColumnWidth)
        commentView.setLineWrapColumnOrWidth(499)
        commentView.setFrameShape(QFrame.StyledPanel)
        commentView_font = QFont()
        commentView_font.fromString(self.prefs['comments_font'])
        commentView.setFont(commentView_font)
        commentDockWidget.setWidget(commentView)

        # Info and help widget
        infoDockWidget = QDockWidget("Info", self)
        infoDockWidget.setObjectName("infoDockWidget")
        infoDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
        infoView = QTextEdit(infoDockWidget)
        infoView.setFrameShape(QFrame.StyledPanel)
        infoView.setReadOnly(True)
        infoDockWidget.setWidget(infoView)

        # Node list and jump menu widget
        refDockWidget = QDockWidget("Field References", self)
        refDockWidget.setObjectName("refDockWidget")
        refDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
        ref_model = reftree.ReferenceTreeModel(None, refDockWidget)
        refView = QTreeView(refDockWidget)
        refView.setModel(ref_model)
        refView.setUniformRowHeights(True)
        refView.setRootIsDecorated(False)
        refView.setIndentation(15)
        refView.setColumnWidth(0, 160)
        refView.setFrameShape(QFrame.StyledPanel)
        refDockWidget.setWidget(refView)
        refView.doubleClicked.connect(self.ref_tree_double_clicked)

        # Logging and debugging widget
        logDockWidget = QDockWidget("Log Viewer", self)
        logDockWidget.setObjectName("logDockWidget")
        logDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
        logView = QPlainTextEdit(logDockWidget)
        logView.setLineWrapMode(QPlainTextEdit.NoWrap)
        logView.setReadOnly(True)
        logView_font = QFont()
        logView_font.fromString(self.prefs['base_font'])
        logView.setFont(logView_font)
        logView.ensureCursorVisible()
        logDockWidget.setWidget(logView)

        # Undo view widget
        undoDockWidget = QDockWidget("Undo History", self)
        undoDockWidget.setObjectName("undoDockWidget")
        undoDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
        undoView = QUndoView(self.undo_stack)
        undoDockWidget.setWidget(undoView)

        # Define corner docking behaviour
        self.setDockNestingEnabled(True)
        self.setCorner(Qt.TopLeftCorner,
                       Qt.LeftDockWidgetArea)
        self.setCorner(Qt.TopRightCorner,
                       Qt.RightDockWidgetArea)
        self.setCorner(Qt.BottomLeftCorner,
                       Qt.LeftDockWidgetArea)
        self.setCorner(Qt.BottomRightCorner,
                       Qt.RightDockWidgetArea)

        # Assign main widget and dock widgets to QMainWindow
        self.setCentralWidget(classTable)
        self.addDockWidget(Qt.LeftDockWidgetArea, classTreeDockWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, commentDockWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, infoDockWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, refDockWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, undoDockWidget)

        # Store widgets for access by other objects
        self.classTable = classTable
        self.commentView = commentView
        self.infoView = infoView
        self.classTree = classTree
        self.logView = logView
        self.undoView = undoView
        self.refView = refView
        self.filterTreeBox = class_tree_filter_edit

        # Store docks for access by other objects
        self.commentDockWidget = commentDockWidget
        self.infoDockWidget = infoDockWidget
        self.classTreeDockWidget = classTreeDockWidget
        self.logDockWidget = logDockWidget
        self.undoDockWidget = undoDockWidget
        self.refDockWidget = refDockWidget

        # Perform other UI-related initialization tasks
        self.center()
        self.setUnifiedTitleAndToolBarOnMac(True)
        self.setWindowIcon(QIcon(':/images/logo.png'))

        # Status bar setup
        self.statusBar().showMessage('Status: Ready')
        self.unitsLabel = QLabel()
        self.unitsLabel.setAlignment(Qt.AlignCenter)
        self.unitsLabel.setMinimumSize(self.unitsLabel.sizeHint())
        self.unitsLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        self.statusBar().addPermanentWidget(self.unitsLabel)
        self.pathLabel = QLabel()
        self.pathLabel.setAlignment(Qt.AlignCenter)
        self.pathLabel.setMinimumSize(self.pathLabel.sizeHint())
        self.pathLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        self.statusBar().addPermanentWidget(self.pathLabel)
        self.versionLabel = QLabel()
        self.versionLabel.setAlignment(Qt.AlignCenter)
        self.versionLabel.setMinimumSize(self.versionLabel.sizeHint())
        self.versionLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        self.statusBar().addPermanentWidget(self.versionLabel)
        self.progressBarIDF = QProgressBar()
        self.progressBarIDF.setAlignment(Qt.AlignCenter)
        self.progressBarIDF.setMaximumWidth(200)
        self.statusBar().addPermanentWidget(self.progressBarIDF)

        self.clipboard = QApplication.instance().clipboard()
        self.obj_clipboard = []

        self.setStyleSheet("""
            QToolTip {
               background-color: gray;
               color: white;
               border: black solid 1px
            } 
            # QMenu {
            #     background-color: rgbf(0.949020, 0.945098, 0.941176);
            #     color: rgb(255,255,255);
            # }
            # QMenu::item::selected {
            #     background-color: rgbf(0.949020, 0.945098, 0.941176);
            # }
            """)

    def create_tray_menu(self):
        """Creates an icon and menu for the system tray
        """

        # Menu for the system tray
        self.trayIconMenu = QMenu(self)
        self.trayIconMenu.addAction(self.minimizeAction)
        self.trayIconMenu.addAction(self.maximizeAction)
        self.trayIconMenu.addAction(self.restoreAction)
        self.trayIconMenu.addSeparator()
        self.trayIconMenu.addAction(self.exitAct)

        # System tray itself
        self.trayIcon = QSystemTrayIcon(self)
        self.trayIcon.setContextMenu(self.trayIconMenu)
        self.trayIcon.setIcon(QIcon(':/images/logo.png'))
        self.trayIcon.setToolTip('IDF+')
        self.trayIcon.show()

    def create_actions(self):
        """Creates appropriate actions for use in menus and toolbars.
        """

        self.newAct = QAction(QIcon(':/images/new1.png'), "&New", self,
                                    shortcut=QKeySequence.New,
                                    statusTip="Create a new file",
                                    iconVisibleInMenu=True,
                                    triggered=self.new_file)

        self.openAct = QAction(QIcon(':/images/open.png'), "&Open...", self,
                                     shortcut=QKeySequence.Open,
                                     statusTip="Open an existing file",
                                     iconVisibleInMenu=True,
                                     triggered=self.open_file)

        self.saveAct = QAction(QIcon(':/images/save.png'), "&Save", self,
                                     shortcut=QKeySequence.Save,
                                     statusTip="Save the document to disk",
                                     iconVisibleInMenu=True,
                                     triggered=self.save)

        self.saveFormatAct = QAction(QIcon(':/images/save.png'), "&Format && Save",
                                     self, shortcut=QKeySequence('Ctrl+Shift+F'),
                                     statusTip="Format File and Save to disk",
                                     iconVisibleInMenu=True,
                                     triggered=self.format_save)

        self.saveAsAct = QAction(QIcon(':/images/saveas.png'), "Save &As...", self,
                                       shortcut=QKeySequence.SaveAs,
                                       statusTip="Save the document under a new name",
                                       iconVisibleInMenu=True,
                                       triggered=self.save_as)

        self.exitAct = QAction(QIcon(':/images/quit.png'), "E&xit", self,
                                     shortcut=QKeySequence('Ctrl+Q'),
                                     iconVisibleInMenu=True,
                                     statusTip="Exit the application",
                                     triggered=self.closeAllWindows)

        self.cutObjAct = QAction(QIcon(':/images/cut.png'), "Cu&t Object", self,
                                       shortcut=QKeySequence.Cut,
                                       statusTip="Cut current selection's contents to clipboard",
                                       iconVisibleInMenu=True,
                                       triggered=self.cutObject,
                                       iconText='Cut Obj')

        self.copyAct = QAction(QIcon(':/images/copy.png'),
                                     "&Copy Selected Values", self,
                                     statusTip="Copy current selection's contents to clipboard",
                                     iconVisibleInMenu=True,
                                     triggered=self.copySelected)

        self.pasteAct = QAction(QIcon(':/images/paste.png'),
                                      "&Paste Selected Values", self,
                                      statusTip="Paste clipboard into current selection",
                                      iconVisibleInMenu=True,
                                      triggered=self.pasteSelected)

        self.pasteExtAct = QAction(QIcon(':/images/paste.png'),
                                      "&Paste from External", self,
                                      shortcut=QKeySequence('Ctrl+Shift+v'),
                                      statusTip="Paste from external program",
                                      iconVisibleInMenu=True,
                                      triggered=self.paste_from_external)

        self.transposeAct = QAction("Transpose", self,
                                          shortcut=QKeySequence('Ctrl+t'),
                                          statusTip="Transpose rows and columns in object display",
                                          triggered=self.transpose_table)

        self.newObjAct = QAction(QIcon(':/images/new2.png'), "New Object", self,
                                       shortcut=QKeySequence('Ctrl+Shift+n'),
                                       statusTip="Create new object in current class",
                                       iconVisibleInMenu=True,
                                       triggered=self.newObject,
                                       iconText='New Obj')

        self.copyObjAct = QAction(QIcon(':/images/copy.png'), "Copy Object", self,
                                        shortcut=QKeySequence.Copy,
                                        statusTip="Copy the current Object(s)",
                                        iconVisibleInMenu=True,
                                        triggered=self.copyObject,
                                        iconText='Copy Obj')

        self.pasteObjAct = QAction(QIcon(':/images/paste.png'), "Paste Object", self,
                                         shortcut=QKeySequence.Paste,
                                         statusTip="Paste the currently copies Object(s)",
                                         iconVisibleInMenu=True,
                                         triggered=self.pasteObject,
                                         iconText='Paste Obj')

        self.dupObjAct = QAction(QIcon(':/images/copy.png'), "Duplicate Object", self,
                                       shortcut=QKeySequence('Shift+Ctrl+d'),
                                       statusTip="Duplicate the current Object(s)",
                                       iconVisibleInMenu=True,
                                       triggered=self.duplicateObject,
                                       iconText='Dup Obj')

        self.delObjAct = QAction(QIcon(':/images/delete.png'), "Delete Object", self,
                                       shortcut=QKeySequence.Delete,
                                       statusTip="Delete the current Object(s)",
                                       iconVisibleInMenu=True,
                                       triggered=self.deleteObject,
                                       iconText='Del Obj')

        self.undoAct = QAction(QIcon(':/images/undo.png'), "&Undo", self,
                                     shortcut=QKeySequence.Undo,
                                     statusTip="Undo previous action",
                                     iconVisibleInMenu=True,
                                     triggered=self.undo_stack.undo)

        self.redoAct = QAction(QIcon(':/images/redo.png'), "&Redo", self,
                                     shortcut=QKeySequence.Redo,
                                     statusTip="Redo previous action",
                                     iconVisibleInMenu=True,
                                     triggered=self.undo_stack.redo)

        self.groupAct = QAction("Hide Groups in Class Tree", self,
                                      shortcut=QKeySequence('Ctrl+g'),
                                      triggered=self.toggle_groups,
                                      checkable=True)

        # self.navForwardAct = QAction("Forward", self,
        #         shortcut=QKeySequence('Ctrl+Plus'),
        #         statusTip="Go forward to the next object",
        #         triggered=self.navForward)
        #
        # self.navBackAct = QAction("Back", self,
        #         shortcut=QKeySequence('Ctrl+Minus'),
        #         statusTip="Go back to the previous object",
        #         triggered=self.navBack)

        self.showInFolderAct = QAction(QIcon(':/images/new.png'), "&Show in folder",
                                             self, shortcut=QKeySequence('Ctrl+Shift+t'),
                                             statusTip="Open location of current file",
                                             iconVisibleInMenu=True)
        self.showInFolderAct.triggered.connect(lambda: self.show_in_folder())

        self.epDocGettingStartedAction = QAction("EnergyPlus Getting Started", self,
                                                       triggered=self.energy_plus_docs)

        self.epDocIORefAction = QAction("EnergyPlus I/O Reference", self,
                                              triggered=self.energy_plus_docs)

        self.epDocOutputDetailsAction = QAction("EnergyPlus Output Details and Examples",
                                                      self, triggered=self.energy_plus_docs)

        self.epDocEngineeringRefAction = QAction("EnergyPlus Engineering Reference", self,
                                                       triggered=self.energy_plus_docs)

        self.epDocAuxiliaryProgsAction = QAction("EnergyPlus Auxiliary Programs", self,
                                                       triggered=self.energy_plus_docs)

        self.epDocEMSGuideAction = QAction("EnergyPlus EMS Application Guide", self,
                                                 triggered=self.energy_plus_docs)

        self.epDocComplianceAction = QAction("Using EnergyPlus for Compliance", self,
                                                   triggered=self.energy_plus_docs)

        self.epDocInterfaceAction = QAction("External Interface Application Guide", self,
                                                  triggered=self.energy_plus_docs)

        self.epDocTipsTricksAction = QAction("Tips and Tricks Using EnergyPlus", self,
                                                   triggered=self.energy_plus_docs)

        self.epDocPlantGuideAction = QAction("EnergyPlus Plant Application Guide", self,
                                                   triggered=self.energy_plus_docs)

        self.epDocAcknowledgmentsAction = QAction("EnergyPlus Acknowledgments", self,
                                                        triggered=self.energy_plus_docs)

        self.openInEditorAct = QAction(QIcon(':/images/new.png'),
                                             "&Open in text editor", self,
                                             shortcut=QKeySequence('Ctrl+e'),
                                             statusTip="Open current file in default editor",
                                             iconVisibleInMenu=True,
                                             triggered=self.open_in_text_editor)

        self.helpAct = QAction("&EnergyPlus Help (Online)", self,
                                     statusTip="Show the EnergyPlus' help",
                                     triggered=self.energyplus_help)

        self.aboutAct = QAction("&About IDF+", self,
                                      statusTip="Show the application's About box",
                                      triggered=self.about)

        self.clearRecentAct = QAction("Clear Recent", self,
                                            statusTip="Clear recent files",
                                            triggered=self.clear_recent)

        self.minimizeAction = QAction("Mi&nimize", self,
                                            triggered=self.hide)

        self.maximizeAction = QAction("Ma&ximize", self,
                                            triggered=self.showMaximized)

        self.restoreAction = QAction("&Restore", self,
                                           triggered=self.showNormal)

        self.showPrefsAction = QAction("&Preferences", self,
                                             triggered=self.show_prefs_dialog)

        self.showSearchAction = QAction("&Search && Replace", self,
                                              shortcut=QKeySequence('Ctrl+f'),
                                              triggered=self.show_search_dialog)

        self.findThisAct = QAction("Find This", self,
                                         triggered=self.find_this)

        self.jumpFilterGeometry = QAction("Include Geometry", self,
                                                triggered=self.jump_to_filter_geometry,
                                                checkable=True)

        self.setIPUnitsAction = QAction("&IP Units", self,
                                              triggered=self.toggle_units,
                                              checkable=True)

        self.setSIUnitsAction = QAction("&SI Units", self,
                                              triggered=self.toggle_units,
                                              checkable=True)

        self.classWithObjsAction = QAction("Show Only Classes With Objects", self,
                                                 shortcut=QKeySequence('Ctrl+l'),
                                                 statusTip="Show Only Classes With Objects",
                                                 triggered=self.toggle_full_tree,
                                                 checkable=True)

        self.fillRightAction = QAction("Fill right", self,
                                             shortcut=QKeySequence('Ctrl+d'),
                                             statusTip="Fill right",
                                             triggered=self.fill_right)

        self.logDockWidgetAct = self.logDockWidget.toggleViewAction()
        self.transposeAct.setEnabled(False)
        self.setSIUnitsAction.setChecked(True)
        self.undoAct.setEnabled(False)
        self.redoAct.setEnabled(False)
        self.saveAct.setEnabled(False)
        self.undo_stack.canUndoChanged.connect(self.toggle_can_undo)
        self.undo_stack.canRedoChanged.connect(self.toggle_can_redo)
        self.logDockWidgetAct.toggled.connect(self.start_log_watcher)

    def toggle_can_undo(self):
        if self.undo_stack.canUndo():
            new_state = True
        else:
            new_state = False
        self.undoAct.setEnabled(new_state)
        self.set_dirty(new_state)

    def toggle_can_redo(self):
        if self.undo_stack.canRedo():
            new_state = True
        else:
            new_state = False
        self.redoAct.setEnabled(new_state)

    def create_menus(self):
        """Create all required items for menus.
        """

        # File Menu
        self.fileMenu = self.menuBar().addMenu("&File")
        self.fileMenuActions = (self.newAct, self.openAct, self.saveAct,
                                self.saveAsAct, self.saveFormatAct, None, self.exitAct)
        self.update_file_menu()
        self.fileMenu.aboutToShow.connect(self.update_file_menu)

        # Edit Menu
        self.editMenu = self.menuBar().addMenu("&Edit")
        self.editMenu.addAction(self.undoAct)
        self.editMenu.addAction(self.redoAct)
        self.editMenu.addSeparator().setText('Objects')
        self.editMenu.addAction(self.newObjAct)
        self.editMenu.addAction(self.dupObjAct)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.cutObjAct)
        self.editMenu.addAction(self.copyObjAct)
        self.editMenu.addAction(self.pasteObjAct)
        self.editMenu.addAction(self.pasteExtAct)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.delObjAct)
        self.editMenu.addSeparator().setText('Values')
        self.editMenu.addAction(self.copyAct)
        self.editMenu.addAction(self.pasteAct)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.fillRightAction)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.showSearchAction)

        # Tools Menu
        self.toolsMenu = self.menuBar().addMenu("&Tools")
        self.toolsMenu.addAction(self.showInFolderAct)
        self.toolsMenu.addAction(self.openInEditorAct)
        self.toolsMenu.addSeparator()
        self.toolsMenu.addAction(self.showPrefsAction)

        # View Menu
        self.viewMenu = self.menuBar().addMenu("&View")
        action_group = QActionGroup(self)
        self.viewMenu.addAction(action_group.addAction(self.setSIUnitsAction))
        self.viewMenu.addAction(action_group.addAction(self.setIPUnitsAction))
        self.viewMenu.addSeparator().setText('Dockable Widgets')
        self.viewMenu.addAction(self.classTreeDockWidget.toggleViewAction())
        self.viewMenu.addAction(self.infoView.parent().toggleViewAction())
        self.viewMenu.addAction(self.commentView.parent().toggleViewAction())
        self.viewMenu.addAction(self.logDockWidgetAct)
        self.viewMenu.addAction(self.undoView.parent().toggleViewAction())
        self.viewMenu.addSeparator().setText('Toolbars')
        self.viewMenu.addAction(self.fileToolBar.toggleViewAction())
        self.viewMenu.addAction(self.editToolBar.toggleViewAction())
        # self.viewMenu.addAction(self.navToolBar.toggleViewAction())
        self.viewMenu.addAction(self.filterToolBar.toggleViewAction())
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.classWithObjsAction)
        self.viewMenu.addAction(self.groupAct)
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.transposeAct)

        # Jump Menu
        self.jumpToMenu = self.menuBar().addMenu("&Jump")
        self.update_jump_menu()
        self.jumpToMenu.aboutToShow.connect(self.update_jump_menu)
        self.jumpFilterGeometry.setEnabled(False)

        # Help Menu
        self.helpMenu = self.menuBar().addMenu("&Help")
        self.helpMenu.addAction(self.helpAct)
        self.helpMenu.addAction(self.aboutAct)
        self.helpMenu.addSeparator()
        self.helpMenu.addAction(self.epDocGettingStartedAction)
        self.helpMenu.addAction(self.epDocIORefAction)
        self.helpMenu.addAction(self.epDocOutputDetailsAction)
        self.helpMenu.addAction(self.epDocEngineeringRefAction)
        self.helpMenu.addAction(self.epDocAuxiliaryProgsAction)
        self.helpMenu.addAction(self.epDocEMSGuideAction)
        self.helpMenu.addAction(self.epDocComplianceAction)
        self.helpMenu.addAction(self.epDocInterfaceAction)
        self.helpMenu.addAction(self.epDocTipsTricksAction)
        self.helpMenu.addAction(self.epDocPlantGuideAction)
        self.helpMenu.addAction(self.epDocAcknowledgmentsAction)

    def create_tool_bars(self):
        """Creates the necessary toolbars.
        """

        # File Toolbar
        self.fileToolBar = self.addToolBar("File Toolbar")
        self.fileToolBar.setObjectName('fileToolbar')
        self.fileToolBar.addAction(self.newAct)
        self.fileToolBar.addAction(self.openAct)
        self.fileToolBar.addAction(self.saveAct)
        self.fileToolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

        # Edit Toolbar
        self.editToolBar = self.addToolBar("Edit Toolbar")
        self.editToolBar.setObjectName('editToolbar')
        self.editToolBar.addAction(self.undoAct)
        self.editToolBar.addAction(self.redoAct)
        self.editToolBar.addAction(self.newObjAct)
        self.editToolBar.addAction(self.dupObjAct)
        self.editToolBar.addAction(self.delObjAct)
        self.editToolBar.addAction(self.cutObjAct)
        self.editToolBar.addAction(self.copyObjAct)
        self.editToolBar.addAction(self.pasteObjAct)
        self.editToolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

        # Object history navigation toolbar
        # self.navToolBar = self.addToolBar("Navigation Toolbar")
        # self.navToolBar.setObjectName('viewToolBar')
        # self.navToolBar.addAction(self.navForwardAct)
        # self.navToolBar.addAction(self.navBackAct)
        # self.navToolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

        # Object filter toolbar
        self.filterToolBar = self.addToolBar("Filter Toolbar")
        self.filterToolBar.setObjectName('filterToolBar')
        self.filterBox = QLineEdit()
        self.filterBox.setPlaceholderText("Filter Objects")
        self.filterBox.setMaximumWidth(160)
        self.filterBox.setFixedWidth(160)
        # filterLabel = QLabel("Filter Obj:", self)
        # filterLabel.setBuddy(self.filterBox)
        # self.filterToolBar.addWidget(filterLabel)
        self.filterBox.textChanged.connect(self.tableFilterRegExpChanged)
        self.filterBox.textChanged.connect(self.treeFilterRegExpChanged)
        clearFilterButton = QPushButton('Clear')
        clearFilterButton.setMaximumWidth(45)
        clearFilterButton.clicked.connect(self.clearFilterClicked)
        self.filterToolBar.addWidget(self.filterBox)
        self.filterToolBar.addWidget(clearFilterButton)
        self.caseSensitivity = QCheckBox('Case Sensitive')
        self.caseSensitivity.stateChanged.connect(self.caseSensitivityChanged)
        self.filterToolBar.addWidget(self.caseSensitivity)
        self.filterToolBar.addSeparator()
        self.filterToolBar.addAction(self.transposeAct)

    def create_shortcuts(self):
        """Creates keyboard shortcuts.
        """

        # QShortcut(QKeySequence('Ctrl+l'), self).activated.connect(self.toggle_full_tree)
        # QShortcut(QKeySequence('Ctrl+d'), self).activated.connect(self.fill_right)
        # QShortcut(QKeySequence('Ctrl+d'), self).activated.connect(self.fill_right)

#    def createAction(self, text, slot=None, shortcut=None, icon=None,
#                     tip=None, checkable=False, signal="triggered()"):
#        action = QAction(text, self)
#        if icon is not None:
#            action.setIcon(QIcon(":/%s.png" % icon))
#        if shortcut is not None:
#            action.setShortcut(shortcut)
#        if tip is not None:
#            action.setToolTip(tip)
#            action.setStatusTip(tip)
#        if slot is not None:
#            self.connect(action, QtCore.SIGNAL(signal), slot)
#        if checkable:
#            action.setCheckable(True)
#        return action
#

    def custom_table_context_menu(self, position):

        # Create a menu and populate it with actions
        menu = QMenu(self)
        menu.addAction(self.undoAct)
        menu.addAction(self.redoAct)
        menu.addSeparator()
        menu.addAction(self.copyObjAct)
        menu.addAction(self.dupObjAct)
        menu.addAction(self.delObjAct)
        menu.addAction(self.newObjAct)
        menu.addAction(self.cutObjAct)
        menu.addSeparator()
        menu.addMenu(self.jumpToMenu)
        menu.addSeparator()
        menu.addAction(self.findThisAct)
        menu.popup(self.classTable.viewport().mapToGlobal(position))
        self.mouse_position = position

    def reset_progress_bar(self):
        self.progressBarIDF.hide()

    def center(self):
        """Called to center the window on the screen on startup.
        """

        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width() - size.width()) / 2,
                  (screen.height() - size.height()) / 2)

    def show_prefs_dialog(self):
        """Handles showing the settings dialog and setting its values.
        """

        dlg = PrefsDialog(self, self.prefs)
        if dlg.exec_():
            # Refresh the table view to take into account any new prefs
            self.load_table_view(self.current_obj_class)

            # Clear the idd cache if requested
            if self.prefs.get('clear_idd_cache', False) == True:
                self.clear_idd_cache()

            # Update preferences if various flags apply
            if not self.idf:
                return
            options_dict = dict()
            if self.prefs.get('apply_default_save_behaviour', False) == True:
                options_dict.update({'sort_order': self.prefs.get('sort_order'),
                                     'special_formatting': self.prefs.get('special_formatting')})
            # if self.prefs.get('apply_default_units_behaviour', False) == True:
            #     options_dict.update({'save_units': self.prefs.get('save_units')})
            # if self.prefs.get('apply_default_hidden_class_behaviour', False) == True:
            #     options_dict.update({'save_hidden_classes': self.prefs.get('save_hidden_classes')})
            if options_dict:
                self.idf.set_options(options_dict)
                self.set_dirty(True)

    def show_search_dialog(self):
        """Opens the search dialog.
        """

        SearchReplaceDialog(self).show()

    def find_this(self):
        """Searches for fields with similar content.
        """

        index = self.classTable.indexAt(self.mouse_position)
        text = self.classTable.model().data(index, Qt.EditRole)
        if text:
            SearchReplaceDialog(self, initial_query=text).show()
Ejemplo n.º 23
0
    def __init__(self, quarterwidget):
        QObject.__init__(self, quarterwidget)
        #QObject.__init__(quarterwidget)

        self._quarterwidget = quarterwidget
        self._rendermanager = self._quarterwidget.getSoRenderManager()

        self.contextmenu = QMenu()
        self.functionsmenu = QMenu("Functions")
        self.rendermenu = QMenu("Render Mode")
        self.stereomenu = QMenu("Stereo Mode")
        self.transparencymenu = QMenu("Transparency Type")

        self.functionsgroup = QActionGroup(self)
        self.stereomodegroup = QActionGroup(self)
        self.rendermodegroup = QActionGroup(self)
        self.transparencytypegroup = QActionGroup(self)

        self.rendermodes = []
        self.rendermodes.append((SoRenderManager.AS_IS, "as is"))
        self.rendermodes.append((SoRenderManager.WIREFRAME, "wireframe"))
        self.rendermodes.append(
            (SoRenderManager.WIREFRAME_OVERLAY, "wireframe overlay"))
        self.rendermodes.append((SoRenderManager.POINTS, "points"))
        self.rendermodes.append((SoRenderManager.HIDDEN_LINE, "hidden line"))
        self.rendermodes.append((SoRenderManager.BOUNDING_BOX, "bounding box"))

        self.stereomodes = []
        self.stereomodes.append((SoRenderManager.MONO, "mono"))
        self.stereomodes.append((SoRenderManager.ANAGLYPH, "anaglyph"))
        self.stereomodes.append((SoRenderManager.QUAD_BUFFER, "quad buffer"))
        self.stereomodes.append(
            (SoRenderManager.INTERLEAVED_ROWS, "interleaved rows"))
        self.stereomodes.append(
            (SoRenderManager.INTERLEAVED_COLUMNS, "interleaved columns"))

        self.transparencytypes = []
        self.transparencytypes.append((SoGLRenderAction.NONE, "none"))
        self.transparencytypes.append(
            (SoGLRenderAction.SCREEN_DOOR, "screen door"))
        self.transparencytypes.append((SoGLRenderAction.ADD, "add"))
        self.transparencytypes.append(
            (SoGLRenderAction.DELAYED_ADD, "delayed add"))
        self.transparencytypes.append(
            (SoGLRenderAction.SORTED_OBJECT_ADD, "sorted object add"))
        self.transparencytypes.append((SoGLRenderAction.BLEND, "blend"))
        self.transparencytypes.append(
            (SoGLRenderAction.DELAYED_BLEND, "delayed blend"))
        self.transparencytypes.append(
            (SoGLRenderAction.SORTED_OBJECT_BLEND, "sorted object blend"))
        self.transparencytypes.append(
            (SoGLRenderAction.SORTED_OBJECT_SORTED_TRIANGLE_ADD,
             "sorted object sorted triangle add"))
        self.transparencytypes.append(
            (SoGLRenderAction.SORTED_OBJECT_SORTED_TRIANGLE_BLEND,
             "sorted object sorted triangle blend"))
        self.transparencytypes.append(
            (SoGLRenderAction.SORTED_LAYERS_BLEND, "sorted layers blend"))

        self.rendermodeactions = []
        for first, second in self.rendermodes:
            action = QAction(second, self)
            action.setCheckable(True)
            action.setChecked(self._rendermanager.getRenderMode() == first)
            action.setData(first)
            self.rendermodeactions.append(action)
            self.rendermodegroup.addAction(action)
            self.rendermenu.addAction(action)

        self.stereomodeactions = []
        for first, second in self.stereomodes:
            action = QAction(second, self)
            action.setCheckable(True)
            action.setChecked(self._rendermanager.getStereoMode() == first)
            action.setData(first)
            self.stereomodeactions.append(action)
            self.stereomodegroup.addAction(action)
            self.stereomenu.addAction(action)

        self.transparencytypeactions = []
        for first, second in self.transparencytypes:
            action = QAction(second, self)
            action.setCheckable(True)
            action.setChecked(self._rendermanager.getGLRenderAction().
                              getTransparencyType() == first)
            action.setData(first)
            self.transparencytypeactions.append(action)
            self.transparencytypegroup.addAction(action)
            self.transparencymenu.addAction(action)

        viewall = QAction("View All", self)
        seek = QAction("Seek", self)
        self.functionsmenu.addAction(viewall)
        self.functionsmenu.addAction(seek)

        self.connect(seek, QtCore.SIGNAL("triggered(bool)"), self.seek)

        self.connect(viewall, QtCore.SIGNAL("triggered(bool)"), self.viewAll)

        self.connect(self.rendermodegroup,
                     QtCore.SIGNAL("triggered(QAction *)"),
                     self.changeRenderMode)

        self.connect(self.stereomodegroup,
                     QtCore.SIGNAL("triggered(QAction *)"),
                     self.changeStereoMode)

        self.connect(self.transparencytypegroup,
                     QtCore.SIGNAL("triggered(QAction *)"),
                     self.changeTransparencyType)

        self.contextmenu.addMenu(self.functionsmenu)
        self.contextmenu.addMenu(self.rendermenu)
        self.contextmenu.addMenu(self.stereomenu)
        self.contextmenu.addMenu(self.transparencymenu)
Ejemplo n.º 24
0
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        layout = QVBoxLayout()
        self.editor = QPlainTextEdit(
        )  # Could also use a QTextEdit and set self.editor.setAcceptRichText(False)

        # Setup the QTextEdit editor configuration
        fixedfont = QFontDatabase.systemFont(QFontDatabase.FixedFont)
        fixedfont.setPointSize(12)
        self.editor.setFont(fixedfont)

        # self.path holds the path of the currently open file.
        # If none, we haven't got a file open yet (or creating new).
        self.path = None

        layout.addWidget(self.editor)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.status = QStatusBar()
        self.setStatusBar(self.status)

        file_toolbar = QToolBar("File")
        file_toolbar.setIconSize(QSize(14, 14))
        self.addToolBar(file_toolbar)
        file_menu = self.menuBar().addMenu("&File")

        open_file_action = QAction(
            QIcon(os.path.join('images', 'blue-folder-open-document.png')),
            "Open file...", self)
        open_file_action.setStatusTip("Open file")
        open_file_action.triggered.connect(self.file_open)
        file_menu.addAction(open_file_action)
        file_toolbar.addAction(open_file_action)

        save_file_action = QAction(QIcon(os.path.join('images', 'disk.png')),
                                   "Save", self)
        save_file_action.setStatusTip("Save current page")
        save_file_action.triggered.connect(self.file_save)
        file_menu.addAction(save_file_action)
        file_toolbar.addAction(save_file_action)

        saveas_file_action = QAction(
            QIcon(os.path.join('images', 'disk--pencil.png')), "Save As...",
            self)
        saveas_file_action.setStatusTip("Save current page to specified file")
        saveas_file_action.triggered.connect(self.file_saveas)
        file_menu.addAction(saveas_file_action)
        file_toolbar.addAction(saveas_file_action)

        print_action = QAction(QIcon(os.path.join('images', 'printer.png')),
                               "Print...", self)
        print_action.setStatusTip("Print current page")
        print_action.triggered.connect(self.file_print)
        file_menu.addAction(print_action)
        file_toolbar.addAction(print_action)

        edit_toolbar = QToolBar("Edit")
        edit_toolbar.setIconSize(QSize(16, 16))
        self.addToolBar(edit_toolbar)
        edit_menu = self.menuBar().addMenu("&Edit")

        undo_action = QAction(
            QIcon(os.path.join('images', 'arrow-curve-180-left.png')), "Undo",
            self)
        undo_action.setStatusTip("Undo last change")
        undo_action.triggered.connect(self.editor.undo)
        edit_menu.addAction(undo_action)

        redo_action = QAction(QIcon(os.path.join('images', 'arrow-curve.png')),
                              "Redo", self)
        redo_action.setStatusTip("Redo last change")
        redo_action.triggered.connect(self.editor.redo)
        edit_toolbar.addAction(redo_action)
        edit_menu.addAction(redo_action)

        edit_menu.addSeparator()

        cut_action = QAction(QIcon(os.path.join('images', 'scissors.png')),
                             "Cut", self)
        cut_action.setStatusTip("Cut selected text")
        cut_action.triggered.connect(self.editor.cut)
        edit_toolbar.addAction(cut_action)
        edit_menu.addAction(cut_action)

        copy_action = QAction(
            QIcon(os.path.join('images', 'document-copy.png')), "Copy", self)
        copy_action.setStatusTip("Copy selected text")
        copy_action.triggered.connect(self.editor.copy)
        edit_toolbar.addAction(copy_action)
        edit_menu.addAction(copy_action)

        paste_action = QAction(
            QIcon(os.path.join('images', 'clipboard-paste-document-text.png')),
            "Paste", self)
        paste_action.setStatusTip("Paste from clipboard")
        paste_action.triggered.connect(self.editor.paste)
        edit_toolbar.addAction(paste_action)
        edit_menu.addAction(paste_action)

        select_action = QAction(
            QIcon(os.path.join('images', 'selection-input.png')), "Select all",
            self)
        select_action.setStatusTip("Select all text")
        select_action.triggered.connect(self.editor.selectAll)
        edit_menu.addAction(select_action)

        edit_menu.addSeparator()

        wrap_action = QAction(
            QIcon(os.path.join('images', 'arrow-continue.png')),
            "Wrap text to window", self)
        wrap_action.setStatusTip("Toggle wrap text to window")
        wrap_action.setCheckable(True)
        wrap_action.setChecked(True)
        wrap_action.triggered.connect(self.edit_toggle_wrap)
        edit_menu.addAction(wrap_action)

        self.update_title()
        self.show()
    def __init__(self, widget):
        QMainWindow.__init__(self)
        self.setWindowTitle("Backend Discord GUI")

        grad = QPalette()
        gradient = QConicalGradient(QPointF(700, -10), 195)
        gradient.setColorAt(0.0, QColor(30, 30, 30))
        gradient.setColorAt(0.5, QColor(50, 50, 50))
        gradient.setColorAt(0.97, QColor(50, 13, 150))
        gradient.setColorAt(1.0, QColor(106, 13, 173))
        gradient.setSpread(QGradient.RepeatSpread)
        grad.setBrush(QPalette.Window, QBrush(gradient))
        self.setPalette(grad)

        # Status Bar
        self.statusbar = self.statusBar()
        self.statusbar.showMessage("Preparing Window...")

        qtRectangle = self.frameGeometry()
        centerPoint = QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        self.move(qtRectangle.topLeft())

        # Menu
        self.menu = self.menuBar()
        file_menu = self.menu.addMenu("File")

        new_bot_proj = QAction("New Bot Project", self)
        new_bot_proj.setShortcut("Ctrl+P")
        new_bot_proj.setStatusTip('Create a new Bot')
        new_bot_proj.triggered.connect(self.do_nothing)

        new_bot_file = QAction("New Bot File", self)
        new_bot_file.setShortcut("Ctrl+N")
        new_bot_file.setStatusTip('Create a new Command file')
        new_bot_file.triggered.connect(self.do_nothing)

        new_int_play = QAction("New Interactive Playground", self)
        new_int_play.setStatusTip('Create a Test App')
        new_int_play.triggered.connect(self.do_nothing)

        open_bot_proj = QAction("Open Bot Project", self)
        open_bot_proj.setShortcut("Ctrl+O")
        open_bot_proj.setStatusTip('Open a Bot Project')
        open_bot_proj.triggered.connect(self.do_nothing)

        open_bot_file = QAction("Open Bot File", self)
        open_bot_file.setStatusTip('Open a Command file')
        open_bot_file.triggered.connect(self.do_nothing)

        open_bot_iplay = QAction("Open Interactive Playground", self)
        open_bot_iplay.setStatusTip('Open a Test App')
        open_bot_iplay.triggered.connect(self.do_nothing)

        add_bot_file = QAction("Add Bot File", self)
        add_bot_file.setStatusTip('Add existing Command file')
        add_bot_file.triggered.connect(self.do_nothing)

        save_bot_proj = QAction("Save Bot Project", self)
        save_bot_proj.setStatusTip('Save a Bot Project')
        save_bot_proj.triggered.connect(self.do_nothing)

        save_bot_file = QAction("Save Bot File", self)
        save_bot_file.setStatusTip('Save a Command file')
        save_bot_file.triggered.connect(self.do_nothing)

        save_all = QAction("Save All", self)
        save_all.setShortcut("Ctrl+S")
        save_all.triggered.connect(self.do_nothing)

        close_editor = QAction("Close Editor", self)
        close_editor.setStatusTip('Close the editor only')
        close_editor.triggered.connect(self.do_nothing)

        close_workspace = QAction("Close Workspace", self)
        close_workspace.setShortcut("Ctrl+Q")
        close_workspace.setStatusTip('Close everything')
        close_workspace.triggered.connect(self.do_nothing)

        file_menu.addAction(new_bot_proj)
        file_menu.addAction(new_bot_file)
        file_menu.addAction(new_int_play)
        file_menu.addSeparator()
        file_menu.addAction(open_bot_proj)
        file_menu.addAction(open_bot_file)
        file_menu.addAction(open_bot_iplay)
        file_menu.addAction(add_bot_file)
        file_menu.addSeparator()
        file_menu.addAction(save_bot_proj)
        file_menu.addAction(save_bot_file)
        file_menu.addAction(save_all)
        file_menu.addSeparator()
        file_menu.addAction(close_editor)
        file_menu.addAction(close_workspace)

        edit_menu = self.menu.addMenu("Edit")

        find_file = QAction("Find File", self)
        find_file.setShortcut("Ctrl+F")
        find_file.setStatusTip("Find a Command")
        find_file.triggered.connect(self.do_nothing)

        file_settings = QAction("Open Find Settings", self)
        file_settings.setShortcut("Ctrl+Shift+S")
        file_settings.setStatusTip("Find a Command")
        file_settings.triggered.connect(self.do_nothing)

        toggle_file = QAction("Toggle File", self, checkable=True)
        toggle_file.setStatusTip("Toggles a Command file to be used")
        toggle_file.setChecked(True)
        toggle_file.triggered.connect(self.do_nothing)

        delete_file = QAction("Delete File", self)
        delete_file.setShortcut("Ctrl+Backspace")
        delete_file.setStatusTip("Delete a Command file")
        delete_file.triggered.connect(self.do_nothing)

        remove_file = QAction("Remove File", self)
        remove_file.setStatusTip("Removes a Command file from workspace")
        remove_file.triggered.connect(self.do_nothing)

        edit_menu.addAction(find_file)
        edit_menu.addAction(file_settings)
        edit_menu.addAction(toggle_file)
        edit_menu.addSeparator()
        edit_menu.addAction(delete_file)
        edit_menu.addAction(remove_file)

        viewMenu = self.menu.addMenu('View')

        command_palette = QAction("Command Palette", self)
        command_palette.setShortcut("Ctrl+Shift+P")
        command_palette.setStatusTip("Delete a Command file")
        command_palette.triggered.connect(self.do_nothing)

        open_view = QAction("Open View", self)
        open_view.setStatusTip("Delete a Command file")
        open_view.triggered.connect(self.do_nothing)

        appearance_settings = QAction("Appearance Settings", self)
        appearance_settings.setStatusTip("Delete a Command file")
        appearance_settings.triggered.connect(self.do_nothing)

        output_console = QAction("Output Console", self)
        output_console.setStatusTip("Delete a Command file")
        output_console.triggered.connect(self.do_nothing)

        debug_console = QAction("Debug Console", self)
        debug_console.setStatusTip("Delete a Command file")
        debug_console.triggered.connect(self.do_nothing)

        error_log = QAction("Error Log", self)
        error_log.setStatusTip("Delete a Command file")
        error_log.triggered.connect(self.do_nothing)

        view_logs = QAction("View All Logs", self)
        view_logs.setStatusTip("Delete a Command file")
        view_logs.triggered.connect(self.do_nothing)

        viewStatAct = QAction('View statusbar', self, checkable=True)
        viewStatAct.setStatusTip('View statusbar')
        viewStatAct.setChecked(True)
        viewStatAct.triggered.connect(self.toggleMenu)

        viewMenu.addAction(command_palette)
        viewMenu.addAction(open_view)
        viewMenu.addSeparator()
        viewMenu.addAction(appearance_settings)
        viewMenu.addSeparator()
        viewMenu.addAction(output_console)
        viewMenu.addAction(debug_console)
        viewMenu.addAction(error_log)
        viewMenu.addAction(view_logs)
        viewMenu.addSeparator()
        viewMenu.addAction(viewStatAct)

        runMenu = self.menu.addMenu('Run')

        start = QAction("Start", self)
        start.setShortcut("Ctrl+R")
        start.setStatusTip("Begin to start Command")
        start.triggered.connect(self.do_nothing)

        stop = QAction("Stop", self)
        stop.setShortcut("Ctrl+T")
        stop.setStatusTip("Terminate the Command")
        stop.triggered.connect(self.do_nothing)

        test_file = QAction("Test File", self)
        test_file.setStatusTip("Test the Command open on test server")
        test_file.triggered.connect(self.do_nothing)

        test_server = QAction("Test Server Connect", self)
        test_server.setShortcut("Ctrl+Shift+R")
        test_server.setStatusTip("Test server connection")
        test_server.triggered.connect(self.do_nothing)

        test_ping = QAction("Test Activity Ping", self)
        test_ping.setStatusTip("Test Bot API connection")
        test_ping.triggered.connect(self.do_nothing)

        test_commands = QAction("Test Ping Commands", self)
        test_commands.setStatusTip("Test all commands received")
        test_commands.triggered.connect(self.do_nothing)

        open_test_logs = QAction("View Test Logs", self)
        open_test_logs.setStatusTip("Open the logs for testing")
        open_test_logs.triggered.connect(self.do_nothing)

        runMenu.addAction(start)
        runMenu.addAction(stop)
        runMenu.addSeparator()
        runMenu.addAction(test_file)
        runMenu.addAction(test_server)
        runMenu.addAction(test_ping)
        runMenu.addAction(test_commands)
        runMenu.addAction(open_test_logs)

        terminalMenu = self.menu.addMenu('Terminal')

        start_bot = QAction("Start Bot", self)
        start_bot.setStatusTip("Begin to start Bot")
        start_bot.triggered.connect(self.do_nothing)

        stop_bot = QAction("Stop Bot", self)
        stop_bot.setStatusTip("Terminate the Bot")
        stop_bot.triggered.connect(self.do_nothing)

        terminal_logs = QAction("View Terminal Logs", self)
        terminal_logs.setStatusTip("Opens the Terminal logs")
        terminal_logs.triggered.connect(self.do_nothing)

        python_discord = QAction("Build Task as Python Discord", self)
        python_discord.setStatusTip(
            "Builds the Bot in Python Programming Language")
        python_discord.triggered.connect(self.do_nothing)

        javascript_discord = QAction("Build Task as Javascript Discord", self)
        javascript_discord.setStatusTip(
            "Builds the Bot in Javascript Programming Language")
        javascript_discord.triggered.connect(self.do_nothing)

        discordGUI_discord = QAction("Build Task as Discord-GUI", self)
        discordGUI_discord.setShortcut("Ctrl+Shift+W")
        discordGUI_discord.setStatusTip(
            "Builds the Bot in Discord-GUI Readable Language")
        discordGUI_discord.triggered.connect(self.do_nothing)

        build_errors = QAction("View Build Errors", self)
        build_errors.setStatusTip("Opens the Build Error Log")
        build_errors.triggered.connect(self.do_nothing)

        terminalMenu.addAction(start_bot)
        terminalMenu.addAction(stop_bot)
        terminalMenu.addSeparator()
        terminalMenu.addAction(terminal_logs)
        terminalMenu.addSeparator()
        terminalMenu.addAction(python_discord)
        terminalMenu.addAction(javascript_discord)
        terminalMenu.addAction(discordGUI_discord)
        terminalMenu.addAction(build_errors)

        windowMenu = self.menu.addMenu('Window')

        hide = QAction("Hide", self)
        hide.setStatusTip("Hide the Window")
        hide.triggered.connect(self.do_nothing)

        minimise = QAction("Minimise", self)
        minimise.setStatusTip("Minimise the Window")
        minimise.triggered.connect(self.do_nothing)

        maximise = QAction("Maximise", self)
        maximise.setStatusTip("Maximise the Window")
        maximise.triggered.connect(self.do_nothing)

        settings = QAction("Discord-GUI Settings", self)
        settings.setShortcut("Ctrl+L")
        settings.setStatusTip("Opens Discord-GUI's Settings")
        settings.triggered.connect(self.do_nothing)

        directory = QAction("Open Discord-GUI Directory", self)
        directory.setStatusTip("Goto the Discord-GUI Directory")
        directory.triggered.connect(self.do_nothing)

        windowMenu.addAction(hide)
        windowMenu.addAction(minimise)
        windowMenu.addAction(maximise)
        windowMenu.addSeparator()
        windowMenu.addAction(settings)
        windowMenu.addAction(directory)

        helpMenu = self.menu.addMenu('Help')

        welcome = QAction("Welcome", self)
        welcome.setStatusTip("Displays Welcome Message")
        welcome.triggered.connect(self.do_nothing)

        int_play = QAction("Interactive Playground", self)
        int_play.setStatusTip("Displays Interactive Playground Help")
        int_play.triggered.connect(self.do_nothing)

        docs = QAction("Documentation", self)
        docs.setStatusTip("Redirects to the Documentation of the app")
        docs.triggered.connect(self.do_nothing)

        keys_shorts = QAction("Keyboard Shortcuts", self)
        keys_shorts.setStatusTip("Displays Keyboard Shortcuts")
        keys_shorts.triggered.connect(self.do_nothing)

        report_issue = QAction("Report Issue", self)
        report_issue.setStatusTip("Redirects to Reporting an Issue")
        report_issue.triggered.connect(self.do_nothing)

        more_help = QAction("More Help", self)
        more_help.setStatusTip("Redirects to More Help Page")
        more_help.triggered.connect(self.do_nothing)

        helpMenu.addAction(welcome)
        helpMenu.addAction(int_play)
        helpMenu.addAction(docs)
        helpMenu.addSeparator()
        helpMenu.addAction(keys_shorts)
        helpMenu.addAction(report_issue)
        helpMenu.addAction(more_help)

        self.setCentralWidget(widget)
Ejemplo n.º 26
0
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        layout = QVBoxLayout()
        self.editor = TextEdit()
        # Setup the QTextEdit editor configuration
        self.editor.setAutoFormatting(QTextEdit.AutoAll)
        self.editor.selectionChanged.connect(self.update_format)
        # Initialize default font size.
        font = QFont('Times', 12)
        self.editor.setFont(font)
        # We need to repeat the size to init the current format.
        self.editor.setFontPointSize(12)

        # self.path holds the path of the currently open file.
        # If none, we haven't got a file open yet (or creating new).
        self.path = None

        layout.addWidget(self.editor)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.status = QStatusBar()
        self.setStatusBar(self.status)

        # Uncomment to disable native menubar on Mac
        # self.menuBar().setNativeMenuBar(False)

        file_toolbar = QToolBar("File")
        file_toolbar.setIconSize(QSize(14, 14))
        self.addToolBar(file_toolbar)
        file_menu = self.menuBar().addMenu("&File")

        open_file_action = QAction(
            QIcon(os.path.join('images', 'blue-folder-open-document.png')),
            "Open file...", self)
        open_file_action.setStatusTip("Open file")
        open_file_action.triggered.connect(self.file_open)
        file_menu.addAction(open_file_action)
        file_toolbar.addAction(open_file_action)

        save_file_action = QAction(QIcon(os.path.join('images', 'disk.png')),
                                   "Save", self)
        save_file_action.setStatusTip("Save current page")
        save_file_action.triggered.connect(self.file_save)
        file_menu.addAction(save_file_action)
        file_toolbar.addAction(save_file_action)

        saveas_file_action = QAction(
            QIcon(os.path.join('images', 'disk--pencil.png')), "Save As...",
            self)
        saveas_file_action.setStatusTip("Save current page to specified file")
        saveas_file_action.triggered.connect(self.file_saveas)
        file_menu.addAction(saveas_file_action)
        file_toolbar.addAction(saveas_file_action)

        print_action = QAction(QIcon(os.path.join('images', 'printer.png')),
                               "Print...", self)
        print_action.setStatusTip("Print current page")
        print_action.triggered.connect(self.file_print)
        file_menu.addAction(print_action)
        file_toolbar.addAction(print_action)

        edit_toolbar = QToolBar("Edit")
        edit_toolbar.setIconSize(QSize(16, 16))
        self.addToolBar(edit_toolbar)
        edit_menu = self.menuBar().addMenu("&Edit")

        undo_action = QAction(
            QIcon(os.path.join('images', 'arrow-curve-180-left.png')), "Undo",
            self)
        undo_action.setStatusTip("Undo last change")
        undo_action.triggered.connect(self.editor.undo)
        edit_menu.addAction(undo_action)

        redo_action = QAction(QIcon(os.path.join('images', 'arrow-curve.png')),
                              "Redo", self)
        redo_action.setStatusTip("Redo last change")
        redo_action.triggered.connect(self.editor.redo)
        edit_toolbar.addAction(redo_action)
        edit_menu.addAction(redo_action)

        edit_menu.addSeparator()

        cut_action = QAction(QIcon(os.path.join('images', 'scissors.png')),
                             "Cut", self)
        cut_action.setStatusTip("Cut selected text")
        cut_action.setShortcut(QKeySequence.Cut)
        cut_action.triggered.connect(self.editor.cut)
        edit_toolbar.addAction(cut_action)
        edit_menu.addAction(cut_action)

        copy_action = QAction(
            QIcon(os.path.join('images', 'document-copy.png')), "Copy", self)
        copy_action.setStatusTip("Copy selected text")
        cut_action.setShortcut(QKeySequence.Copy)
        copy_action.triggered.connect(self.editor.copy)
        edit_toolbar.addAction(copy_action)
        edit_menu.addAction(copy_action)

        paste_action = QAction(
            QIcon(os.path.join('images', 'clipboard-paste-document-text.png')),
            "Paste", self)
        paste_action.setStatusTip("Paste from clipboard")
        cut_action.setShortcut(QKeySequence.Paste)
        paste_action.triggered.connect(self.editor.paste)
        edit_toolbar.addAction(paste_action)
        edit_menu.addAction(paste_action)

        select_action = QAction(
            QIcon(os.path.join('images', 'selection-input.png')), "Select all",
            self)
        select_action.setStatusTip("Select all text")
        cut_action.setShortcut(QKeySequence.SelectAll)
        select_action.triggered.connect(self.editor.selectAll)
        edit_menu.addAction(select_action)

        edit_menu.addSeparator()

        wrap_action = QAction(
            QIcon(os.path.join('images', 'arrow-continue.png')),
            "Wrap text to window", self)
        wrap_action.setStatusTip("Toggle wrap text to window")
        wrap_action.setCheckable(True)
        wrap_action.setChecked(True)
        wrap_action.triggered.connect(self.edit_toggle_wrap)
        edit_menu.addAction(wrap_action)

        format_toolbar = QToolBar("Format")
        format_toolbar.setIconSize(QSize(16, 16))
        self.addToolBar(format_toolbar)
        format_menu = self.menuBar().addMenu("&Format")

        # We need references to these actions/settings to update as selection changes, so attach to self.
        self.fonts = QFontComboBox()
        self.fonts.currentFontChanged.connect(self.editor.setCurrentFont)
        format_toolbar.addWidget(self.fonts)

        self.fontsize = QComboBox()
        self.fontsize.addItems([str(s) for s in FONT_SIZES])

        # Connect to the signal producing the text of the current selection. Convert the string to float
        # and set as the pointsize. We could also use the index + retrieve from FONT_SIZES.
        self.fontsize.currentIndexChanged[str].connect(
            lambda s: self.editor.setFontPointSize(float(s)))
        format_toolbar.addWidget(self.fontsize)

        self.bold_action = QAction(
            QIcon(os.path.join('images', 'edit-bold.png')), "Bold", self)
        self.bold_action.setStatusTip("Bold")
        self.bold_action.setShortcut(QKeySequence.Bold)
        self.bold_action.setCheckable(True)
        self.bold_action.toggled.connect(lambda x: self.editor.setFontWeight(
            QFont.Bold if x else QFont.Normal))
        format_toolbar.addAction(self.bold_action)
        format_menu.addAction(self.bold_action)

        self.italic_action = QAction(
            QIcon(os.path.join('images', 'edit-italic.png')), "Italic", self)
        self.italic_action.setStatusTip("Italic")
        self.italic_action.setShortcut(QKeySequence.Italic)
        self.italic_action.setCheckable(True)
        self.italic_action.toggled.connect(self.editor.setFontItalic)
        format_toolbar.addAction(self.italic_action)
        format_menu.addAction(self.italic_action)

        self.underline_action = QAction(
            QIcon(os.path.join('images', 'edit-underline.png')), "Underline",
            self)
        self.underline_action.setStatusTip("Underline")
        self.underline_action.setShortcut(QKeySequence.Underline)
        self.underline_action.setCheckable(True)
        self.underline_action.toggled.connect(self.editor.setFontUnderline)
        format_toolbar.addAction(self.underline_action)
        format_menu.addAction(self.underline_action)

        format_menu.addSeparator()

        self.alignl_action = QAction(
            QIcon(os.path.join('images', 'edit-alignment.png')), "Align left",
            self)
        self.alignl_action.setStatusTip("Align text left")
        self.alignl_action.setCheckable(True)
        self.alignl_action.triggered.connect(
            lambda: self.editor.setAlignment(Qt.AlignLeft))
        format_toolbar.addAction(self.alignl_action)
        format_menu.addAction(self.alignl_action)

        self.alignc_action = QAction(
            QIcon(os.path.join('images', 'edit-alignment-center.png')),
            "Align center", self)
        self.alignc_action.setStatusTip("Align text center")
        self.alignc_action.setCheckable(True)
        self.alignc_action.triggered.connect(
            lambda: self.editor.setAlignment(Qt.AlignCenter))
        format_toolbar.addAction(self.alignc_action)
        format_menu.addAction(self.alignc_action)

        self.alignr_action = QAction(
            QIcon(os.path.join('images', 'edit-alignment-right.png')),
            "Align right", self)
        self.alignr_action.setStatusTip("Align text right")
        self.alignr_action.setCheckable(True)
        self.alignr_action.triggered.connect(
            lambda: self.editor.setAlignment(Qt.AlignRight))
        format_toolbar.addAction(self.alignr_action)
        format_menu.addAction(self.alignr_action)

        self.alignj_action = QAction(
            QIcon(os.path.join('images', 'edit-alignment-justify.png')),
            "Justify", self)
        self.alignj_action.setStatusTip("Justify text")
        self.alignj_action.setCheckable(True)
        self.alignj_action.triggered.connect(
            lambda: self.editor.setAlignment(Qt.AlignJustify))
        format_toolbar.addAction(self.alignj_action)
        format_menu.addAction(self.alignj_action)

        format_group = QActionGroup(self)
        format_group.setExclusive(True)
        format_group.addAction(self.alignl_action)
        format_group.addAction(self.alignc_action)
        format_group.addAction(self.alignr_action)
        format_group.addAction(self.alignj_action)

        format_menu.addSeparator()

        # A list of all format-related widgets/actions, so we can disable/enable signals when updating.
        self._format_actions = [
            self.fonts,
            self.fontsize,
            self.bold_action,
            self.italic_action,
            self.underline_action,
            # We don't need to disable signals for alignment, as they are paragraph-wide.
        ]

        # Initialize.
        self.update_format()
        self.update_title()
        self.show()

    def block_signals(self, objects, b):
        for o in objects:
            o.blockSignals(b)

    def update_format(self):
        """
        Update the font format toolbar/actions when a new text selection is made. This is neccessary to keep
        toolbars/etc. in sync with the current edit state.
        :return:
        """
        # Disable signals for all format widgets, so changing values here does not trigger further formatting.
        self.block_signals(self._format_actions, True)

        self.fonts.setCurrentFont(self.editor.currentFont())
        # Nasty, but we get the font-size as a float but want it was an int
        self.fontsize.setCurrentText(str(int(self.editor.fontPointSize())))

        self.italic_action.setChecked(self.editor.fontItalic())
        self.underline_action.setChecked(self.editor.fontUnderline())
        self.bold_action.setChecked(self.editor.fontWeight() == QFont.Bold)

        self.alignl_action.setChecked(self.editor.alignment() == Qt.AlignLeft)
        self.alignc_action.setChecked(
            self.editor.alignment() == Qt.AlignCenter)
        self.alignr_action.setChecked(self.editor.alignment() == Qt.AlignRight)
        self.alignj_action.setChecked(
            self.editor.alignment() == Qt.AlignJustify)

        self.block_signals(self._format_actions, False)

    def dialog_critical(self, s):
        dlg = QMessageBox(self)
        dlg.setText(s)
        dlg.setIcon(QMessageBox.Critical)
        dlg.show()

    def file_open(self):
        path, _ = QFileDialog.getOpenFileName(
            self, "Open file", "",
            "HTML documents (*.html);Text documents (*.txt);All files (*.*)")

        try:
            with open(path, 'rU') as f:
                text = f.read()

        except Exception as e:
            self.dialog_critical(str(e))

        else:
            self.path = path
            # Qt will automatically try and guess the format as txt/html
            self.editor.setText(text)
            self.update_title()

    def file_save(self):
        if self.path is None:
            # If we do not have a path, we need to use Save As.
            return self.file_saveas()

        text = self.editor.toHtml() if splitext(
            self.path) in HTML_EXTENSIONS else self.editor.toPlainText()

        try:
            with open(self.path, 'w') as f:
                f.write(text)

        except Exception as e:
            self.dialog_critical(str(e))

    def file_saveas(self):
        path, _ = QFileDialog.getSaveFileName(
            self, "Save file", "",
            "HTML documents (*.html);Text documents (*.txt);All files (*.*)")

        if not path:
            # If dialog is cancelled, will return ''
            return

        text = self.editor.toHtml() if splitext(
            path) in HTML_EXTENSIONS else self.editor.toPlainText()

        try:
            with open(path, 'w') as f:
                f.write(text)

        except Exception as e:
            self.dialog_critical(str(e))

        else:
            self.path = path
            self.update_title()

    def file_print(self):
        dlg = QPrintDialog()
        if dlg.exec_():
            self.editor.print_(dlg.printer())

    def update_title(self):
        self.setWindowTitle(
            "%s - Megasolid Idiom" %
            (os.path.basename(self.path) if self.path else "Untitled"))

    def edit_toggle_wrap(self):
        self.editor.setLineWrapMode(1 if self.editor.lineWrapMode() ==
                                    0 else 0)
Ejemplo n.º 27
0
    def __init__(self, *args, **kwargs):
        super(Notepad, self).__init__(*args, **kwargs)

        self.setWindowIcon(QIcon('arti.PNG'))
        self.setGeometry(200, 100, 700, 400)

        layout = QVBoxLayout()
        self.editor = QPlainTextEdit()
        self.editor.setFont(QFont('Roboto', 12))

        # self.path holds the path of the currently open file.
        # If none, we haven't got a file open yet (or creating new).
        self.path = None

        layout.addWidget(self.editor)

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.status = QStatusBar()
        self.setStatusBar(self.status)

        file_toolbar = QToolBar("File")
        file_toolbar.setIconSize(QSize(14, 14))
        self.addToolBar(file_toolbar)
        file_menu = self.menuBar().addMenu("&File")

        open_file_action = QAction(QIcon(), "Open file...", self)
        open_file_action.setStatusTip("Open file")
        open_file_action.triggered.connect(self.file_open)
        file_menu.addAction(open_file_action)
        file_toolbar.addAction(open_file_action)
        open_file_action.setShortcut(QKeySequence('Ctrl+O'))

        save_file_action = QAction(QIcon(), "Save", self)
        save_file_action.setStatusTip("Save current page")
        save_file_action.triggered.connect(self.file_save)
        file_menu.addAction(save_file_action)
        file_toolbar.addAction(save_file_action)
        save_file_action.setShortcut(QKeySequence('Ctrl+S'))

        saveas_file_action = QAction(QIcon(), "Save As...", self)
        saveas_file_action.setStatusTip("Save current page to specified file")
        saveas_file_action.triggered.connect(self.file_saveas)
        file_menu.addAction(saveas_file_action)
        file_toolbar.addAction(saveas_file_action)
        saveas_file_action.setShortcut(QKeySequence('Ctrl+Shift+S'))

        print_action = QAction(QIcon(), "Print...", self)
        print_action.setStatusTip("Print current page")
        print_action.triggered.connect(self.file_print)
        file_menu.addAction(print_action)
        file_toolbar.addAction(print_action)
        print_action.setShortcut(QKeySequence('Ctrl+P'))

        edit_toolbar = QToolBar("Edit")
        edit_toolbar.setIconSize(QSize(16, 16))
        self.addToolBar(edit_toolbar)
        edit_menu = self.menuBar().addMenu("&Edit")

        undo_action = QAction(QIcon(), "Undo", self)
        undo_action.setStatusTip("Undo last change")
        undo_action.triggered.connect(self.editor.undo)
        edit_menu.addAction(undo_action)
        undo_action.setShortcut(QKeySequence('Ctrl+Z'))

        redo_action = QAction(QIcon(), "Redo", self)
        redo_action.setStatusTip("Redo last change")
        redo_action.triggered.connect(self.editor.redo)
        edit_toolbar.addAction(redo_action)
        edit_menu.addAction(redo_action)
        redo_action.setShortcut(QKeySequence('Ctrl+Y'))

        edit_menu.addSeparator()

        cut_action = QAction(QIcon(), "Cut", self)
        cut_action.setStatusTip("Cut selected text")
        cut_action.triggered.connect(self.editor.cut)
        edit_toolbar.addAction(cut_action)
        edit_menu.addAction(cut_action)
        cut_action.setShortcut(QKeySequence('Ctrl+X'))

        copy_action = QAction(QIcon(), "Copy", self)
        copy_action.setStatusTip("Copy selected text")
        copy_action.triggered.connect(self.editor.copy)
        edit_toolbar.addAction(copy_action)
        edit_menu.addAction(copy_action)
        copy_action.setShortcut(QKeySequence('Ctrl+C'))

        paste_action = QAction(QIcon(), "Paste", self)
        paste_action.setStatusTip("Paste from clipboard")
        paste_action.triggered.connect(self.editor.paste)
        edit_toolbar.addAction(paste_action)
        edit_menu.addAction(paste_action)
        paste_action.setShortcut(QKeySequence('Ctrl+V'))

        select_action = QAction(QIcon(), "Select all", self)
        select_action.setStatusTip("Select all text")
        select_action.triggered.connect(self.editor.selectAll)
        edit_menu.addAction(select_action)
        select_action.setShortcut(QKeySequence('Ctrl+A'))

        edit_menu.addSeparator()

        wrap_action = QAction(QIcon(), "Wrap text to window", self)
        wrap_action.setStatusTip("Toggle wrap text to window")
        wrap_action.setCheckable(True)
        wrap_action.setChecked(True)
        wrap_action.triggered.connect(self.edit_toggle_wrap)
        edit_menu.addAction(wrap_action)

        self.update_title()
        self.show()
Ejemplo n.º 28
0
class MainWindow(QMainWindow):
    def __init__(self, config):
        super(MainWindow, self).__init__()

        QFontDatabase.addApplicationFont('../resources/fonts/poppins/Poppins-Medium.ttf')
        QFontDatabase.addApplicationFont('../resources/fonts/source code pro/SourceCodePro-Regular.ttf')
        QFontDatabase.addApplicationFont('../resources/fonts/asap/Asap-Regular.ttf')

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        if MainConsole.main_console is not None:
            self.ui.scripts_console_splitter.addWidget(MainConsole.main_console)
        self.ui.scripts_console_splitter.setSizes([350, 350])
        self.ui.splitter.setSizes([120, 800])
        self.setWindowTitle('Ryven')
        self.setWindowIcon(QIcon('../resources/pics/program_icon2.png'))
        self.load_stylesheet('dark')
        self.ui.scripts_tab_widget.removeTab(0)

        # menu actions
        self.flow_design_actions = []
        self.setup_menu_actions()

        # shortcuts
        save_shortcut = QShortcut(QKeySequence.Save, self)
        save_shortcut.activated.connect(self.on_save_project_triggered)
        import_nodes_shortcut = QShortcut(QKeySequence('Ctrl+i'), self)
        import_nodes_shortcut.activated.connect(self.on_import_nodes_triggered)

        # clear temp folder
        if not os.path.exists('temp'):
            os.mkdir('temp')
        for f in os.listdir('temp'):
            os.remove('temp/'+f)

        # GENERAL ATTRIBUTES
        self.scripts = []
        self.custom_nodes = []
        self.all_nodes = [SetVariable_Node(), GetVariable_Node(), Val_Node(), Result_Node()]
        self.package_names = []

        #   holds NI subCLASSES for imported nodes:
        self.all_node_instance_classes = {
            self.all_nodes[0]: SetVar_NodeInstance,
            self.all_nodes[1]: GetVar_NodeInstance,
            self.all_nodes[2]: Val_NodeInstance,
            self.all_nodes[3]: Result_NodeInstance
        }  # (key: node obj, val: NI subclass) (used in Flow)

        #   custom subclasses for input widgets
        #   {node : {str: PortInstanceWidget-subclass}} (used in PortInstance)
        self.custom_node_input_widget_classes = {}

        # UI
        self.scripts_list_widget = ScriptsListWidget(self, self.scripts)
        self.ui.scripts_scrollArea.setWidget(self.scripts_list_widget)
        self.ui.add_new_script_pushButton.clicked.connect(self.create_new_script_button_pressed)
        self.ui.new_script_name_lineEdit.returnPressed.connect(self.create_new_script_LE_return_pressed)


        if config['config'] == 'create plain new project':
            self.try_to_create_new_script()
        elif config['config'] == 'open project':
            print('importing packages...')
            self.import_packages(config['required packages'])
            print('loading project...')
            self.parse_project(config['content'])
            print('finished')

        print('''
CONTROLS
placing: right mouse
selecting: left mouse
panning: middle mouse
saving: ctrl+s
        ''')


        Design.set_flow_theme()
        Design.set_flow_theme()  # temporary
        #   the double call is just a temporary fix for an issue I will address in a future release.
        #   Problem: because the signal emitted when setting a flow theme is directly connected to the according slots
        #   in NodeInstance as well as NodeInstance_TitleLabel, the NodeInstance's slot (which starts an animation which
        #   uses the title label's current and theme dependent color) could get called before the title
        #   label's slot has been called to reinitialize this color. This results in wrong color end points for the
        #   title label when activating animations.
        #   This is pretty nasty since I cannot think of a nice fix for this issue other that not letting the slot
        #   methods be called directly from the emitted signal but instead through a defined procedure like before.


        # maybe this will be necessary due to scheduling issues when loading flows
        # for s in self.scripts:
        #     s.flow.viewport().update()

        self.resize(1500, 800)


    def setup_menu_actions(self):
        # flow designs
        for d in Design.flow_themes:
            design_action = QAction(d.name, self)
            self.ui.menuFlow_Design_Style.addAction(design_action)
            design_action.triggered.connect(self.on_design_action_triggered)
            self.flow_design_actions.append(design_action)

        self.ui.actionImport_Nodes.triggered.connect(self.on_import_nodes_triggered)
        self.ui.actionSave_Project.triggered.connect(self.on_save_project_triggered)
        self.ui.actionEnableDebugging.triggered.connect(self.on_enable_debugging_triggered)
        self.ui.actionDisableDebugging.triggered.connect(self.on_disable_debugging_triggered)
        self.ui.actionSave_Pic_Viewport.triggered.connect(self.on_save_scene_pic_viewport_triggered)
        self.ui.actionSave_Pic_Whole_Scene_scaled.triggered.connect(self.on_save_scene_pic_whole_triggered)

        # performance mode
        self.action_set_performance_mode_fast = QAction('Fast', self)
        self.action_set_performance_mode_fast.setCheckable(True)

        self.action_set_performance_mode_pretty = QAction('Pretty', self)
        self.action_set_performance_mode_pretty.setCheckable(True)

        performance_mode_AG = QActionGroup(self)
        performance_mode_AG.addAction(self.action_set_performance_mode_fast)
        performance_mode_AG.addAction(self.action_set_performance_mode_pretty)
        self.action_set_performance_mode_fast.setChecked(True)
        performance_mode_AG.triggered.connect(self.on_performance_mode_changed)

        performance_menu = QMenu('Performance Mode', self)
        performance_menu.addAction(self.action_set_performance_mode_fast)
        performance_menu.addAction(self.action_set_performance_mode_pretty)

        self.ui.menuView.addMenu(performance_menu)

        # animations
        self.action_set_animation_active = QAction('Enabled', self)
        self.action_set_animation_active.setCheckable(True)

        self.action_set_animations_inactive = QAction('Disabled', self)
        self.action_set_animations_inactive.setCheckable(True)

        animation_enabled_AG = QActionGroup(self)
        animation_enabled_AG.addAction(self.action_set_animation_active)
        animation_enabled_AG.addAction(self.action_set_animations_inactive)
        self.action_set_animation_active.setChecked(True)
        animation_enabled_AG.triggered.connect(self.on_animation_enabling_changed)

        animations_menu = QMenu('Animations', self)
        animations_menu.addAction(self.action_set_animation_active)
        animations_menu.addAction(self.action_set_animations_inactive)

        self.ui.menuView.addMenu(animations_menu)

    def load_stylesheet(self, ss):
        ss_content = ''
        try:
            f = open('../resources/stylesheets/'+ss+'.txt')
            ss_content = f.read()
            f.close()
        finally:
            Design.ryven_stylesheet = ss_content
            self.setStyleSheet(ss_content)

    def on_performance_mode_changed(self, action):
        if action == self.action_set_performance_mode_fast:
            Design.set_performance_mode('fast')
        else:
            Design.set_performance_mode('pretty')

    def on_animation_enabling_changed(self, action):
        if action == self.action_set_animation_active:
            Design.animations_enabled = True
        else:
            Design.animations_enabled = False

    def on_design_action_triggered(self):
        index = self.flow_design_actions.index(self.sender())
        Design.set_flow_theme(Design.flow_themes[index])

    def on_enable_debugging_triggered(self):
        Debugger.enable()

    def on_disable_debugging_triggered(self):
        Debugger.disable()

    def on_save_scene_pic_viewport_triggered(self):
        """Saves a picture of the currently visible viewport."""
        if len(self.scripts) == 0:
            return

        file_path = QFileDialog.getSaveFileName(self, 'select file', '', 'PNG(*.png)')[0]
        img = self.scripts[self.ui.scripts_tab_widget.currentIndex()].flow.get_viewport_img()
        img.save(file_path)

    def on_save_scene_pic_whole_triggered(self):
        """Saves a picture of the whole currently visible scene."""
        if len(self.scripts) == 0:
            return

        file_path = QFileDialog.getSaveFileName(self, 'select file', '', 'PNG(*.png)')[0]
        img = self.scripts[self.ui.scripts_tab_widget.currentIndex()].flow.get_whole_scene_img()
        img.save(file_path)


    def create_new_script_button_pressed(self):
        self.try_to_create_new_script(name=self.ui.new_script_name_lineEdit.text())

    def create_new_script_LE_return_pressed(self):
        self.try_to_create_new_script(name=self.ui.new_script_name_lineEdit.text())


    def try_to_create_new_script(self, name='fancy script', config=None):
        """Tries to create a new script with a given name. If the name is already used or '', it fails."""
        if len(name) == 0:
            return
        for s in self.scripts:
            if s.name == name:
                return

        new_script = Script(self, name, config)
        new_script.name_changed.connect(self.rename_script)
        self.ui.scripts_tab_widget.addTab(new_script.widget, new_script.name)
        self.scripts.append(new_script)
        self.scripts_list_widget.recreate_ui()

    def rename_script(self, script, new_name):
        self.ui.scripts_tab_widget.setTabText(self.scripts.index(script), new_name)
        script.name = new_name

    def delete_script(self, script):
        index = self.scripts.index(script)
        self.ui.scripts_tab_widget.removeTab(index)
        del self.scripts[index]


    def on_import_nodes_triggered(self):
        file_path = QFileDialog.getOpenFileName(self, 'select nodes file', '../packages', 'Ryven Packages(*.rpc)',)[0]
        if file_path != '':
            self.import_nodes_package(file_path)

    def import_packages(self, packages_list):
        for p in packages_list:
            self.import_nodes_package(p)

    def import_nodes_package(self, file_path):
        j_str = ''
        try:
            f = open(file_path)
            j_str = f.read()
            f.close()
        except FileExistsError or FileNotFoundError:
            Debugger.debug('couldn\'t open file')
            return

        # don't import a package twice if it already has been imported
        filename = os.path.splitext(os.path.basename(file_path))
        if filename in self.package_names:
            return

        # Important: translate the package first (metacore files -> src code files)
        PackageTranslator = self.get_class_from_file(file_path='../Ryven_PackageTranslator',
                                                     file_name='Ryven_PackageTranslator',
                                                     class_name='PackageTranslator')
        package_translator = PackageTranslator(os.path.dirname(os.path.abspath(file_path)))

        self.parse_nodes(j_str,
                         package_path=os.path.dirname(file_path),
                         package_name=os.path.splitext(os.path.basename(file_path))[0])#

        self.package_names.append(filename)


    def parse_nodes(self, j_str, package_path, package_name):
        """Parses the nodes from a node package in JSON format.
        Here, all the classes get imported and for every node a Node object with specific attribute values gets
        created."""

        import json

        # strict=False is necessary to allow 'control characters' like '\n' for newline when loading the json
        j_obj = json.loads(j_str, strict=False)

        Debugger.debug(j_obj['type'])
        if j_obj['type'] != 'Ryven nodes package' and j_obj['type'] != 'vyScriptFP nodes package':  # old syntax
            return

        # package_title = j_obj['title']
        # package_description = j_obj['description']
        j_nodes_list = j_obj['nodes']

        num_nodes = len(j_nodes_list)
        for ni in range(num_nodes):
            j_node = j_nodes_list[ni]
            self.parse_node(j_node, package_name, package_path)

        Debugger.debug(len(self.custom_nodes), 'nodes imported')


    def parse_node(self, j_node, package_name, package_path):
        new_node = Node()

        # loading the node's specifications which get finally set below after importing the classes
        node_title = j_node['title']
        node_class_name = j_node['class name']
        node_description = j_node['description']
        node_type = j_node['type']
        node_has_main_widget = j_node['has main widget']
        node_main_widget_pos = j_node['widget position'] if node_has_main_widget else None
        node_design_style = j_node['design style']
        node_color = j_node['color']

        # Every node has a custom module name which differs from it's name to prevent import issues when using
        # multiple (different) Nodes with same titles. For further info: see node manager
        node_module_name = j_node['module name']
        module_name_separator = '___'

        # CUSTOM CLASS IMPORTS ----------------------------------------------------------------------------
        # creating all the necessary path variables here for all potentially imported classes

        #       IMPORT NODE INSTANCE SUBCLASS
        node_instance_class_file_path = package_path + '/nodes/' + node_module_name + '/'
        node_instance_widgets_file_path = node_instance_class_file_path + '/widgets'
        node_instance_filename = node_module_name  # the NI file's name is just the 'module name'
        new_node_instance_class = self.get_class_from_file(file_path=node_instance_class_file_path,
                                                           file_name=node_instance_filename,
                                                           class_name=node_class_name + '_NodeInstance')
        self.all_node_instance_classes[new_node] = new_node_instance_class

        #       IMPORT MAIN WIDGET
        if node_has_main_widget:
            main_widget_filename = node_module_name + module_name_separator + 'main_widget'
            new_node.main_widget_class = self.get_class_from_file(file_path=node_instance_widgets_file_path,
                                                                  file_name=main_widget_filename,
                                                                  class_name=node_class_name +
                                                                             '_NodeInstance_MainWidget')

        #       IMPORT CUSTOM INPUT WIDGETS
        #       I need to create the dict for the node's potential custom input widgets already here
        self.custom_node_input_widget_classes[new_node] = {}
        for w_name in j_node['custom input widgets']:
            input_widget_filename = node_module_name + module_name_separator + w_name
            custom_widget_class = self.get_class_from_file(file_path=node_instance_widgets_file_path,
                                                           file_name=input_widget_filename,
                                                           class_name=w_name + '_PortInstanceWidget')
            self.custom_node_input_widget_classes[new_node][w_name] = custom_widget_class

        # ---------------------------------------------------------------------------------------------------

        j_n_inputs = j_node['inputs']
        inputs = []
        num_inputs = len(j_n_inputs)
        for ii in range(num_inputs):
            # loading info
            j_input = j_n_inputs[ii]
            i_type = j_input['type']
            i_label = j_input['label']
            i_has_widget = None
            i_widget_name = ''
            i_widget_pos = None
            if i_type == 'data':
                i_has_widget = j_input['has widget']
                if i_has_widget:
                    i_widget_name = j_input['widget name']
                    i_widget_pos = j_input['widget position']

            # creating port
            new_input = NodePort()
            new_input.type_ = i_type
            new_input.label = i_label
            if i_has_widget:
                new_input.widget_name = i_widget_name
                new_input.widget_pos = i_widget_pos
            inputs.append(new_input)

        j_n_outputs = j_node['outputs']
        outputs = []
        num_outputs = len(j_n_outputs)
        for oi in range(num_outputs):
            # loading info
            j_output = j_n_outputs[oi]
            o_type = j_output['type']
            o_label = j_output['label']

            # creating port
            new_output = NodePort()
            new_output.type_ = o_type
            new_output.label = o_label
            outputs.append(new_output)

        # setting the Node's attributes
        new_node.title = node_title
        new_node.description = node_description
        new_node.type_ = node_type
        new_node.package = package_name
        new_node.has_main_widget = node_has_main_widget
        if node_has_main_widget:
            new_node.main_widget_pos = node_main_widget_pos
        new_node.design_style = node_design_style
        new_node.color = QColor(node_color)
        new_node.inputs = inputs
        new_node.outputs = outputs

        self.custom_nodes.append(new_node)
        self.all_nodes.append(new_node)


    def get_class_from_file(self, file_path, file_name, class_name):
        """Returns a class with a given name from a file for instantiation by importing the module.
        Used for all the dynamically imported classes:
            - NodeInstances
            - A NodeInstance's main widget
            - A NodeInstance's custom input widgets
        """
        # Debugger.debug(file_path)
        # Debugger.debug(file_name)
        # Debugger.debug(class_name)
        sys.path.append(file_path)
        try:
            new_module = __import__(file_name, fromlist=[class_name])
        except ModuleNotFoundError as e:
            QMessageBox.warning(self, 'Missing Python module', str(e))
            sys.exit()
        new_class = getattr(new_module, class_name)
        return new_class


    def parse_project(self, j_obj):
        if j_obj['general info']['type'] != 'Ryven project file':
            return

        for s in j_obj['scripts']:  # fill flows
            self.try_to_create_new_script(config=s)


    def on_save_project_triggered(self):
        file_name = QFileDialog.getSaveFileName(self, 'select location and give file name',
                                                '../saves', 'Ryven Project(*.rpo)')[0]
        if file_name != '':
            self.save_project(file_name)


    def save_project(self, file_name):
        import json

        file = None
        try:
            if os.path.exists(file_name):
                os.remove(file_name)
            file = open(file_name, 'w')
        except FileNotFoundError:
            Debugger.debug('couldn\'t open file')
            return


        general_project_info_dict = {'type': 'Ryven project file'}

        scripts_data = []
        for script in self.scripts:
            scripts_data.append(script.get_json_data())

        whole_project_dict = {'general info': general_project_info_dict,
                              'scripts': scripts_data}

        json_str = json.dumps(whole_project_dict)
        Debugger.debug(json_str)


        file.write(json_str)
        file.close()
Ejemplo n.º 29
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.setWindowTitle('OpenMC Plot Explorer')

        self.restored = False
        self.pixmap = None
        self.zoom = 100

        self.model = PlotModel()
        self.restoreModelSettings()

        self.cellsModel = DomainTableModel(self.model.activeView.cells)
        self.materialsModel = DomainTableModel(self.model.activeView.materials)

        # Plot Image
        self.plotIm = PlotImage(self.model, FM, self)
        self.frame = QScrollArea(self)
        self.frame.setAlignment(QtCore.Qt.AlignCenter)
        self.frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.frame.setWidget(self.plotIm)
        self.setCentralWidget(self.frame)

        # Dock
        self.dock = OptionsDock(self.model, FM, self)
        self.dock.setObjectName("OptionsDock")
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock)

        # Color Dialog
        self.colorDialog = ColorDialog(self.model, FM, self)
        self.colorDialog.hide()

        # Restore Window Settings
        self.restoreWindowSettings()

        # Create menubar
        self.createMenuBar()

        # Status Bar
        self.coordLabel = QLabel()
        self.statusBar().addPermanentWidget(self.coordLabel)
        self.coordLabel.hide()

        # Load Plot
        self.statusBar().showMessage('Generating Plot...')
        self.dock.updateDock()
        self.colorDialog.updateDialogValues()

        if self.restored:
            self.model.updateIDs()
            self.showCurrentView()
        else:
            # Timer allows GUI to render before plot finishes loading
            QtCore.QTimer.singleShot(0, self.model.generatePlot)
            QtCore.QTimer.singleShot(0, self.showCurrentView)

    # Create and update menus:

    def createMenuBar(self):
        self.mainMenu = self.menuBar()

        # File Menu
        self.saveImageAction = QAction("&Save Image As...", self)
        self.saveImageAction.setShortcut("Ctrl+Shift+S")
        self.saveImageAction.setToolTip('Save plot image')
        self.saveImageAction.setStatusTip('Save plot image')
        self.saveImageAction.triggered.connect(self.saveImage)

        self.saveViewAction = QAction("Save &View Settings...", self)
        self.saveViewAction.setShortcut(QtGui.QKeySequence.Save)
        self.saveViewAction.setStatusTip('Save current view settings')
        self.saveViewAction.triggered.connect(self.saveView)

        self.openAction = QAction("&Open View Settings...", self)
        self.openAction.setShortcut(QtGui.QKeySequence.Open)
        self.openAction.setToolTip('Open saved view settings')
        self.openAction.setStatusTip('Open saved view settings')
        self.openAction.triggered.connect(self.openView)

        self.quitAction = QAction("&Quit", self)
        self.quitAction.setShortcut(QtGui.QKeySequence.Quit)
        self.quitAction.setToolTip('Quit OpenMC Plot Explorer')
        self.quitAction.setStatusTip('Quit OpenMC Plot Explorer')
        self.quitAction.triggered.connect(self.close)

        self.fileMenu = self.mainMenu.addMenu('&File')
        self.fileMenu.addAction(self.saveImageAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.saveViewAction)
        self.fileMenu.addAction(self.openAction)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.quitAction)

        # Edit Menu
        self.applyAction = QAction("&Apply Changes", self)
        self.applyAction.setShortcut("Shift+Return")
        self.applyAction.setToolTip('Generate new view with changes applied')
        self.applyAction.setStatusTip('Generate new view with changes applied')
        self.applyAction.triggered.connect(self.applyChanges)

        self.undoAction = QAction('&Undo', self)
        self.undoAction.setShortcut(QtGui.QKeySequence.Undo)
        self.undoAction.setToolTip('Undo')
        self.undoAction.setStatusTip('Undo last plot view change')
        self.undoAction.setDisabled(True)
        self.undoAction.triggered.connect(self.undo)

        self.redoAction = QAction('&Redo', self)
        self.redoAction.setDisabled(True)
        self.redoAction.setToolTip('Redo')
        self.redoAction.setStatusTip('Redo last plot view change')
        self.redoAction.setShortcut(QtGui.QKeySequence.Redo)
        self.redoAction.triggered.connect(self.redo)

        self.restoreAction = QAction("&Restore Default Plot", self)
        self.restoreAction.setShortcut("Ctrl+R")
        self.restoreAction.setToolTip('Restore to default plot view')
        self.restoreAction.setStatusTip('Restore to default plot view')
        self.restoreAction.triggered.connect(self.restoreDefault)

        self.editMenu = self.mainMenu.addMenu('&Edit')
        self.editMenu.addAction(self.applyAction)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.undoAction)
        self.editMenu.addAction(self.redoAction)
        self.editMenu.addSeparator()
        self.editMenu.addAction(self.restoreAction)
        self.editMenu.addSeparator()
        self.editMenu.aboutToShow.connect(self.updateEditMenu)

        # Edit -> Basis Menu
        self.xyAction = QAction('&xy  ', self)
        self.xyAction.setCheckable(True)
        self.xyAction.setShortcut('Alt+X')
        self.xyAction.setToolTip('Change to xy basis')
        self.xyAction.setStatusTip('Change to xy basis')
        self.xyAction.triggered.connect(
            lambda: self.editBasis('xy', apply=True))

        self.xzAction = QAction('x&z  ', self)
        self.xzAction.setCheckable(True)
        self.xzAction.setShortcut('Alt+Z')
        self.xzAction.setToolTip('Change to xz basis')
        self.xzAction.setStatusTip('Change to xz basis')
        self.xzAction.triggered.connect(
            lambda: self.editBasis('xz', apply=True))

        self.yzAction = QAction('&yz  ', self)
        self.yzAction.setCheckable(True)
        self.yzAction.setShortcut('Alt+Y')
        self.yzAction.setToolTip('Change to yz basis')
        self.yzAction.setStatusTip('Change to yz basis')
        self.yzAction.triggered.connect(
            lambda: self.editBasis('yz', apply=True))

        self.basisMenu = self.editMenu.addMenu('&Basis')
        self.basisMenu.addAction(self.xyAction)
        self.basisMenu.addAction(self.xzAction)
        self.basisMenu.addAction(self.yzAction)
        self.basisMenu.aboutToShow.connect(self.updateBasisMenu)

        # Edit -> Color By Menu
        self.cellAction = QAction('&Cell', self)
        self.cellAction.setCheckable(True)
        self.cellAction.setShortcut('Alt+C')
        self.cellAction.setToolTip('Color by cell')
        self.cellAction.setStatusTip('Color plot by cell')
        self.cellAction.triggered.connect(
            lambda: self.editColorBy('cell', apply=True))

        self.materialAction = QAction('&Material', self)
        self.materialAction.setCheckable(True)
        self.materialAction.setShortcut('Alt+M')
        self.materialAction.setToolTip('Color by material')
        self.materialAction.setStatusTip('Color plot by material')
        self.materialAction.triggered.connect(
            lambda: self.editColorBy('material', apply=True))

        self.colorbyMenu = self.editMenu.addMenu('&Color By')
        self.colorbyMenu.addAction(self.cellAction)
        self.colorbyMenu.addAction(self.materialAction)
        self.colorbyMenu.aboutToShow.connect(self.updateColorbyMenu)

        self.editMenu.addSeparator()

        self.maskingAction = QAction('Enable &Masking', self)
        self.maskingAction.setShortcut('Ctrl+M')
        self.maskingAction.setCheckable(True)
        self.maskingAction.setToolTip('Toggle masking')
        self.maskingAction.setStatusTip('Toggle whether masking is enabled')
        self.maskingAction.triggered[bool].connect(
            lambda bool=bool: self.toggleMasking(bool, apply=True))
        self.editMenu.addAction(self.maskingAction)

        self.highlightingAct = QAction('Enable High&lighting', self)
        self.highlightingAct.setShortcut('Ctrl+L')
        self.highlightingAct.setCheckable(True)
        self.highlightingAct.setToolTip('Toggle highlighting')
        self.highlightingAct.setStatusTip(
            'Toggle whether highlighting is enabled')
        self.highlightingAct.triggered[bool].connect(
            lambda bool=bool: self.toggleHighlighting(bool, apply=True))
        self.editMenu.addAction(self.highlightingAct)

        # View Menu
        self.dockAction = QAction('Hide &Dock', self)
        self.dockAction.setShortcut("Ctrl+D")
        self.dockAction.setToolTip('Toggle dock visibility')
        self.dockAction.setStatusTip('Toggle dock visibility')
        self.dockAction.triggered.connect(self.toggleDockView)

        self.zoomAction = QAction('&Zoom...', self)
        self.zoomAction.setShortcut('Alt+Shift+Z')
        self.zoomAction.setToolTip('Edit zoom factor')
        self.zoomAction.setStatusTip('Edit zoom factor')
        self.zoomAction.triggered.connect(self.editZoomAct)

        self.viewMenu = self.mainMenu.addMenu('&View')
        self.viewMenu.addAction(self.dockAction)
        self.viewMenu.addSeparator()
        self.viewMenu.addAction(self.zoomAction)
        self.viewMenu.aboutToShow.connect(self.updateViewMenu)

        # Window Menu
        self.mainWindowAction = QAction('&Main Window', self)
        self.mainWindowAction.setShortcut('Alt+W')
        self.mainWindowAction.setCheckable(True)
        self.mainWindowAction.setToolTip('Bring main window to front')
        self.mainWindowAction.setStatusTip('Bring main window to front')
        self.mainWindowAction.triggered.connect(self.showMainWindow)

        self.colorDialogAction = QAction('Color &Options', self)
        self.colorDialogAction.setShortcut('Alt+D')
        self.colorDialogAction.setCheckable(True)
        self.colorDialogAction.setToolTip('Bring Color Dialog to front')
        self.colorDialogAction.setStatusTip('Bring Color Dialog to front')
        self.colorDialogAction.triggered.connect(self.showColorDialog)

        self.windowMenu = self.mainMenu.addMenu('&Window')
        self.windowMenu.addAction(self.mainWindowAction)
        self.windowMenu.addAction(self.colorDialogAction)
        self.windowMenu.aboutToShow.connect(self.updateWindowMenu)

    def updateEditMenu(self):
        changed = self.model.currentView != self.model.defaultView
        self.restoreAction.setDisabled(not changed)

        self.maskingAction.setChecked(self.model.currentView.masking)
        self.highlightingAct.setChecked(self.model.currentView.highlighting)

        self.undoAction.setText(f'&Undo ({len(self.model.previousViews)})')
        self.redoAction.setText(f'&Redo ({len(self.model.subsequentViews)})')

    def updateBasisMenu(self):
        self.xyAction.setChecked(self.model.currentView.basis == 'xy')
        self.xzAction.setChecked(self.model.currentView.basis == 'xz')
        self.yzAction.setChecked(self.model.currentView.basis == 'yz')

    def updateColorbyMenu(self):
        cv = self.model.currentView
        self.cellAction.setChecked(cv.colorby == 'cell')
        self.materialAction.setChecked(cv.colorby == 'material')

    def updateViewMenu(self):
        if self.dock.isVisible():
            self.dockAction.setText('Hide &Dock')
        else:
            self.dockAction.setText('Show &Dock')

    def updateWindowMenu(self):
        self.colorDialogAction.setChecked(self.colorDialog.isActiveWindow())
        self.mainWindowAction.setChecked(self.isActiveWindow())

    # Menu and shared methods:

    def saveImage(self):
        filename, ext = QFileDialog.getSaveFileName(self, "Save Plot Image",
                                                    "untitled",
                                                    "Images (*.png *.ppm)")
        if filename:
            if "." not in filename:
                self.pixmap.save(filename + ".png")
            else:
                self.pixmap.save(filename)
            self.statusBar().showMessage('Plot Image Saved', 5000)

    def saveView(self):
        filename, ext = QFileDialog.getSaveFileName(self, "Save View Settings",
                                                    "untitled",
                                                    "View Settings (*.pltvw)")
        if filename:
            if "." not in filename:
                filename += ".pltvw"

            saved = {
                'default': self.model.defaultView,
                'current': self.model.currentView
            }

            with open(filename, 'wb') as file:
                pickle.dump(saved, file)

    def openView(self):
        filename, ext = QFileDialog.getOpenFileName(self, "Open View Settings",
                                                    ".", "*.pltvw")
        if filename:
            try:
                with open(filename, 'rb') as file:
                    saved = pickle.load(file)
            except Exception:
                message = 'Error loading plot settings'
                saved = {'default': None, 'current': None}
            if saved['default'] == self.model.defaultView:
                self.model.activeView = saved['current']
                self.dock.updateDock()
                self.applyChanges()
                message = f'{filename} settings loaded'
            else:
                message = 'Error loading plot settings. Incompatible model.'
            self.statusBar().showMessage(message, 5000)

    def applyChanges(self):
        if self.model.activeView != self.model.currentView:
            self.statusBar().showMessage('Generating Plot...')
            QApplication.processEvents()

            self.model.storeCurrent()
            self.model.subsequentViews = []
            self.model.generatePlot()
            self.resetModels()
            self.showCurrentView()

        else:
            self.statusBar().showMessage('No changes to apply.', 3000)

    def undo(self):
        self.statusBar().showMessage('Generating Plot...')
        QApplication.processEvents()

        self.model.undo()
        self.resetModels()
        self.showCurrentView()
        self.dock.updateDock()
        self.colorDialog.updateDialogValues()

        if not self.model.previousViews:
            self.undoAction.setDisabled(True)
        self.redoAction.setDisabled(False)

    def redo(self):
        self.statusBar().showMessage('Generating Plot...')
        QApplication.processEvents()

        self.model.redo()
        self.resetModels()
        self.showCurrentView()
        self.dock.updateDock()
        self.colorDialog.updateDialogValues()

        if not self.model.subsequentViews:
            self.redoAction.setDisabled(True)
        self.undoAction.setDisabled(False)

    def restoreDefault(self):
        if self.model.currentView != self.model.defaultView:

            self.statusBar().showMessage('Generating Plot...')
            QApplication.processEvents()

            self.model.storeCurrent()
            self.model.activeView = copy.deepcopy(self.model.defaultView)
            self.model.generatePlot()
            self.resetModels()
            self.showCurrentView()
            self.dock.updateDock()
            self.colorDialog.updateDialogValues()

            self.model.subsequentViews = []

    def editBasis(self, basis, apply=False):
        self.model.activeView.basis = basis
        self.dock.updateBasis()
        if apply:
            self.applyChanges()

    def editColorBy(self, domain_kind, apply=False):
        self.model.activeView.colorby = domain_kind
        self.dock.updateColorBy()
        self.colorDialog.updateColorBy()
        if apply:
            self.applyChanges()

    def toggleMasking(self, state, apply=False):
        self.model.activeView.masking = bool(state)
        self.colorDialog.updateMasking()
        if apply:
            self.applyChanges()

    def toggleHighlighting(self, state, apply=False):
        self.model.activeView.highlighting = bool(state)
        self.colorDialog.updateHighlighting()
        if apply:
            self.applyChanges()

    def toggleDockView(self):
        if self.dock.isVisible():
            self.dock.hide()
            if not self.isMaximized() and not self.dock.isFloating():
                self.resize(self.width() - self.dock.width(), self.height())
        else:
            self.dock.setVisible(True)
            if not self.isMaximized() and not self.dock.isFloating():
                self.resize(self.width() + self.dock.width(), self.height())
        self.resizePixmap()
        self.showMainWindow()

    def editZoomAct(self):
        percent, ok = QInputDialog.getInt(self, "Edit Zoom", "Zoom Percent:",
                                          self.dock.zoomBox.value(), 25, 2000)
        if ok:
            self.dock.zoomBox.setValue(percent)

    def editZoom(self, value):
        self.zoom = value
        self.resizePixmap()
        self.dock.zoomBox.setValue(value)

    def showMainWindow(self):
        self.raise_()
        self.activateWindow()

    def showColorDialog(self):
        self.colorDialog.show()
        self.colorDialog.raise_()
        self.colorDialog.activateWindow()

    # Dock methods:

    def editSingleOrigin(self, value, dimension):
        self.model.activeView.origin[dimension] = value

    def editWidth(self, value):
        self.model.activeView.width = value
        self.onRatioChange()
        self.dock.updateWidth()

    def editHeight(self, value):
        self.model.activeView.height = value
        self.onRatioChange()
        self.dock.updateHeight()

    def toggleAspectLock(self, state):
        self.model.activeView.aspectLock = bool(state)
        self.onRatioChange()
        self.dock.updateAspectLock()

    def editVRes(self, value):
        self.model.activeView.vRes = value
        self.dock.updateVRes()

    def editHRes(self, value):
        self.model.activeView.hRes = value
        self.onRatioChange()
        self.dock.updateHRes()

    # Color dialog methods:

    def editMaskingColor(self):
        current_color = self.model.activeView.maskBackground
        dlg = QColorDialog(self)

        dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            self.model.activeView.maskBackground = new_color
            self.colorDialog.updateMaskingColor()

    def editHighlightColor(self):
        current_color = self.model.activeView.highlightBackground
        dlg = QColorDialog(self)

        dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            self.model.activeView.highlightBackground = new_color
            self.colorDialog.updateHighlightColor()

    def editAlpha(self, value):
        self.model.activeView.highlightAlpha = value

    def editSeed(self, value):
        self.model.activeView.highlightSeed = value

    def editBackgroundColor(self, apply=False):
        current_color = self.model.activeView.plotBackground
        dlg = QColorDialog(self)

        dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            self.model.activeView.plotBackground = new_color
            self.colorDialog.updateBackgroundColor()

        if apply:
            self.applyChanges()

    # Plot image methods

    def editPlotOrigin(self, xOr, yOr, zOr=None, apply=False):
        if zOr != None:
            self.model.activeView.origin = [xOr, yOr, zOr]
        else:
            self.model.activeView.origin[self.xBasis] = xOr
            self.model.activeView.origin[self.yBasis] = yOr

        self.dock.updateOrigin()

        if apply:
            self.applyChanges()

    def revertDockControls(self):
        self.dock.revertToCurrent()

    def editDomainColor(self, kind, id):
        if kind == 'Cell':
            domain = self.model.activeView.cells
        else:
            domain = self.model.activeView.materials

        current_color = domain[id].color
        dlg = QColorDialog(self)

        if isinstance(current_color, tuple):
            dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        elif isinstance(current_color, str):
            current_color = openmc.plots._SVG_COLORS[current_color]
            dlg.setCurrentColor(QtGui.QColor.fromRgb(*current_color))
        if dlg.exec_():
            new_color = dlg.currentColor().getRgb()[:3]
            domain[id].color = new_color

        self.applyChanges()

    def toggleDomainMask(self, state, kind, id):
        if kind == 'Cell':
            domain = self.model.activeView.cells
        else:
            domain = self.model.activeView.materials

        domain[id].masked = bool(state)
        self.applyChanges()

    def toggleDomainHighlight(self, state, kind, id):
        if kind == 'Cell':
            domain = self.model.activeView.cells
        else:
            domain = self.model.activeView.materials

        domain[id].highlighted = bool(state)
        self.applyChanges()

    # Helper methods:

    def restoreWindowSettings(self):
        settings = QtCore.QSettings()

        self.resize(settings.value("mainWindow/Size", QtCore.QSize(800, 600)))
        self.move(
            settings.value("mainWindow/Position", QtCore.QPoint(100, 100)))
        self.restoreState(settings.value("mainWindow/State"))

        self.colorDialog.resize(
            settings.value("colorDialog/Size", QtCore.QSize(400, 500)))
        self.colorDialog.move(
            settings.value("colorDialog/Position", QtCore.QPoint(600, 200)))
        self.colorDialog.setVisible(
            bool(settings.value("colorDialog/Visible", 0)))

    def restoreModelSettings(self):
        if os.path.isfile("plot_settings.pkl"):

            with open('plot_settings.pkl', 'rb') as file:
                model = pickle.load(file)

            if model.defaultView == self.model.defaultView:
                self.model.currentView = model.currentView
                self.model.activeView = copy.deepcopy(model.currentView)
                self.model.previousViews = model.previousViews
                self.model.subsequentViews = model.subsequentViews
                if os.path.isfile('plot_ids.binary') \
                    and os.path.isfile('plot.ppm'):
                    self.restored = True

    def resetModels(self):
        self.cellsModel = DomainTableModel(self.model.activeView.cells)
        self.materialsModel = DomainTableModel(self.model.activeView.materials)
        self.cellsModel.beginResetModel()
        self.cellsModel.endResetModel()
        self.materialsModel.beginResetModel()
        self.materialsModel.endResetModel()
        self.colorDialog.updateDomainTabs()

    def showCurrentView(self):
        self.pixmap = QtGui.QPixmap('plot.ppm')
        self.resizePixmap()
        self.updateScale()
        self.updateRelativeBases()

        if self.model.previousViews:
            self.undoAction.setDisabled(False)
        if self.model.subsequentViews:
            self.redoAction.setDisabled(False)
        else:
            self.redoAction.setDisabled(True)

        self.statusBar().showMessage('Done', 1000)
        self.adjustWindow()

    def updateScale(self):
        cv = self.model.currentView
        self.scale = (self.pixmap.width() / cv.width,
                      self.pixmap.height() / cv.height)

    def updateRelativeBases(self):
        cv = self.model.currentView
        self.xBasis = 0 if cv.basis[0] == 'x' else 1
        self.yBasis = 1 if cv.basis[1] == 'y' else 2

    def adjustWindow(self):
        self.screen = app.desktop().screenGeometry()
        self.setMaximumSize(self.screen.width(), self.screen.height())

    def onRatioChange(self):
        av = self.model.activeView
        if av.aspectLock:
            ratio = av.width / max(av.height, .001)
            av.vRes = int(av.hRes / ratio)
            self.dock.updateVRes()

    def showCoords(self, xPlotPos, yPlotPos):
        cv = self.model.currentView
        if cv.basis == 'xy':
            coords = (f"({round(xPlotPos, 2)}, {round(yPlotPos, 2)}, "
                      f"{round(cv.origin[2], 2)})")
        elif cv.basis == 'xz':
            coords = (f"({round(xPlotPos, 2)}, {round(cv.origin[1], 2)}, "
                      f"{round(yPlotPos, 2)})")
        else:
            coords = (f"({round(cv.origin[0], 2)}, {round(xPlotPos, 2)}, "
                      f"{round(yPlotPos, 2)})")
        self.coordLabel.setText(f'{coords}')

    def resizePixmap(self):
        z = self.zoom / 100
        self.plotIm.setPixmap(
            self.pixmap.scaled(self.frame.width() * z,
                               self.frame.height() * z,
                               QtCore.Qt.KeepAspectRatio,
                               QtCore.Qt.SmoothTransformation))
        self.plotIm.adjustSize()

    def moveEvent(self, event):
        self.adjustWindow()

    def resizeEvent(self, event):
        if self.pixmap:
            self.adjustWindow()
            self.resizePixmap()
            self.updateScale()

    def closeEvent(self, event):
        settings = QtCore.QSettings()
        settings.setValue("mainWindow/Size", self.size())
        settings.setValue("mainWindow/Position", self.pos())
        settings.setValue("mainWindow/State", self.saveState())

        settings.setValue("colorDialog/Size", self.colorDialog.size())
        settings.setValue("colorDialog/Position", self.colorDialog.pos())
        visible = int(self.colorDialog.isVisible())
        settings.setValue("colorDialog/Visible", visible)

        if len(self.model.previousViews) > 10:
            self.model.previousViews = self.model.previousViews[-10:]
        if len(self.model.subsequentViews) > 10:
            self.model.subsequentViews = self.model.subsequentViews[-10:]

        with open('plot_settings.pkl', 'wb') as file:
            pickle.dump(self.model, file)