コード例 #1
0
class WorkflowWidget(QWidget):
    sigAddFunction = Signal(object)

    def __init__(self, workflowview: QAbstractItemView):
        super(WorkflowWidget, self).__init__()

        self.view = workflowview

        self.toolbar = QToolBar()
        self.addfunctionmenu = QToolButton()
        self.addfunctionmenu.setIcon(QIcon(path("icons/addfunction.png")))
        self.addfunctionmenu.setText("Add Function")
        # Defer menu population to once the plugins have been loaded; otherwise, the menu may not contain anything
        # if this widget is init'd before all plugins have been loaded.
        self.functionmenu = QMenu()
        self.functionmenu.aboutToShow.connect(self.populateFunctionMenu)
        self.addfunctionmenu.setMenu(self.functionmenu)
        self.addfunctionmenu.setPopupMode(QToolButton.InstantPopup)
        self.toolbar.addWidget(self.addfunctionmenu)
        # self.toolbar.addAction(QIcon(path('icons/up.png')), 'Move Up')
        # self.toolbar.addAction(QIcon(path('icons/down.png')), 'Move Down')
        self.toolbar.addAction(QIcon(path("icons/folder.png")),
                               "Load Workflow")
        self.toolbar.addAction(QIcon(path("icons/trash.png")),
                               "Delete Operation", self.deleteOperation)

        v = QVBoxLayout()
        v.addWidget(self.view)
        v.addWidget(self.toolbar)
        v.setContentsMargins(0, 0, 0, 0)
        self.setLayout(v)

    def populateFunctionMenu(self):
        self.functionmenu.clear()
        sortingDict = {}
        for plugin in pluginmanager.get_plugins_of_type("OperationPlugin"):
            typeOfOperationPlugin = plugin.getCategory()
            if not typeOfOperationPlugin in sortingDict.keys():
                sortingDict[typeOfOperationPlugin] = []
            sortingDict[typeOfOperationPlugin].append(plugin)
        for key in sortingDict.keys():
            self.functionmenu.addSeparator()
            self.functionmenu.addAction(key)
            self.functionmenu.addSeparator()
            for plugin in sortingDict[key]:
                self.functionmenu.addAction(
                    plugin.name,
                    partial(self.addOperation, plugin, autoconnectall=True))

    def addOperation(self, operation: OperationPlugin, autoconnectall=True):
        self.view.model().workflow.addOperation(operation(), autoconnectall)
        print("selected new row:", self.view.model().rowCount() - 1)
        self.view.setCurrentIndex(self.view.model().index(
            self.view.model().rowCount() - 1, 0))

    def deleteOperation(self):
        for index in self.view.selectedIndexes():
            operation = self.view.model().workflow.operations[index.row()]
            self.view.model().workflow.remove_operation(operation)
コード例 #2
0
ファイル: configuration_panel.py プロジェクト: fagan2888/ert
    def __init__(self, config_file, help_tool):
        QWidget.__init__(self)

        layout = QVBoxLayout()

        toolbar = QToolBar("toolbar")

        save_action = toolbar.addAction(resourceIcon("ide/disk"), "Save")
        save_action.triggered.connect(self.save)

        save_as_action = toolbar.addAction(resourceIcon("ide/save_as"),
                                           "Save As")
        save_as_action.triggered.connect(self.saveAs)

        # reload_icon = toolbar.style().standardIcon(QStyle.SP_BrowserReload)
        # reload_action = toolbar.addAction(reload_icon, "Reload")
        # reload_action.triggered.connect(self.reload)

        toolbar.addSeparator()

        toolbar.addAction(help_tool.getAction())

        stretchy_separator = QWidget()
        stretchy_separator.setSizePolicy(QSizePolicy.Expanding,
                                         QSizePolicy.Expanding)
        toolbar.addWidget(stretchy_separator)

        search = SearchBox()
        search.setMaximumWidth(200)
        search.setContentsMargins(5, 2, 5, 2)

        toolbar.addWidget(search)

        layout.addWidget(toolbar)

        self.ide_panel = IdePanel()
        layout.addWidget(self.ide_panel, 1)

        self.config_file = config_file

        with open(config_file) as f:
            config_file_text = f.read()

        self.highlighter = KeywordHighlighter(self.ide_panel.document())

        search.filterChanged.connect(self.highlighter.setSearchString)

        self.parseDefines(config_file_text)
        self.ide_panel.document().setPlainText(config_file_text)

        cursor = self.ide_panel.textCursor()
        cursor.setPosition(0)
        self.ide_panel.setTextCursor(cursor)
        self.ide_panel.setFocus()

        self.setLayout(layout)
コード例 #3
0
class WorkflowWidget(QWidget):
    sigAddFunction = Signal(object)

    def __init__(self, workflowview: QAbstractItemView):
        super(WorkflowWidget, self).__init__()

        self.view = workflowview

        self.toolbar = QToolBar()
        addfunctionmenu = QToolButton()
        functionmenu = QMenu()
        sortingDict = {}
        for plugin in pluginmanager.getPluginsOfCategory("ProcessingPlugin"):
            typeOfProcessingPlugin = plugin.plugin_object.getCategory()
            if not typeOfProcessingPlugin in sortingDict.keys():
                sortingDict[typeOfProcessingPlugin] = []
            sortingDict[typeOfProcessingPlugin].append(plugin)
        for key in sortingDict.keys():
            functionmenu.addSeparator()
            functionmenu.addAction(key)
            functionmenu.addSeparator()
            for plugin in sortingDict[key]:
                functionmenu.addAction(
                    plugin.name,
                    partial(self.addProcess,
                            plugin.plugin_object,
                            autoconnectall=True))
        addfunctionmenu.setMenu(functionmenu)
        addfunctionmenu.setIcon(QIcon(path("icons/addfunction.png")))
        addfunctionmenu.setText("Add Function")
        addfunctionmenu.setPopupMode(QToolButton.InstantPopup)
        self.toolbar.addWidget(addfunctionmenu)
        # self.toolbar.addAction(QIcon(path('icons/up.png')), 'Move Up')
        # self.toolbar.addAction(QIcon(path('icons/down.png')), 'Move Down')
        self.toolbar.addAction(QIcon(path("icons/folder.png")),
                               "Load Workflow")
        self.toolbar.addAction(QIcon(path("icons/trash.png")),
                               "Delete Operation", self.deleteProcess)

        v = QVBoxLayout()
        v.addWidget(self.view)
        v.addWidget(self.toolbar)
        v.setContentsMargins(0, 0, 0, 0)
        self.setLayout(v)

    def addProcess(self, process, autoconnectall=True):
        self.view.model().workflow.addProcess(process(), autoconnectall)
        print("selected new row:", self.view.model().rowCount() - 1)
        self.view.setCurrentIndex(self.view.model().index(
            self.view.model().rowCount() - 1, 0))

    def deleteProcess(self):
        for index in self.view.selectedIndexes():
            process = self.view.model().workflow._processes[index.row()]
            self.view.model().workflow.removeProcess(process)
コード例 #4
0
class PMGWebBrowser(QWidget):
    def __init__(self, parent=None, toolbar='standard'):
        """

        :param parent:
        :param toolbar:多种选项:‘no’,‘standard’,'no_url_input','refresh_only'
        """
        super().__init__(parent)
        self.webview = PMGWebEngineView()
        self.setLayout(QVBoxLayout())
        self.toolbar = QToolBar()
        self.url_input = QLineEdit()
        self.toolbar.addWidget(self.url_input)
        self.toolbar.addAction('go').triggered.connect(
            lambda b: self.load_url())
        back_action = self.toolbar.addAction('back')
        back_action.triggered.connect(self.webview.back)

        forward_action = self.toolbar.addAction('forward')
        forward_action.triggered.connect(self.webview.forward)
        self.layout().addWidget(self.toolbar)
        if toolbar == 'no':
            self.toolbar.hide()
        elif toolbar == 'no_url_input':
            self.url_input.hide()
        elif toolbar == 'refresh_only':
            self.url_input.hide()
            back_action.setEnabled(False)
            forward_action.setEnabled(True)

        self.layout().addWidget(self.webview)
        self.setWindowTitle('My Browser')
        self.showMaximized()

        # command:>
        # jupyter notebook --port 5000 --no-browser --ip='*' --NotebookApp.token=''
        # --NotebookApp.password='' c:\users\12957\

        # self.webview.load(QUrl("http://127.0.0.1:5000/notebooks/desktop/Untitled.ipynb"))  # 直接请求页面。
        # self.webview.load(QUrl("E:\Python\pyminer_bin\PyMiner\bin\pmgwidgets\display\browser\show_formula.html"))  # 直接请求页面。
        # self.setCentralWidget(self.webview)

    def load_url(self, url: str = ''):
        if url == '':
            url = self.url_input.text().strip()
        else:
            self.url_input.setText(url)
        self.webview.load(QUrl(url))
コード例 #5
0
    def __init__(self, *args):
        QMainWindow.__init__(self, *args)

        self.plot = BodePlot(self)
        self.plot.setContentsMargins(5, 5, 5, 0)

        self.setContextMenuPolicy(Qt.NoContextMenu)

        self.setCentralWidget(self.plot)

        toolBar = QToolBar(self)
        self.addToolBar(toolBar)

        btnPrint = QToolButton(toolBar)
        btnPrint.setText("Print")
        btnPrint.setIcon(QIcon(QPixmap(print_xpm)))
        btnPrint.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        toolBar.addWidget(btnPrint)
        btnPrint.clicked.connect(self.print_)

        btnExport = QToolButton(toolBar)
        btnExport.setText("Export")
        btnExport.setIcon(QIcon(QPixmap(print_xpm)))
        btnExport.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        toolBar.addWidget(btnExport)
        btnExport.clicked.connect(self.exportDocument)

        toolBar.addSeparator()

        dampBox = QWidget(toolBar)
        dampLayout = QHBoxLayout(dampBox)
        dampLayout.setSpacing(0)
        dampLayout.addWidget(QWidget(dampBox), 10)  # spacer
        dampLayout.addWidget(QLabel("Damping Factor", dampBox), 0)
        dampLayout.addSpacing(10)

        toolBar.addWidget(dampBox)

        self.statusBar()

        self.showInfo()
コード例 #6
0
    def __init__(self):
        super().__init__()
        self.setWindowTitle(__namever__)
        self.setWindowIcon(get_icon('master'))
        self.setContextMenuPolicy(Qt.NoContextMenu)

        if platform.system() == 'Windows':
            import ctypes
            myappid = 'climate_data_preprocessing_tool'  # arbitrary string
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
                myappid)

        self.data_downloader = None

        # Setup the toolbar.
        self.show_data_downloader_btn = QToolButton()
        self.show_data_downloader_btn.setIcon(get_icon('search_weather_data'))
        self.show_data_downloader_btn.setAutoRaise(True)
        self.show_data_downloader_btn.setToolTip("Download Data")
        self.show_data_downloader_btn.clicked.connect(
            self.show_data_downloader)

        toolbar = QToolBar('Main')
        toolbar.setObjectName('main_toolbar')
        toolbar.setFloatable(False)
        toolbar.setMovable(False)
        toolbar.setIconSize(get_iconsize('normal'))
        self.addToolBar(Qt.TopToolBarArea, toolbar)

        toolbar.addWidget(self.show_data_downloader_btn)
        toolbar.addWidget(create_toolbar_stretcher())
        toolbar.addWidget(self._create_workdir_manager())

        # Setup the main widget.
        self.gapfiller = WeatherDataGapfiller()
        self.setCentralWidget(self.gapfiller)

        self._restore_window_geometry()
        self._restore_window_state()
        self.set_workdir(CONF.get('main', 'working_dir', get_home_dir()))
コード例 #7
0
class UiLinelistsWindow(object):

    # this code was taken as-is from the Designer.
    # Cleaning it up sounds like a lower priority
    # task for now.
    def setupUi(self, MainWindow, title):
        MainWindow.setWindowTitle(title)
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(600, 850)
        MainWindow.setMinimumSize(QSize(300, 350))
        self.centralWidget = QWidget(MainWindow)
        self.centralWidget.setObjectName("centralWidget")
        self.gridLayout = QGridLayout(self.centralWidget)
        self.gridLayout.setContentsMargins(11, 11, 11, 11)
        self.gridLayout.setSpacing(6)
        self.gridLayout.setObjectName("gridLayout")
        self.horizontalLayout_5 = QHBoxLayout()
        self.horizontalLayout_5.setContentsMargins(11, 11, 11, 11)
        self.horizontalLayout_5.setSpacing(6)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.lines_selected_label = QLabel(self.centralWidget)
        self.lines_selected_label.setObjectName("lines_selected_label")
        self.horizontalLayout_5.addWidget(self.lines_selected_label)
        self.label = QLabel(self.centralWidget)
        self.label.setObjectName("label")
        self.horizontalLayout_5.addWidget(self.label)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout_5.addItem(spacerItem)
        self.draw_button = QPushButton(self.centralWidget)
        self.draw_button.setObjectName("draw_button")
        self.horizontalLayout_5.addWidget(self.draw_button)
        self.erase_button = QPushButton(self.centralWidget)
        self.erase_button.setObjectName("erase_button")
        self.horizontalLayout_5.addWidget(self.erase_button)
        self.dismiss_button = QPushButton(self.centralWidget)
        self.dismiss_button.setObjectName("dismiss_button")
        self.horizontalLayout_5.addWidget(self.dismiss_button)
        self.gridLayout.addLayout(self.horizontalLayout_5, 4, 0, 1, 1)
        self.verticalLayout_11 = QVBoxLayout()
        self.verticalLayout_11.setContentsMargins(11, 11, 11, 11)
        self.verticalLayout_11.setSpacing(6)
        self.verticalLayout_11.setObjectName("verticalLayout_11")
        self.tabWidget = QTabWidget(self.centralWidget)
        self.tabWidget.setObjectName("tabWidget")
        self.tabWidget.setTabsClosable(True)
        self.verticalLayout_11.addWidget(self.tabWidget)
        self.gridLayout.addLayout(self.verticalLayout_11, 0, 0, 1, 1)
        self.horizontalLayout_7 = QHBoxLayout()
        self.horizontalLayout_7.setContentsMargins(11, 11, 11, 11)
        self.horizontalLayout_7.setSpacing(6)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout_7.addItem(spacerItem)
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.gridLayout.addLayout(self.horizontalLayout_7, 2, 0, 2, 1)
        MainWindow.setCentralWidget(self.centralWidget)

        # self.menuBar = QMenuBar(MainWindow)
        # self.menuBar.setGeometry(QRect(0, 0, 767, 22))
        # self.menuBar.setObjectName("menuBar")
        #
        # self.menuFile = QMenu(self.menuBar)
        # self.menuFile.setObjectName("menuFile")
        #
        # MainWindow.setMenuBar(self.menuBar)

        self.mainToolBar = QToolBar(MainWindow)
        self.mainToolBar.setMovable(False)
        self.mainToolBar.setFloatable(False)
        self.mainToolBar.setObjectName("mainToolBar")
        MainWindow.addToolBar(Qt.TopToolBarArea, self.mainToolBar)

        # self.statusBar = QStatusBar(MainWindow)
        # self.statusBar.setObjectName("statusBar")
        # MainWindow.setStatusBar(self.statusBar)

        self.actionOpen = QAction(MainWindow)
        icon = QIcon(os.path.join(ICON_PATH, "Open Folder-48.png"))
        self.actionOpen.setIcon(icon)
        self.actionOpen.setObjectName("actionOpen")

        self.actionExport = QAction(MainWindow)
        icon = QIcon(os.path.join(ICON_PATH, "Export-48.png"))
        self.actionExport.setIcon(icon)
        self.actionExport.setObjectName("actionExport")

        self.line_list_selector = QComboBox()
        self.line_list_selector.setToolTip(
            "Select line list from internal library")

        self.actionExit = QAction(MainWindow)
        self.actionExit.setObjectName("actionExit")
        self.actionRemove = QAction(MainWindow)
        self.actionRemove.setObjectName("actionRemove")
        self.actionChange_Color = QAction(MainWindow)
        self.actionChange_Color.setObjectName("actionChange_Color")
        # self.menuFile.addAction(self.actionOpen)
        # self.menuFile.addSeparator()
        # self.menuFile.addAction(self.actionExit)
        # self.menuBar.addAction(self.menuFile.menuAction())
        self.mainToolBar.addAction(self.actionOpen)
        self.mainToolBar.addAction(self.actionExport)
        self.mainToolBar.addSeparator()
        self.mainToolBar.addWidget(self.line_list_selector)
        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QCoreApplication.translate
        self.lines_selected_label.setText(_translate("MainWindow", "0"))
        self.lines_selected_label.setToolTip(
            "Total number of lines selected in all sets.")
        self.label.setText(_translate("MainWindow", "lines selected"))
        self.label.setToolTip("Total number of lines selected in all sets.")
        self.draw_button.setText(_translate("MainWindow", "Draw"))
        self.draw_button.setToolTip(
            "Plot markers for all selected lines in all sets.")
        self.erase_button.setText(_translate("MainWindow", "Erase"))
        self.erase_button.setToolTip("Erase all markers")
        self.dismiss_button.setText(_translate("MainWindow", "Dismiss"))
        self.dismiss_button.setToolTip("Dismiss this window")
        # self.menuFile.setTitle(_translate("MainWindow", "File"))
        self.actionOpen.setText(_translate("MainWindow", "Open"))
        self.actionExport.setText(
            _translate("MainWindow", "Export plotted lines"))
        self.actionExit.setText(_translate("MainWindow", "Exit"))
        self.actionRemove.setText(_translate("MainWindow", "Remove"))
        self.actionRemove.setToolTip(
            _translate("MainWindow", "Removes the selected layer"))
        self.actionChange_Color.setText(
            _translate("MainWindow", "Change Color"))
        self.actionChange_Color.setToolTip(
            _translate("MainWindow", "Change the line color selected layer"))
コード例 #8
0
class WorkingDirectory(SpyderPluginWidget):
    """Working directory changer plugin."""

    CONF_SECTION = 'workingdir'
    CONFIGWIDGET_CLASS = WorkingDirectoryConfigPage
    LOG_PATH = get_conf_path(CONF_SECTION)

    sig_option_changed = Signal(str, object)
    set_previous_enabled = Signal(bool)
    set_next_enabled = Signal(bool)
    redirect_stdio = Signal(bool)
    set_explorer_cwd = Signal(str)
    refresh_findinfiles = Signal()
    set_current_console_wd = Signal(str)

    def __init__(self, parent, workdir=None, **kwds):
        SpyderPluginWidget.__init__(self, parent)

        self.toolbar = QToolBar(self)

        # Initialize plugin
        self.initialize_plugin()

        self.toolbar.setWindowTitle(self.get_plugin_title())
        # Used to save Window state
        self.toolbar.setObjectName(self.get_plugin_title())

        # Previous dir action
        self.history = []
        self.histindex = None
        self.previous_action = create_action(self,
                                             "previous",
                                             None,
                                             ima.icon('previous'),
                                             _('Back'),
                                             triggered=self.previous_directory)
        self.toolbar.addAction(self.previous_action)

        # Next dir action
        self.history = []
        self.histindex = None
        self.next_action = create_action(self,
                                         "next",
                                         None,
                                         ima.icon('next'),
                                         _('Next'),
                                         triggered=self.next_directory)
        self.toolbar.addAction(self.next_action)

        # Enable/disable previous/next actions
        self.set_previous_enabled.connect(self.previous_action.setEnabled)
        self.set_next_enabled.connect(self.next_action.setEnabled)

        # Path combo box
        adjust = self.get_option('working_dir_adjusttocontents')
        self.pathedit = PathComboBox(self, adjust_to_contents=adjust)
        self.pathedit.setToolTip(
            _("This is the working directory for newly\n"
              "opened consoles (Python/IPython consoles and\n"
              "terminals), for the file explorer, for the\n"
              "find in files plugin and for new files\n"
              "created in the editor"))
        self.pathedit.open_dir.connect(self.chdir)
        self.pathedit.activated[str].connect(self.chdir)
        self.pathedit.setMaxCount(self.get_option('working_dir_history'))
        wdhistory = self.load_wdhistory(workdir)
        if workdir is None:
            if self.get_option('startup/use_last_directory'):
                if wdhistory:
                    workdir = wdhistory[0]
                else:
                    workdir = "."
            else:
                workdir = self.get_option('startup/fixed_directory', ".")
                if not osp.isdir(workdir):
                    workdir = "."
        self.chdir(workdir)
        self.pathedit.addItems(wdhistory)
        self.pathedit.selected_text = self.pathedit.currentText()
        self.refresh_plugin()
        self.toolbar.addWidget(self.pathedit)

        # Browse action
        browse_action = create_action(self,
                                      "browse",
                                      None,
                                      ima.icon('DirOpenIcon'),
                                      _('Browse a working directory'),
                                      triggered=self.select_directory)
        self.toolbar.addAction(browse_action)

        # Parent dir action
        parent_action = create_action(self,
                                      "parent",
                                      None,
                                      ima.icon('up'),
                                      _('Change to parent directory'),
                                      triggered=self.parent_directory)
        self.toolbar.addAction(parent_action)

    #------ SpyderPluginWidget API ---------------------------------------------
    def get_plugin_title(self):
        """Return widget title"""
        return _('Global working directory')

    def get_plugin_icon(self):
        """Return widget icon"""
        return ima.icon('DirOpenIcon')

    def get_plugin_actions(self):
        """Setup actions"""
        return (None, None)

    def register_plugin(self):
        """Register plugin in Spyder's main window"""
        self.redirect_stdio.connect(self.main.redirect_internalshell_stdio)
        self.main.console.shell.refresh.connect(self.refresh_plugin)
        iconsize = 24
        self.toolbar.setIconSize(QSize(iconsize, iconsize))
        self.main.addToolBar(self.toolbar)

    def refresh_plugin(self):
        """Refresh widget"""
        curdir = getcwd()
        self.pathedit.add_text(curdir)
        self.save_wdhistory()
        self.set_previous_enabled.emit(self.histindex is not None
                                       and self.histindex > 0)
        self.set_next_enabled.emit(self.histindex is not None and \
                                   self.histindex < len(self.history)-1)

    def apply_plugin_settings(self, options):
        """Apply configuration file's plugin settings"""
        pass

    def closing_plugin(self, cancelable=False):
        """Perform actions before parent main window is closed"""
        return True

    #------ Public API ---------------------------------------------------------
    def load_wdhistory(self, workdir=None):
        """Load history from a text file in user home directory"""
        if osp.isfile(self.LOG_PATH):
            wdhistory, _ = encoding.readlines(self.LOG_PATH)
            wdhistory = [name for name in wdhistory if os.path.isdir(name)]
        else:
            if workdir is None:
                workdir = get_home_dir()
            wdhistory = [workdir]
        return wdhistory

    def save_wdhistory(self):
        """Save history to a text file in user home directory"""
        text = [ to_text_string( self.pathedit.itemText(index) ) \
                 for index in range(self.pathedit.count()) ]
        encoding.writelines(text, self.LOG_PATH)

    @Slot()
    def select_directory(self):
        """Select directory"""
        self.redirect_stdio.emit(False)
        directory = getexistingdirectory(self.main, _("Select directory"),
                                         getcwd())
        if directory:
            self.chdir(directory)
        self.redirect_stdio.emit(True)

    @Slot()
    def previous_directory(self):
        """Back to previous directory"""
        self.histindex -= 1
        self.chdir(directory='', browsing_history=True)

    @Slot()
    def next_directory(self):
        """Return to next directory"""
        self.histindex += 1
        self.chdir(directory='', browsing_history=True)

    @Slot()
    def parent_directory(self):
        """Change working directory to parent directory"""
        self.chdir(os.path.join(getcwd(), os.path.pardir))

    @Slot(str)
    @Slot(str, bool)
    @Slot(str, bool, bool)
    def chdir(self, directory, browsing_history=False, refresh_explorer=True):
        """Set directory as working directory"""
        if directory:
            directory = osp.abspath(to_text_string(directory))

        # Working directory history management
        if browsing_history:
            directory = self.history[self.histindex]
        elif directory in self.history:
            self.histindex = self.history.index(directory)
        else:
            if self.histindex is None:
                self.history = []
            else:
                self.history = self.history[:self.histindex + 1]
            self.history.append(directory)
            self.histindex = len(self.history) - 1

        # Changing working directory
        os.chdir(to_text_string(directory))
        self.refresh_plugin()
        if refresh_explorer:
            self.set_explorer_cwd.emit(directory)
            self.set_as_current_console_wd()
        self.refresh_findinfiles.emit()

    def set_as_current_console_wd(self):
        """Set as current console working directory"""
        self.set_current_console_wd.emit(getcwd())
コード例 #9
0
ファイル: plugin.py プロジェクト: impact27/spyder
class WorkingDirectory(SpyderPluginWidget):
    """Working directory changer plugin."""

    CONF_SECTION = 'workingdir'
    CONFIGWIDGET_CLASS = WorkingDirectoryConfigPage
    LOG_PATH = get_conf_path(CONF_SECTION)

    set_previous_enabled = Signal(bool)
    set_next_enabled = Signal(bool)
    redirect_stdio = Signal(bool)
    set_explorer_cwd = Signal(str)
    refresh_findinfiles = Signal()
    set_current_console_wd = Signal(str)
    
    def __init__(self, parent, workdir=None, **kwds):
        SpyderPluginWidget.__init__(self, parent)
        self.hide()

        self.toolbar = QToolBar(self)

        # Initialize plugin
        self.initialize_plugin()
        self.options_button.hide()
        
        self.toolbar.setWindowTitle(self.get_plugin_title())
        # Used to save Window state
        self.toolbar.setObjectName(self.get_plugin_title())

        # Previous dir action
        self.history = []
        self.histindex = None
        self.previous_action = create_action(self, "previous", None,
                                     ima.icon('previous'), _('Back'),
                                     triggered=self.previous_directory)
        self.toolbar.addAction(self.previous_action)

        # Next dir action
        self.next_action = create_action(self, "next", None,
                                     ima.icon('next'), _('Next'),
                                     triggered=self.next_directory)
        self.toolbar.addAction(self.next_action)

        # Enable/disable previous/next actions
        self.set_previous_enabled.connect(self.previous_action.setEnabled)
        self.set_next_enabled.connect(self.next_action.setEnabled)
        
        # Path combo box
        adjust = self.get_option('working_dir_adjusttocontents')
        self.pathedit = PathComboBox(self, adjust_to_contents=adjust)
        self.pathedit.setToolTip(_("This is the working directory for newly\n"
                               "opened consoles (Python/IPython consoles and\n"
                               "terminals), for the file explorer, for the\n"
                               "find in files plugin and for new files\n"
                               "created in the editor"))
        self.pathedit.open_dir.connect(self.chdir)
        self.pathedit.activated[str].connect(self.chdir)
        self.pathedit.setMaxCount(self.get_option('working_dir_history'))
        wdhistory = self.load_wdhistory(workdir)
        if workdir is None:
            if self.get_option('console/use_project_or_home_directory'):
                workdir = get_home_dir()
            else:
                workdir = self.get_option('console/fixed_directory', default='')
                if not osp.isdir(workdir):
                    workdir = get_home_dir()
        self.chdir(workdir)
        self.pathedit.addItems(wdhistory)
        self.pathedit.selected_text = self.pathedit.currentText()
        self.refresh_plugin()
        self.toolbar.addWidget(self.pathedit)
        
        # Browse action
        browse_action = create_action(self, "browse", None,
                                      ima.icon('DirOpenIcon'),
                                      _('Browse a working directory'),
                                      triggered=self.select_directory)
        self.toolbar.addAction(browse_action)

        # Parent dir action
        parent_action = create_action(self, "parent", None,
                                      ima.icon('up'),
                                      _('Change to parent directory'),
                                      triggered=self.parent_directory)
        self.toolbar.addAction(parent_action)
                
    #------ SpyderPluginWidget API ---------------------------------------------    
    def get_plugin_title(self):
        """Return widget title"""
        return _('Current working directory')
    
    def get_plugin_icon(self):
        """Return widget icon"""
        return ima.icon('DirOpenIcon')
        
    def get_plugin_actions(self):
        """Setup actions"""
        return [None, None]
    
    def register_plugin(self):
        """Register plugin in Spyder's main window"""
        self.redirect_stdio.connect(self.main.redirect_internalshell_stdio)
        self.main.console.shell.refresh.connect(self.refresh_plugin)
        iconsize = 24 
        self.toolbar.setIconSize(QSize(iconsize, iconsize))
        self.main.addToolBar(self.toolbar)
        
    def refresh_plugin(self):
        """Refresh widget"""
        curdir = getcwd_or_home()
        self.pathedit.add_text(curdir)
        self.save_wdhistory()
        self.set_previous_enabled.emit(
                             self.histindex is not None and self.histindex > 0)
        self.set_next_enabled.emit(self.histindex is not None and \
                                   self.histindex < len(self.history)-1)

    def apply_plugin_settings(self, options):
        """Apply configuration file's plugin settings"""
        pass
        
    def closing_plugin(self, cancelable=False):
        """Perform actions before parent main window is closed"""
        return True
        
    #------ Public API ---------------------------------------------------------
    def load_wdhistory(self, workdir=None):
        """Load history from a text file in user home directory"""
        if osp.isfile(self.LOG_PATH):
            wdhistory, _ = encoding.readlines(self.LOG_PATH)
            wdhistory = [name for name in wdhistory if os.path.isdir(name)]
        else:
            if workdir is None:
                workdir = get_home_dir()
            wdhistory = [ workdir ]
        return wdhistory

    def save_wdhistory(self):
        """Save history to a text file in user home directory"""
        text = [ to_text_string( self.pathedit.itemText(index) ) \
                 for index in range(self.pathedit.count()) ]
        try:
            encoding.writelines(text, self.LOG_PATH)
        except EnvironmentError:
            pass
    
    @Slot()
    def select_directory(self):
        """Select directory"""
        self.redirect_stdio.emit(False)
        directory = getexistingdirectory(self.main, _("Select directory"),
                                         getcwd_or_home())
        if directory:
            self.chdir(directory)
        self.redirect_stdio.emit(True)
    
    @Slot()
    def previous_directory(self):
        """Back to previous directory"""
        self.histindex -= 1
        self.chdir(directory='', browsing_history=True)
    
    @Slot()
    def next_directory(self):
        """Return to next directory"""
        self.histindex += 1
        self.chdir(directory='', browsing_history=True)
    
    @Slot()
    def parent_directory(self):
        """Change working directory to parent directory"""
        self.chdir(os.path.join(getcwd_or_home(), os.path.pardir))

    @Slot(str)
    @Slot(str, bool)
    @Slot(str, bool, bool)
    @Slot(str, bool, bool, bool)
    def chdir(self, directory, browsing_history=False,
              refresh_explorer=True, refresh_console=True):
        """Set directory as working directory"""
        if directory:
            directory = osp.abspath(to_text_string(directory))

        # Working directory history management
        if browsing_history:
            directory = self.history[self.histindex]
        elif directory in self.history:
            self.histindex = self.history.index(directory)
        else:
            if self.histindex is None:
                self.history = []
            else:
                self.history = self.history[:self.histindex+1]
            self.history.append(directory)
            self.histindex = len(self.history)-1
        
        # Changing working directory
        try:
            os.chdir(directory)
            if refresh_explorer:
                self.set_explorer_cwd.emit(directory)
            if refresh_console:
                self.set_current_console_wd.emit(directory)
            self.refresh_findinfiles.emit()
        except OSError:
            self.history.pop(self.histindex)
        self.refresh_plugin()
コード例 #10
0
class WorkflowWidget(QWidget):
    sigAddFunction = Signal(object)
    sigRunWorkflow = Signal()

    # TODO -- emit Workflow from sigRunWorkflow

    def __init__(self,
                 workflowview: QAbstractItemView,
                 operation_filter: Callable[[OperationPlugin], bool] = None,
                 workflows: Dict[Workflow, str] = None):
        super(WorkflowWidget, self).__init__()

        self.operation_filter = operation_filter
        self.view = workflowview

        self.autorun_checkbox = QCheckBox("Run Automatically")
        self.autorun_checkbox.setCheckState(Qt.Unchecked)
        self.autorun_checkbox.stateChanged.connect(self._autorun_state_changed)
        self.run_button = QPushButton("Run Workflow")
        self.run_button.clicked.connect(self.sigRunWorkflow.emit)
        self.view.model().workflow.attach(self._autorun)
        # TODO -- actually hook up the auto run OR dependent class needs to connect (see SAXSGUIPlugin)

        self.toolbar = QToolBar()
        self.addfunctionmenu = QToolButton()
        self.addfunctionmenu.setIcon(QIcon(path("icons/addfunction.png")))
        self.addfunctionmenu.setText("Add Function")
        self.addfunctionmenu.setToolTip("Add Operation")
        self.addfunctionmenu.setWhatsThis(
            "This button can be used to add a new operation to the end of a workflow. "
            "A menu to select operations will be populated based on the installed "
            "operations' categories.")
        # Defer menu population to once the plugins have been loaded; otherwise, the menu may not contain anything
        # if this widget is init'd before all plugins have been loaded.
        self.functionmenu = QMenu()
        self.functionmenu.aboutToShow.connect(self.populateFunctionMenu)
        self.addfunctionmenu.setMenu(self.functionmenu)
        self.addfunctionmenu.setPopupMode(QToolButton.InstantPopup)

        self.workflows = WorkflowDict(workflows or {})

        self.workflow_menu = QMenu()
        self.workflow_menu.aboutToShow.connect(self.populateWorkflowMenu)
        self.workflow_selector = QToolButton()
        self.workflow_selector.setIcon(QIcon(path("icons/bookshelf.png")))
        self.workflow_selector.setText("Select Workflow")
        self.workflow_selector.setToolTip("Workflow Library")
        self.workflow_selector.setWhatsThis(
            "This button allows switching between any stored workflows. "
            "(Stored workflows are typically defined programmatically "
            "in a GUI Plugin's modules.)")
        self.workflow_selector.setMenu(self.workflow_menu)
        self.workflow_selector.setPopupMode(QToolButton.InstantPopup)
        self.toolbar.addWidget(self.workflow_selector)

        self.toolbar.addWidget(self.addfunctionmenu)
        # self.toolbar.addAction(QIcon(path('icons/up.png')), 'Move Up')
        # self.toolbar.addAction(QIcon(path('icons/down.png')), 'Move Down')
        action = self.toolbar.addAction(QIcon(path("icons/save.png")),
                                        "Export Workflow")
        action.setEnabled(False)  # FIXME: implement export workflow feature
        action = self.toolbar.addAction(QIcon(path("icons/folder.png")),
                                        "Import Workflow")
        action.setEnabled(False)  # FIXME: implement import workflow feature

        action = self.toolbar.addAction(QIcon(path("icons/trash.png")),
                                        "Delete Operation",
                                        self.deleteOperation)
        action.setWhatsThis("This button removes the currently selected operation from the workflow. "\
                            "(The currently selected operation is highlighted. "\
                            "An operation is selected when its text is clicked in the workflow editor.")

        v = QVBoxLayout()
        v.addWidget(self.view)
        h = QHBoxLayout()
        h.addWidget(self.autorun_checkbox)
        h.addWidget(self.run_button)
        v.addLayout(h)
        v.addWidget(self.toolbar)
        v.setContentsMargins(0, 0, 0, 0)
        self.setLayout(v)

    def _autorun_state_changed(self, state):
        if state == Qt.Checked:
            self.run_button.setDisabled(True)
        else:
            self.run_button.setDisabled(False)

    def _autorun(self):
        if self.autorun_checkbox.isChecked():
            self.sigRunWorkflow.emit()

    def populateFunctionMenu(self):
        self.functionmenu.clear()
        sortingDict = MenuDict()
        operations = pluginmanager.get_plugins_of_type("OperationPlugin")
        if self.operation_filter is not None:
            operations = filter(self.operation_filter, operations)
        for operation in operations:

            categories = operation.categories
            if not categories:
                categories = [("Uncategorized", )
                              ]  # put found operations into a default category

            for categories_tuple in categories:
                if isinstance(categories_tuple, str):
                    categories_tuple = (categories_tuple, )
                submenu = sortingDict
                categories_list = list(categories_tuple)
                while categories_list:
                    category = categories_list.pop(0)
                    submenu = submenu[category]

                submenu['___'].append(operation)

        self._mkMenu(sortingDict)

    def populateWorkflowMenu(self):
        self.workflow_menu.clear()
        for workflow, workflow_name in self.workflows.items():
            self.workflow_menu.addAction(workflow_name,
                                         partial(self.setWorkflow, workflow))

    def _mkMenu(self, sorting_dict, menu=None):
        if menu is None:
            menu = self.functionmenu
            menu.clear()

        for key in sorting_dict:
            if key == '___':
                menu.addSeparator()
                for operation in sorting_dict['___']:
                    menu.addAction(
                        operation.name,
                        partial(self.addOperation,
                                operation,
                                autoconnectall=True))
            else:
                submenu = QMenu(title=key, parent=menu)
                menu.addMenu(submenu)
                self._mkMenu(sorting_dict[key], submenu)

    def setWorkflow(self, workflow: Workflow):
        self.view.model().workflow = workflow

    def addWorkflow(self, workflow: Workflow, name: str = None):
        if name is None:
            name = workflow.name
        if name in self.workflows:
            raise ValueError(
                f'A workflow already exists in this editor with the name "{name}"'
            )
        self.workflows[name] = workflow

    def removeWorkflow(self, workflow):
        for name, match_workflow in self.workflows.items():
            if workflow == match_workflow:
                del self.workflows[name]

    def addOperation(self, operation: OperationPlugin, autoconnectall=True):
        self.view.model().workflow.add_operation(operation())
        if autoconnectall:
            self.view.model().workflow.auto_connect_all()
        print("selected new row:", self.view.model().rowCount() - 1)
        self.view.setCurrentIndex(self.view.model().index(
            self.view.model().rowCount() - 1, 0))

    def deleteOperation(self):
        index = self.view.currentIndex()
        operation = self.view.model().workflow.operations[index.row()]
        self.view.model().workflow.remove_operation(operation)
        self.view.setCurrentIndex(QModelIndex())
コード例 #11
0
class MainWindowLightsOut(QMainWindow):
    """Main Window."""
    def __init__(self):
        """Init Main Window."""
        super().__init__()

        # Title and set icon
        self.setWindowTitle(f"LightsOut by ok97465 - {VER}")

        icon = QIcon()
        icon.addPixmap(QPixmap(r'ok_64x64.ico'), QIcon.Normal, QIcon.Off)
        self.setWindowIcon(icon)

        # Setup toolbar
        self.toolbar = QToolBar()
        self.new_btn = None
        self.clear_btn = None
        self.n_lights_1axis_spinbox = None
        self.show_solution_chkbox = None
        self.setup_toolbar()

        # Setup Button
        self.btn_grid_table = QTableWidget(self)

        # Setup Status Bar
        self.n_clicked = 0
        self.clicked_label = QLabel("0", self)
        self.n_solution_1_label = QLabel("0", self)
        self.setup_status_bar()

        # Setup info  of lights out
        self.manage_puzzle = ManageLightsOutPuzzle()
        self.new_game()

        # Setup Main Layout
        self.setCentralWidget(self.btn_grid_table)
        self.resize_main_window()

        QTimer.singleShot(100, self.resize_main_window)

    def resize_main_window(self):
        """Resize mainwindow to fit table."""
        self.toolbar.adjustSize()
        self.statusBar().adjustSize()
        w = CELL_SIZE * self.manage_puzzle.n_lights_1axis
        w += self.btn_grid_table.frameWidth() * 2

        w = max([w, self.toolbar.width(), self.statusBar().width()])

        h = CELL_SIZE * self.manage_puzzle.n_lights_1axis
        h += self.btn_grid_table.frameWidth() * 2
        h += self.toolbar.frameSize().height()
        h += self.statusBar().height()

        self.resize(w, h)

    def new_game(self):
        """Create New Game."""
        self.manage_puzzle.new_puzzle(self.n_lights_1axis_spinbox.value())
        self.setup_btn_grid(self.manage_puzzle.n_lights_1axis)
        self.show_puzzle()
        self.n_solution_1_label.setText(
            f"{self.manage_puzzle.count_1_of_solution()}")
        self.resize_main_window()

    def setup_toolbar(self):
        """Set up toolbar."""
        self.addToolBar(self.toolbar)
        self.toolbar.setMovable(False)
        self.toolbar.setFloatable(False)

        self.toolbar.setStyleSheet(
            "QToolButton {{height:{30}px;width:{30}px;}}")

        self.new_btn = create_toolbutton(self,
                                         qta.icon("mdi.new-box",
                                                  color=ICON_COLOR),
                                         "Start new game.",
                                         triggered=self.new_game)
        self.toolbar.addWidget(self.new_btn)
        self.toolbar.addSeparator()

        self.clear_btn = create_toolbutton(self,
                                           qta.icon("fa5s.eraser",
                                                    color=ICON_COLOR),
                                           "Click을 초기화 한다.",
                                           triggered=self.show_puzzle)
        self.toolbar.addWidget(self.clear_btn)
        self.toolbar.addSeparator()

        self.n_lights_1axis_spinbox = QSpinBox(self)
        self.n_lights_1axis_spinbox.setValue(4)
        self.n_lights_1axis_spinbox.setRange(2, 10)
        self.n_lights_1axis_spinbox.setAlignment(Qt.AlignRight)
        self.n_lights_1axis_spinbox.setToolTip(
            "Set Number of light in 1 axis.")
        self.toolbar.addWidget(self.n_lights_1axis_spinbox)
        self.toolbar.addSeparator()

        self.show_solution_chkbox = QCheckBox("Solution", self)
        self.show_solution_chkbox.setStyleSheet(""" background : "#32414B" """)
        self.show_solution_chkbox.setToolTip("Show the solution.")
        self.show_solution_chkbox.stateChanged.connect(self.show_solution)
        self.toolbar.addWidget(self.show_solution_chkbox)
        self.toolbar.addSeparator()

        self.toolbar.adjustSize()

    def setup_status_bar(self):
        """Set up status bar."""
        status_bar = QStatusBar(self)
        status_bar.addPermanentWidget(QLabel("Clicked", self))
        status_bar.addPermanentWidget(self.clicked_label)
        status_bar.addPermanentWidget(QLabel("Solution", self))
        status_bar.addPermanentWidget(self.n_solution_1_label)

        self.setStatusBar(status_bar)

    def setup_btn_grid(self, n_lights_1axis):
        """Set up grid of buttons."""
        table = self.btn_grid_table
        if n_lights_1axis != table.rowCount():
            table.clear()
            table.setSelectionMode(QAbstractItemView.NoSelection)
            table.setColumnCount(n_lights_1axis)
            table.setRowCount(n_lights_1axis)
            table.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
            table.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)

            table.horizontalHeader().setDefaultSectionSize(CELL_SIZE)
            table.verticalHeader().setDefaultSectionSize(CELL_SIZE)

            table.horizontalHeader().hide()
            table.verticalHeader().hide()

            for idx_row in range(n_lights_1axis):
                for idx_col in range(n_lights_1axis):
                    btn = QPushButton(self)
                    btn.setStyleSheet(BTN_STYLE)
                    btn.setCheckable(True)
                    btn.setChecked(True)
                    btn.clicked.connect(
                        self.clicked_btn_of_grid_factory(idx_row, idx_col))
                    table.setCellWidget(idx_row, idx_col, btn)
        self.show_solution()

    def clicked_btn_of_grid_factory(self, idx_row, idx_col):
        """Generate lambda function of clicked_btn_of_grid."""
        return lambda: self.clicked_btn_of_grid(idx_row, idx_col)

    def clicked_btn_of_grid(self, idx_row, idx_col):
        """Change state of button around clicked button."""
        self.change_state_btn(idx_row - 1, idx_col + 0)
        self.change_state_btn(idx_row + 1, idx_col + 0)
        self.change_state_btn(idx_row + 0, idx_col - 1)
        self.change_state_btn(idx_row + 0, idx_col + 1)

        self.n_clicked += 1
        self.refresh_n_clicked()

        self.check_solve()

    def change_state_btn(self, idx_row, idx_col):
        """Change state of button."""
        btn = self.btn_grid_table.cellWidget(idx_row, idx_col)
        if btn is not None:
            btn.setChecked(not btn.isChecked())

    def show_solution(self):
        """Show the solution on the button."""
        n_lights = self.manage_puzzle.n_lights_1axis
        solution = self.manage_puzzle.mat_solution
        for idx_row in range(n_lights):
            for idx_col in range(n_lights):
                btn = self.btn_grid_table.cellWidget(idx_row, idx_col)
                if btn is not None:
                    if self.show_solution_chkbox.isChecked():
                        if solution[idx_row, idx_col] == 1:
                            btn.setText("◉")
                        else:
                            btn.setText("")
                    else:
                        btn.setText("")

    def refresh_n_clicked(self):
        """Refresh number of clicked."""
        self.clicked_label.setText(f"{self.n_clicked}")

    def show_puzzle(self):
        """Show puzzle."""
        n_lights = self.manage_puzzle.n_lights_1axis
        puzzle = self.manage_puzzle.mat_puzzle
        for idx_row in range(n_lights):
            for idx_col in range(n_lights):
                btn = self.btn_grid_table.cellWidget(idx_row, idx_col)
                if btn is not None:
                    if puzzle[idx_row, idx_col] == 1:
                        btn.setChecked(True)
                    else:
                        btn.setChecked(False)

        self.n_clicked = 0
        self.refresh_n_clicked()

    def check_solve(self):
        """Check if the problem is solved."""
        n_lights = self.manage_puzzle.n_lights_1axis
        for idx_row in range(n_lights):
            for idx_col in range(n_lights):
                btn = self.btn_grid_table.cellWidget(idx_row, idx_col)
                if btn is not None:
                    if btn.isChecked():
                        return

        n_solution = self.manage_puzzle.count_1_of_solution()
        QMessageBox.information(self, "Succeess",
                                ("Congratulation\n"
                                 f"clicked  : {self.n_clicked}\n"
                                 f"solution : {n_solution}"))
コード例 #12
0
ファイル: NoteEditor.py プロジェクト: mwatts/UniqueBible
class NoteEditor(QMainWindow):

    def __init__(self, parent, noteType, noteFileName="", b=None, c=None, v=None):
        super().__init__()
        self.parent, self.noteType = parent, noteType
        self.noteFileName = noteFileName
        if not self.noteType == "file":
            if v:
                self.b, self.c, self.v = b, c, v
            else:
                self.b, self.c, self.v = config.studyB, config.studyC, config.studyV

        # default - "Rich" mode for editing
        self.html = True
        # default - text is not modified; no need for saving new content
        self.parent.noteSaved = True
        config.noteOpened = True
        config.lastOpenedNote = (noteType, b, c, v)

        # specify window size
        self.resizeWindow(2/3, 2/3)

        # setup interface
        self.setupMenuBar()
        self.addToolBarBreak()
        self.setupToolBar()
        if config.hideNoteEditorStyleToolbar:
            self.toolBar.hide()
        self.addToolBarBreak()
        self.setupTextUtility()
        if config.hideNoteEditorTextUtility:
            self.ttsToolbar.hide()
            self.translateToolbar.hide()
        self.setupLayout()

        # display content when first launched
        self.displayInitialContent()
        self.editor.setFocus()

        # specify window title
        self.updateWindowTitle()

    # re-implementing close event, when users close this widget
    def closeEvent(self, event):
        if self.parent.noteSaved:
            config.noteOpened = False
            event.accept()
            if config.lastOpenedNote and config.openBibleNoteAfterEditorClosed:
                #if config.lastOpenedNote[0] == "file":
                #    self.parent.externalFileButtonClicked()
                if config.lastOpenedNote[0] == "book":
                    self.parent.openStudyBookNote()
                elif config.lastOpenedNote[0] == "chapter":
                    self.parent.openStudyChapterNote()
                elif config.lastOpenedNote[0] == "verse":
                    self.parent.openStudyVerseNote()
        else:
            if self.parent.warningNotSaved():
                self.parent.noteSaved = True
                config.noteOpened = False
                event.accept()
            else:
                self.parent.bringToForeground(self)
                event.ignore()

    # re-implement keyPressEvent, control+S for saving file
    def keyPressEvent(self, event):
        keys = {
            Qt.Key_O: self.openFileDialog,
            Qt.Key_S: self.saveNote,
            Qt.Key_B: self.format_bold,
            Qt.Key_I: self.format_italic,
            Qt.Key_U: self.format_underline,
            Qt.Key_M: self.format_custom,
            Qt.Key_D: self.format_clear,
            Qt.Key_F: self.focusSearchField,
        }
        key = event.key()
        if event.modifiers() == Qt.ControlModifier and key in keys:
            keys[key]()

    # window appearance
    def resizeWindow(self, widthFactor, heightFactor):
        availableGeometry = QGuiApplication.instance().desktop().availableGeometry()
        self.resize(availableGeometry.width() * widthFactor, availableGeometry.height() * heightFactor)

    def updateWindowTitle(self):
        if self.noteType == "file":
            if self.noteFileName:
                *_, title = os.path.split(self.noteFileName)
            else:
                title = "NEW"
        else:
            title = self.parent.bcvToVerseReference(self.b, self.c, self.v)
            if self.noteType == "book":
                title, *_ = title.split(" ")            
            elif self.noteType == "chapter":
                title, *_ = title.split(":")
        mode = {True: "rich", False: "plain"}
        notModified = {True: "", False: " [modified]"}
        self.setWindowTitle("Note Editor ({1} mode) - {0}{2}".format(title, mode[self.html], notModified[self.parent.noteSaved]))

    # switching between "rich" & "plain" mode
    def switchMode(self):
        if self.html:
            note = self.editor.toHtml()
            note = re.sub("<body style={0}[ ]*?font-family:[ ]*?'[^']*?';[ ]*?font-size:[ ]*?[0-9]+?pt;".format('"'), "<body style={0}font-family:'{1}'; font-size:{2}pt;".format('"', config.font, config.fontSize), note)
            self.editor.setPlainText(note)
            self.html = False
            self.updateWindowTitle()
        else:
            note = self.editor.toPlainText()
            self.editor.setHtml(note)
            self.html = True
            self.updateWindowTitle()
        # without this hide / show command below, QTextEdit does not update the text in some devices
        self.hide()
        self.show()

    def setupMenuBar(self):
        if config.toolBarIconFullSize:
            self.setupMenuBarFullIconSize()
        else:
            self.setupMenuBarStandardIconSize()

    def setupMenuBarStandardIconSize(self):

        self.menuBar = QToolBar()
        self.menuBar.setWindowTitle(config.thisTranslation["note_title"])
        self.menuBar.setContextMenuPolicy(Qt.PreventContextMenu)
        # In QWidget, self.menuBar is treated as the menubar without the following line
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.menuBar)

        newButton = QPushButton()
        newButton.setToolTip("{0}\n[Ctrl/Cmd + N]".format(config.thisTranslation["menu7_create"]))
        newButtonFile = os.path.join("htmlResources", "newfile.png")
        newButton.setIcon(QIcon(newButtonFile))
        newButton.clicked.connect(self.newNoteFile)
        self.menuBar.addWidget(newButton)

        openButton = QPushButton()
        openButton.setToolTip("{0}\n[Ctrl/Cmd + O]".format(config.thisTranslation["menu7_open"]))
        openButtonFile = os.path.join("htmlResources", "open.png")
        openButton.setIcon(QIcon(openButtonFile))
        openButton.clicked.connect(self.openFileDialog)
        self.menuBar.addWidget(openButton)

        self.menuBar.addSeparator()

        saveButton = QPushButton()
        saveButton.setToolTip("{0}\n[Ctrl/Cmd + S]".format(config.thisTranslation["note_save"]))
        saveButtonFile = os.path.join("htmlResources", "save.png")
        saveButton.setIcon(QIcon(saveButtonFile))
        saveButton.clicked.connect(self.saveNote)
        self.menuBar.addWidget(saveButton)

        saveAsButton = QPushButton()
        saveAsButton.setToolTip(config.thisTranslation["note_saveAs"])
        saveAsButtonFile = os.path.join("htmlResources", "saveas.png")
        saveAsButton.setIcon(QIcon(saveAsButtonFile))
        saveAsButton.clicked.connect(self.openSaveAsDialog)
        self.menuBar.addWidget(saveAsButton)

        self.menuBar.addSeparator()

        toolBarButton = QPushButton()
        toolBarButton.setToolTip(config.thisTranslation["note_print"])
        toolBarButtonFile = os.path.join("htmlResources", "print.png")
        toolBarButton.setIcon(QIcon(toolBarButtonFile))
        toolBarButton.clicked.connect(self.printNote)
        self.menuBar.addWidget(toolBarButton)

        self.menuBar.addSeparator()

        switchButton = QPushButton()
        switchButton.setToolTip(config.thisTranslation["note_mode"])
        switchButtonFile = os.path.join("htmlResources", "switch.png")
        switchButton.setIcon(QIcon(switchButtonFile))
        switchButton.clicked.connect(self.switchMode)
        self.menuBar.addWidget(switchButton)

        self.menuBar.addSeparator()

#        decreaseFontSizeButton = QPushButton()
#        decreaseFontSizeButton.setToolTip(config.thisTranslation["menu2_smaller"])
#        decreaseFontSizeButtonFile = os.path.join("htmlResources", "fontMinus.png")
#        decreaseFontSizeButton.setIcon(QIcon(decreaseFontSizeButtonFile))
#        decreaseFontSizeButton.clicked.connect(self.decreaseNoteEditorFontSize)
#        self.menuBar.addWidget(decreaseFontSizeButton)
#
#        increaseFontSizeButton = QPushButton()
#        increaseFontSizeButton.setToolTip(config.thisTranslation["menu2_larger"])
#        increaseFontSizeButtonFile = os.path.join("htmlResources", "fontPlus.png")
#        increaseFontSizeButton.setIcon(QIcon(increaseFontSizeButtonFile))
#        increaseFontSizeButton.clicked.connect(self.increaseNoteEditorFontSize)
#        self.menuBar.addWidget(increaseFontSizeButton)

#        self.menuBar.addSeparator()

        self.searchLineEdit = QLineEdit()
        self.searchLineEdit.setClearButtonEnabled(True)
        self.searchLineEdit.setToolTip(config.thisTranslation["menu5_search"])
        self.searchLineEdit.setMaximumWidth(400)
        self.searchLineEdit.returnPressed.connect(self.searchLineEntered)
        self.menuBar.addWidget(self.searchLineEdit)

        self.menuBar.addSeparator()

        toolBarButton = QPushButton()
        toolBarButton.setToolTip(config.thisTranslation["note_toolbar"])
        toolBarButtonFile = os.path.join("htmlResources", "toolbar.png")
        toolBarButton.setIcon(QIcon(toolBarButtonFile))
        toolBarButton.clicked.connect(self.toggleToolbar)
        self.menuBar.addWidget(toolBarButton)

        toolBarButton = QPushButton()
        toolBarButton.setToolTip(config.thisTranslation["note_textUtility"])
        toolBarButtonFile = os.path.join("htmlResources", "textUtility.png")
        toolBarButton.setIcon(QIcon(toolBarButtonFile))
        toolBarButton.clicked.connect(self.toggleTextUtility)
        self.menuBar.addWidget(toolBarButton)

        self.menuBar.addSeparator()

    def setupMenuBarFullIconSize(self):

        self.menuBar = QToolBar()
        self.menuBar.setWindowTitle(config.thisTranslation["note_title"])
        self.menuBar.setContextMenuPolicy(Qt.PreventContextMenu)
        # In QWidget, self.menuBar is treated as the menubar without the following line
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.menuBar)

        iconFile = os.path.join("htmlResources", "newfile.png")
        self.menuBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + N]".format(config.thisTranslation["menu7_create"]), self.newNoteFile)

        iconFile = os.path.join("htmlResources", "open.png")
        self.menuBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + O]".format(config.thisTranslation["menu7_open"]), self.openFileDialog)

        self.menuBar.addSeparator()

        iconFile = os.path.join("htmlResources", "save.png")
        self.menuBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + S]".format(config.thisTranslation["note_save"]), self.saveNote)

        iconFile = os.path.join("htmlResources", "saveas.png")
        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_saveAs"], self.openSaveAsDialog)

        self.menuBar.addSeparator()

        iconFile = os.path.join("htmlResources", "print.png")
        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_print"], self.printNote)

        self.menuBar.addSeparator()

        iconFile = os.path.join("htmlResources", "switch.png")
        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_mode"], self.switchMode)

        self.menuBar.addSeparator()

#        iconFile = os.path.join("htmlResources", "fontMinus.png")
#        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["menu2_smaller"], self.decreaseNoteEditorFontSize)
#
#        iconFile = os.path.join("htmlResources", "fontPlus.png")
#        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["menu2_larger"], self.increaseNoteEditorFontSize)

#        self.menuBar.addSeparator()

        self.searchLineEdit = QLineEdit()
        self.searchLineEdit.setToolTip("{0}\n[Ctrl/Cmd + F]".format(config.thisTranslation["menu5_search"]))
        self.searchLineEdit.setMaximumWidth(400)
        self.searchLineEdit.returnPressed.connect(self.searchLineEntered)
        self.menuBar.addWidget(self.searchLineEdit)

        self.menuBar.addSeparator()

        iconFile = os.path.join("htmlResources", "toolbar.png")
        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_toolbar"], self.toggleToolbar)

        iconFile = os.path.join("htmlResources", "textUtility.png")
        self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_textUtility"], self.toggleTextUtility)

        self.menuBar.addSeparator()

    def toggleToolbar(self):
        if config.hideNoteEditorStyleToolbar:
            self.toolBar.show()
            config.hideNoteEditorStyleToolbar = False
        else:
            self.toolBar.hide()
            config.hideNoteEditorStyleToolbar = True

    def toggleTextUtility(self):
        if config.hideNoteEditorTextUtility:
            self.ttsToolbar.show()
            self.translateToolbar.show()
            config.hideNoteEditorTextUtility = False
        else:
            self.ttsToolbar.hide()
            self.translateToolbar.hide()
            config.hideNoteEditorTextUtility = True

    def printNote(self):
        #document = QTextDocument("Sample Page")
        document = self.editor.document()
        printer = QPrinter()

        myPrintDialog = QPrintDialog(printer, self)
        if myPrintDialog.exec_() == QDialog.Accepted:
            return document.print_(printer)

    def setupToolBar(self):
        if config.toolBarIconFullSize:
            self.setupToolBarFullIconSize()
        else:
            self.setupToolBarStandardIconSize()

    def setupToolBarStandardIconSize(self):

        self.toolBar = QToolBar()
        self.toolBar.setWindowTitle(config.thisTranslation["noteTool_title"])
        self.toolBar.setContextMenuPolicy(Qt.PreventContextMenu)
        # self.toolBar can be treated as an individual widget and positioned with a specified layout
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.toolBar)
        
        items = (
            ("noteTool_textFont", "font.png", self.format_font),
            ("noteTool_textColor", "textColor.png", self.format_textColor),
            ("noteTool_textBackgroundColor", "textBgColor.png", self.format_textBackgroundColor),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()

        items = (
            ("noteTool_header1", "header1.png", self.format_header1),
            ("noteTool_header2", "header2.png", self.format_header2),
            ("noteTool_header3", "header3.png", self.format_header3),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()
        
        items = (
            ("{0}\n[Ctrl/Cmd + B]".format(config.thisTranslation["noteTool_bold"]), "bold.png", self.format_bold),
            ("{0}\n[Ctrl/Cmd + I]".format(config.thisTranslation["noteTool_italic"]), "italic.png", self.format_italic),
            ("{0}\n[Ctrl/Cmd + U]".format(config.thisTranslation["noteTool_underline"]), "underline.png", self.format_underline),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar, translation=False)

        self.toolBar.addSeparator()

        items = (
            ("noteTool_superscript", "superscript.png", self.format_superscript),
            ("noteTool_subscript", "subscript.png", self.format_subscript),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()

        self.parent.addStandardIconButton("{0}\n[Ctrl/Cmd + M]\n\n{1}\n* {4}\n* {5}\n* {6}\n\n{2}\n*1 {4}\n*2 {5}\n*3 {6}\n\n{3}\n{10}{4}|{5}|{6}{11}\n{10}{7}|{8}|{9}{11}".format(config.thisTranslation["noteTool_trans0"], config.thisTranslation["noteTool_trans1"], config.thisTranslation["noteTool_trans2"], config.thisTranslation["noteTool_trans3"], config.thisTranslation["noteTool_no1"], config.thisTranslation["noteTool_no2"], config.thisTranslation["noteTool_no3"], config.thisTranslation["noteTool_no4"], config.thisTranslation["noteTool_no5"], config.thisTranslation["noteTool_no6"], "{", "}"), "custom.png", self.format_custom, self.toolBar, translation=False)

        self.toolBar.addSeparator()

        items = (
            ("noteTool_left", "align_left.png", self.format_left),
            ("noteTool_centre", "align_center.png", self.format_center),
            ("noteTool_right", "align_right.png", self.format_right),
            ("noteTool_justify", "align_justify.png", self.format_justify),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()

        self.parent.addStandardIconButton("{0}\n[Ctrl/Cmd + D]".format(config.thisTranslation["noteTool_delete"]), "clearFormat.png", self.format_clear, self.toolBar, translation=False)

        self.toolBar.addSeparator()

        items = (
            ("noteTool_hyperlink", "hyperlink.png", self.openHyperlinkDialog),
            ("noteTool_externalImage", "gallery.png", self.openImageDialog),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()

        items = (
            ("noteTool_image", "addImage.png", self.addInternalImage),
            ("noteTool_exportImage", "export.png", self.exportNoteImages),
        )
        for item in items:
            toolTip, icon, action = item
            self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar)

        self.toolBar.addSeparator()

    def setupToolBarFullIconSize(self):

        self.toolBar = QToolBar()
        self.toolBar.setWindowTitle(config.thisTranslation["noteTool_title"])
        self.toolBar.setContextMenuPolicy(Qt.PreventContextMenu)
        # self.toolBar can be treated as an individual widget and positioned with a specified layout
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.toolBar)

        iconFile = os.path.join("htmlResources", "font.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_textFont"], self.format_font)

        iconFile = os.path.join("htmlResources", "textColor.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_textColor"], self.format_textColor)

        iconFile = os.path.join("htmlResources", "textBgColor.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_textBackgroundColor"], self.format_textBackgroundColor)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "header1.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_header1"], self.format_header1)

        iconFile = os.path.join("htmlResources", "header2.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_header2"], self.format_header2)

        iconFile = os.path.join("htmlResources", "header3.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_header3"], self.format_header3)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "bold.png")
        self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + B]".format(config.thisTranslation["noteTool_bold"]), self.format_bold)

        iconFile = os.path.join("htmlResources", "italic.png")
        self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + I]".format(config.thisTranslation["noteTool_italic"]), self.format_italic)

        iconFile = os.path.join("htmlResources", "underline.png")
        self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + U]".format(config.thisTranslation["noteTool_underline"]), self.format_underline)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "custom.png")
        self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + M]\n\n{1}\n* {4}\n* {5}\n* {6}\n\n{2}\n*1 {4}\n*2 {5}\n*3 {6}\n\n{3}\n{10}{4}|{5}|{6}{11}\n{10}{7}|{8}|{9}{11}".format(config.thisTranslation["noteTool_trans0"], config.thisTranslation["noteTool_trans1"], config.thisTranslation["noteTool_trans2"], config.thisTranslation["noteTool_trans3"], config.thisTranslation["noteTool_no1"], config.thisTranslation["noteTool_no2"], config.thisTranslation["noteTool_no3"], config.thisTranslation["noteTool_no4"], config.thisTranslation["noteTool_no5"], config.thisTranslation["noteTool_no6"], "{", "}"), self.format_custom)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "align_left.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_left"], self.format_left)

        iconFile = os.path.join("htmlResources", "align_center.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_centre"], self.format_center)

        iconFile = os.path.join("htmlResources", "align_right.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_right"], self.format_right)

        iconFile = os.path.join("htmlResources", "align_justify.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_justify"], self.format_justify)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "clearFormat.png")
        self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + D]".format(config.thisTranslation["noteTool_delete"]), self.format_clear)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "hyperlink.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_hyperlink"], self.openHyperlinkDialog)

        iconFile = os.path.join("htmlResources", "gallery.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_externalImage"], self.openImageDialog)

        self.toolBar.addSeparator()

        iconFile = os.path.join("htmlResources", "addImage.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_image"], self.addInternalImage)

        iconFile = os.path.join("htmlResources", "export.png")
        self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_exportImage"], self.exportNoteImages)

        self.toolBar.addSeparator()

    def setupLayout(self):
        self.editor = QTextEdit()  
        self.editor.setStyleSheet("font-family:'{0}'; font-size:{1}pt;".format(config.font, config.fontSize));
        self.editor.textChanged.connect(self.textChanged)
        self.setCentralWidget(self.editor)

        #self.layout = QGridLayout()
        #self.layout.setMenuBar(self.menuBar)
        #self.layout.addWidget(self.toolBar, 0, 0)
        #self.layout.addWidget(self.editor, 1, 0)
        #self.setLayout(self.layout)

    # adjustment of note editor font size
    def increaseNoteEditorFontSize(self):
        if self.html:
            self.editor.selectAll()
            config.noteEditorFontSize += 1
            self.editor.setFontPointSize(config.noteEditorFontSize)
            self.hide()
            self.show()

    def decreaseNoteEditorFontSize(self):
        if self.html and not config.noteEditorFontSize == 0:
            self.editor.selectAll()
            config.noteEditorFontSize -= 1
            self.editor.setFontPointSize(config.noteEditorFontSize)
            self.hide()
            self.show()

    # search field entered
    def searchLineEntered(self):
        searchString = self.searchLineEdit.text()
        if searchString:
            cursor = self.editor.document().find(searchString, self.editor.textCursor())
        if cursor:
            self.editor.setTextCursor(cursor)
        self.hide()
        self.show()

    def focusSearchField(self):
        self.searchLineEdit.setFocus()

    # track if the text being modified
    def textChanged(self):
        if self.parent.noteSaved:
            self.parent.noteSaved = False
            self.updateWindowTitle()

    # display content when first launched
    def displayInitialContent(self):
        if self.noteType == "file":
            if self.noteFileName:
                self.openNoteFile(self.noteFileName)
            else:
                self.newNoteFile()
        else:
            self.openBibleNote()

        self.editor.selectAll()
        self.editor.setFontPointSize(config.noteEditorFontSize)
        self.editor.moveCursor(QTextCursor.Start, QTextCursor.MoveAnchor)

        self.parent.noteSaved = True

    def getEmptyPage(self):
        strict = ''
        if config.includeStrictDocTypeInNote:
            strict = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">'
        return """{4}<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li {0} white-space: pre-wrap; {1}
</style></head><body style="font-family:'{2}'; font-size:{3}pt; font-weight:400; font-style:normal;">
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>"""\
            .format("{", "}", config.font, config.fontSize, strict)

    # load chapter / verse notes from sqlite database
    def openBibleNote(self):
        if self.noteType == "book":
            note = NoteService.getBookNote(self.b)
        elif self.noteType == "chapter":
            note = NoteService.getChapterNote(self.b, self.c)
        elif self.noteType == "verse":
            note = NoteService.getVerseNote(self.b, self.c, self.v)
        if note == config.thisTranslation["empty"]:
            note = self.getEmptyPage()
        else:
            note = self.fixNoteFont(note)
        if self.html:
            self.editor.setHtml(note)
        else:
            self.editor.setPlainText(note)

    # File I / O
    def newNoteFile(self):
        if self.parent.noteSaved:
            self.newNoteFileAction()
        elif self.parent.warningNotSaved():
            self.newNoteFileAction()

    def newNoteFileAction(self):
        self.noteType = "file"
        self.noteFileName = ""
        #self.editor.clear()
        defaultText = self.getEmptyPage()
        if self.html:
            self.editor.setHtml(defaultText)
        else:
            self.editor.setPlainText(defaultText)
        self.parent.noteSaved = True
        self.updateWindowTitle()
        self.hide()
        self.show()

    def openFileDialog(self):
        if self.parent.noteSaved:
            self.openFileDialogAction()
        elif self.parent.warningNotSaved():
            self.openFileDialogAction()

    def openFileDialogAction(self):
        options = QFileDialog.Options()
        fileName, filtr = QFileDialog.getOpenFileName(self,
                config.thisTranslation["menu7_open"],
                "notes",
                "UniqueBible.app Note Files (*.uba);;HTML Files (*.html);;HTM Files (*.htm);;All Files (*)", "", options)
        if fileName:
            self.openNoteFile(fileName)

    def openNoteFile(self, fileName):
        try:
            f = open(fileName, "r", encoding="utf-8")
        except:
            print("Failed to open '{0}'".format(fileName))
        note = f.read()
        f.close()
        self.noteType = "file"
        self.noteFileName = fileName
        note = self.fixNoteFont(note)
        if self.html:
            self.editor.setHtml(note)
        else:
            self.editor.setPlainText(note)
        self.parent.noteSaved = True
        self.updateWindowTitle()
        self.hide()
        self.show()

    def saveNote(self):
        if self.html:
            note = self.editor.toHtml()
        else:
            note = self.editor.toPlainText()
        note = self.fixNoteFont(note)
        if self.noteType == "book":
            NoteService.saveBookNote(self.b, note)
            if config.openBibleNoteAfterSave:
                self.parent.openBookNote(self.b,)
            self.parent.noteSaved = True
            self.updateWindowTitle()
        elif self.noteType == "chapter":
            NoteService.saveChapterNote(self.b, self.c, note)
            if config.openBibleNoteAfterSave:
                self.parent.openChapterNote(self.b, self.c)
            self.parent.noteSaved = True
            self.updateWindowTitle()
        elif self.noteType == "verse":
            NoteService.saveVerseNote(self.b, self.c, self.v, note)
            if config.openBibleNoteAfterSave:
                self.parent.openVerseNote(self.b, self.c, self.v)
            self.parent.noteSaved = True
            self.updateWindowTitle()
        elif self.noteType == "file":
            if self.noteFileName == "":
                self.openSaveAsDialog()
            else:
                self.saveAsNote(self.noteFileName)

    def openSaveAsDialog(self):
        if self.noteFileName:
            *_, defaultName = os.path.split(self.noteFileName)
        else:
            defaultName = "new.uba"
        options = QFileDialog.Options()
        fileName, filtr = QFileDialog.getSaveFileName(self,
                config.thisTranslation["note_saveAs"],
                os.path.join("notes", defaultName),
                "UniqueBible.app Note Files (*.uba);;HTML Files (*.html);;HTM Files (*.htm);;All Files (*)", "", options)
        if fileName:
            if not "." in os.path.basename(fileName):
                fileName = fileName + ".uba"
            self.saveAsNote(fileName)

    def saveAsNote(self, fileName):
        if self.html:
            note = self.editor.toHtml()
        else:
            note = self.editor.toPlainText()
        note = self.fixNoteFont(note)
        f = open(fileName, "w", encoding="utf-8")
        f.write(note)
        f.close()
        self.noteFileName = fileName
        self.parent.addExternalFileHistory(fileName)
        self.parent.setExternalFileButton()
        self.parent.noteSaved = True
        self.updateWindowTitle()

    def fixNoteFont(self, note):
        note = re.sub("<body style={0}[ ]*?font-family:[ ]*?'[^']*?';[ ]*?font-size:[ ]*?[0-9]+?pt;".format('"'), "<body style={0}font-family:'{1}'; font-size:{2}pt;".format('"', config.font, config.fontSize), note)
        if not config.includeStrictDocTypeInNote:
            note = re.sub("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">\n""", "", note)
        return note


    # formatting styles
    def format_clear(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                selectedText = """<span style="font-family:'{0}'; font-size:{1}pt;">{2}</span>""".format(config.font, config.fontSize, selectedText)
                self.editor.insertHtml(selectedText)
            else:
                selectedText = re.sub("<[^\n<>]*?>", "", selectedText)
                self.editor.insertPlainText(selectedText)
        else:
            self.selectTextFirst()

    def format_header1(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.insertHtml("<h1>{0}</h1>".format(selectedText))
            else:
                self.editor.insertPlainText("<h1>{0}</h1>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_header2(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.insertHtml("<h2>{0}</h2>".format(selectedText))
            else:
                self.editor.insertPlainText("<h2>{0}</h2>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_header3(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.insertHtml("<h3>{0}</h3>".format(selectedText))
            else:
                self.editor.insertPlainText("<h3>{0}</h3>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_font(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            ok, font = QFontDialog.getFont(QFont(config.font, config.fontSize), self)
            if ok:
                if self.html:
                    self.editor.setCurrentFont(font)
                else:
                    fontFamily, fontSize, i1, i2, fontWeight, italic, underline, strikeout, *_ = font.key().split(",")
                    spanTag = """<span style="font-family:'{0}'; font-size:{1}pt;""".format(fontFamily, fontSize)
                    # add font weight
                    if fontWeight == "25":
                        spanTag += " font-weight:200;"
                    elif fontWeight == "75":
                        spanTag += " font-weight:600;"
                    # add italic style
                    if italic == "1":
                        spanTag += " font-style:italic;"
                    # add both underline and strikeout style
                    if underline == "1" and strikeout == "1":
                        spanTag += " text-decoration: underline line-through;"
                    # add underline style
                    elif underline == "1":
                        spanTag += " text-decoration: underline;"
                    # add strikeout style
                    elif strikeout == "1":
                        spanTag += " text-decoration: line-through;"
                    # close tag
                    spanTag += '">'
                    self.editor.insertPlainText("{0}{1}</span>".format(spanTag, selectedText))
        else:
            self.selectTextFirst()
        
    def format_textColor(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            color = QColorDialog.getColor(Qt.darkRed, self)
            if color.isValid():
                if self.html:
                    self.editor.setTextColor(color)
                else:
                    self.editor.insertPlainText('<span style="color:{0};">{1}</span>'.format(color.name(), self.editor.textCursor().selectedText()))
        else:
            self.selectTextFirst()

    def format_textBackgroundColor(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            color = QColorDialog.getColor(Qt.yellow, self)
            if color.isValid():
                if self.html:
                    self.editor.setTextBackgroundColor(color)
                else:
                    self.editor.insertPlainText('<span style="background-color:{0};">{1}</span>'.format(color.name(), selectedText))
        else:
            self.selectTextFirst()

    def format_bold(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                # Reference: https://doc.qt.io/qt-5/qfont.html#Weight-enum
                # Bold = 75
                self.editor.setFontWeight(75)
            else:
                self.editor.insertPlainText("<b>{0}</b>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_italic(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setFontItalic(True)
            else:
                self.editor.insertPlainText("<i>{0}</i>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_underline(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setFontUnderline(True)
            else:
                self.editor.insertPlainText("<u>{0}</u>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_superscript(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.insertHtml("<sup>{0}</sup>".format(selectedText))
            else:
                self.editor.insertPlainText("<sup>{0}</sup>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_subscript(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.insertHtml("<sub>{0}</sub>".format(selectedText))
            else:
                self.editor.insertPlainText("<sub>{0}</sub>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_center(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setAlignment(Qt.AlignCenter)
            else:
                self.editor.insertPlainText("<div style='text-align:center;'>{0}</div>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_justify(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setAlignment(Qt.AlignJustify)
            else:
                self.editor.insertPlainText("<div style='text-align:justify;'>{0}</div>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_left(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setAlignment(Qt.AlignLeft)
            else:
                self.editor.insertPlainText("<div style='text-align:left;'>{0}</div>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_right(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            if self.html:
                self.editor.setAlignment(Qt.AlignRight)
            else:
                self.editor.insertPlainText("<div style='text-align:right;'>{0}</div>".format(selectedText))
        else:
            self.selectTextFirst()

    def format_custom(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            selectedText = self.customFormat(selectedText)
            if self.html:
                self.editor.insertHtml(selectedText)
            else:
                self.editor.insertPlainText(selectedText)
        else:
            self.selectTextFirst()

    def customFormat(self, text):
        # QTextEdit's line break character by pressing ENTER in plain & html mode "
"
        # please note that "
" is not an empty string
        text = text.replace("
", "\n")

        text = re.sub("^\*[0-9]+? (.*?)$", r"<ol><li>\1</li></ol>", text, flags=re.M)
        text = text.replace("</ol>\n<ol>", "\n")
        text = re.sub("^\* (.*?)$", r"<ul><li>\1</li></ul>", text, flags=re.M)
        text = text.replace("</ul>\n<ul>", "\n")
        text = re.sub("^{.*?}$", self.formatHTMLTable, text, flags=re.M)
        text = text.replace("</table>\n<table>", "\n")

        # add style to table here
        # please note that QTextEdit supports HTML 4, rather than HTML 5
        # take this old reference: https://www.w3schools.com/tags/tag_table.asp
        text = text.replace('<table>', '<table border="1" cellpadding="5">')

        # convert back to QTextEdit linebreak
        text = text.replace("\n", "
")

        # wrap with default font and font-size
        text = """<span style="font-family:'{0}'; font-size:{1}pt;">{2}</span>""".format(config.font, config.fontSize, text)
        return text

    def formatHTMLTable(self, match):
        row = match.group()[1:-1]
        row = "".join(["<td>{0}</td>".format(cell) for cell in row.split("|")])
        return "<table><tr>{0}</tr></table>".format(row)

    def addInternalImage(self):
        self.openImageDialog(external=False)

    def openImageDialog(self, external=True):
        options = QFileDialog.Options()
        fileName, filtr = QFileDialog.getOpenFileName(self,
                config.thisTranslation["html_open"],
                self.parent.openFileNameLabel.text(),
                "JPG Files (*.jpg);;JPEG Files (*.jpeg);;PNG Files (*.png);;GIF Files (*.gif);;BMP Files (*.bmp);;All Files (*)", "", options)
        if fileName:
            if external:
                self.linkExternalImage(fileName)
            else:
                self.embedImage(fileName)

    def embedImage(self, fileName):
        name, extension = os.path.splitext(os.path.basename(fileName))
        with open(fileName, "rb") as fileObject:
            binaryData = fileObject.read()
            encodedData = base64.b64encode(binaryData)
            asciiString = encodedData.decode('ascii')
            imageTag = '<img src="data:image/{2};base64,{0}" alt="{1}">'.format(asciiString, name, extension[1:])
            if self.html:
                self.editor.insertHtml(imageTag)
            else:
                self.editor.insertPlainText(imageTag)

    def exportNoteImages(self):
        options = QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly
        directory = QFileDialog.getExistingDirectory(self,
                config.thisTranslation["select_a_folder"],
                self.parent.directoryLabel.text(), options)
        if directory:
            if self.html:
                htmlText = self.editor.toHtml()
            else:
                htmlText = self.editor.toPlainText()
            searchPattern = r'src=(["{0}])data:image/([^<>]+?);[ ]*?base64,[ ]*?([^ <>]+?)\1'.format("'")
            for counter, value in enumerate(re.findall(searchPattern, htmlText)):
                *_, ext, asciiString = value
                binaryString = asciiString.encode("ascii")
                binaryData = base64.b64decode(binaryString)
                imageFilePath = os.path.join(directory, "image{0}.{1}".format(counter + 1, ext))
                with open(imageFilePath, "wb") as fileObject:
                    fileObject.write(binaryData)

    def linkExternalImage(self, fileName):
        imageTag = '<img src="{0}" alt="UniqueBible.app">'.format(fileName)
        if self.html:
            self.editor.insertHtml(imageTag)
        else:
            self.editor.insertPlainText(imageTag)

    def openHyperlinkDialog(self):
        selectedText = self.editor.textCursor().selectedText()
        if selectedText:
            text, ok = QInputDialog.getText(self, "UniqueBible.app",
                    config.thisTranslation["noteTool_hyperlink"], QLineEdit.Normal,
                    selectedText)
            if ok and text != '':
                hyperlink = '<a href="{0}">{1}</a>'.format(text, selectedText)
                hyperlink = """<span style="font-family:'{0}'; font-size:{1}pt;">{2}</span>""".format(config.font, config.fontSize, hyperlink)
                if self.html:
                    self.editor.insertHtml(hyperlink)
                else:
                    self.editor.insertPlainText(hyperlink)
        else:
            self.selectTextFirst()

    def setupTextUtility(self):

        self.ttsToolbar = QToolBar()
        self.ttsToolbar.setWindowTitle(config.thisTranslation["noteTool_title"])
        self.ttsToolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        # self.toolBar can be treated as an individual widget and positioned with a specified layout
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.ttsToolbar)

        self.languageCombo = QComboBox()
        self.ttsToolbar.addWidget(self.languageCombo)
        if config.espeak:
            languages = TtsLanguages().isoLang2epeakLang
        else:
            languages = TtsLanguages().isoLang2qlocaleLang
        self.languageCodes = list(languages.keys())
        for code in self.languageCodes:
            self.languageCombo.addItem(languages[code][1])
        # Check if selected tts engine has the language user specify.
        if not (config.ttsDefaultLangauge in self.languageCodes):
            config.ttsDefaultLangauge = "en"
        # Set initial item
        initialIndex = self.languageCodes.index(config.ttsDefaultLangauge)
        self.languageCombo.setCurrentIndex(initialIndex)

        button = QPushButton(config.thisTranslation["speak"])
        button.setToolTip(config.thisTranslation["speak"])
        button.clicked.connect(self.speakText)
        self.ttsToolbar.addWidget(button)
        button = QPushButton(config.thisTranslation["stop"])
        button.setToolTip(config.thisTranslation["stop"])
        button.clicked.connect(self.parent.textCommandParser.stopTtsAudio)
        self.ttsToolbar.addWidget(button)

        self.translateToolbar = QToolBar()
        self.translateToolbar.setWindowTitle(config.thisTranslation["noteTool_title"])
        self.translateToolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        # self.toolBar can be treated as an individual widget and positioned with a specified layout
        # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window
        self.addToolBar(self.translateToolbar)

        self.fromLanguageCombo = QComboBox()
        self.translateToolbar.addWidget(self.fromLanguageCombo)
        self.fromLanguageCombo.addItems(["[Auto]"] +Translator.fromLanguageNames)
        initialIndex = 0
        self.fromLanguageCombo.setCurrentIndex(initialIndex)

        button = QPushButton(config.thisTranslation["context1_translate"])
        button.setToolTip(config.thisTranslation["context1_translate"])
        button.clicked.connect(self.translateText)
        self.translateToolbar.addWidget(button)

        self.toLanguageCombo = QComboBox()
        self.translateToolbar.addWidget(self.toLanguageCombo)
        self.toLanguageCombo.addItems(Translator.toLanguageNames)
        initialIndex = Translator.toLanguageNames.index(config.userLanguage)
        self.toLanguageCombo.setCurrentIndex(initialIndex)

    def speakText(self):
        text = self.editor.textCursor().selectedText()
        if text:
            if config.isTtsInstalled:
                if ":::" in text:
                    text = text.split(":::")[-1]
                command = "SPEAK:::{0}:::{1}".format(self.languageCodes[self.languageCombo.currentIndex()], text)
                self.parent.runTextCommand(command)
            else:
                self.displayMessage(config.thisTranslation["message_noSupport"])
        else:
            self.selectTextFirst()

    def translateText(self):
        text = self.editor.textCursor().selectedText()
        if text:
            translator = Translator()
            if translator.language_translator is not None:
                fromLanguage = Translator.fromLanguageCodes[self.fromLanguageCombo.currentIndex() - 1] if self.fromLanguageCombo.currentIndex() != 0 else translator.identify(text)
                toLanguage = Translator.toLanguageCodes[self.toLanguageCombo.currentIndex()]
                result = translator.translate(text, fromLanguage, toLanguage)
                self.editor.insertPlainText(result)
            else:
                self.displayMessage(config.thisTranslation["ibmWatsonNotEnalbed"])
                webbrowser.open("https://github.com/eliranwong/UniqueBible/wiki/IBM-Watson-Language-Translator")
        else:
            self.selectTextFirst()

    def selectTextFirst(self):
        self.displayMessage(config.thisTranslation["selectTextFirst"])

    def displayMessage(self, message="", title="UniqueBible"):
        reply = QMessageBox.information(self, title, message)
コード例 #13
0
class WorkflowWidget(QWidget):
    sigAddFunction = Signal(object)
    sigRunWorkflow = Signal(object)

    # TODO -- emit Workflow from sigRunWorkflow

    def __init__(self, workflowview: QAbstractItemView):
        super(WorkflowWidget, self).__init__()

        self.view = workflowview

        self.autorun_checkbox = QCheckBox("Run Automatically")
        self.autorun_checkbox.setCheckState(Qt.Unchecked)
        self.autorun_checkbox.stateChanged.connect(self._autorun_state_changed)
        self.run_button = QPushButton("Run Workflow")
        self.run_button.clicked.connect(self.sigRunWorkflow.emit)
        # TODO -- actually hook up the auto run OR dependent class needs to connect (see SAXSGUIPlugin)

        self.toolbar = QToolBar()
        self.addfunctionmenu = QToolButton()
        self.addfunctionmenu.setIcon(QIcon(path("icons/addfunction.png")))
        self.addfunctionmenu.setText("Add Function")
        # Defer menu population to once the plugins have been loaded; otherwise, the menu may not contain anything
        # if this widget is init'd before all plugins have been loaded.
        self.functionmenu = QMenu()
        self.functionmenu.aboutToShow.connect(self.populateFunctionMenu)
        self.addfunctionmenu.setMenu(self.functionmenu)
        self.addfunctionmenu.setPopupMode(QToolButton.InstantPopup)
        self.toolbar.addWidget(self.addfunctionmenu)
        # self.toolbar.addAction(QIcon(path('icons/up.png')), 'Move Up')
        # self.toolbar.addAction(QIcon(path('icons/down.png')), 'Move Down')
        self.toolbar.addAction(QIcon(path("icons/folder.png")),
                               "Load Workflow")
        self.toolbar.addAction(QIcon(path("icons/trash.png")),
                               "Delete Operation", self.deleteOperation)

        v = QVBoxLayout()
        v.addWidget(self.view)
        h = QHBoxLayout()
        h.addWidget(self.autorun_checkbox)
        h.addWidget(self.run_button)
        v.addLayout(h)
        v.addWidget(self.toolbar)
        v.setContentsMargins(0, 0, 0, 0)
        self.setLayout(v)

    def _autorun_state_changed(self, state):
        if state == Qt.Checked:
            self.run_button.setDisabled(True)
        else:
            self.run_button.setDisabled(False)

    def _run_workflow(self, _):
        self._workflow

    def populateFunctionMenu(self):
        self.functionmenu.clear()
        sortingDict = {}
        for plugin in pluginmanager.get_plugins_of_type("OperationPlugin"):
            typeOfOperationPlugin = plugin.categories
            # TODO : should OperationPlugin be responsible for initializing categories
            # to some placeholder value (instead of [])?
            if typeOfOperationPlugin == []:
                typeOfOperationPlugin = "uncategorized"  # put found operations into a default category
            if not typeOfOperationPlugin in sortingDict.keys():
                sortingDict[typeOfOperationPlugin] = []
            sortingDict[typeOfOperationPlugin].append(plugin)
        for key in sortingDict.keys():
            self.functionmenu.addSeparator()
            self.functionmenu.addAction(key)
            self.functionmenu.addSeparator()
            for plugin in sortingDict[key]:
                self.functionmenu.addAction(
                    plugin.name,
                    partial(self.addOperation, plugin, autoconnectall=True))

    def addOperation(self, operation: OperationPlugin, autoconnectall=True):
        self.view.model().workflow.add_operation(operation())
        if autoconnectall:
            self.view.model().workflow.auto_connect_all()
        print("selected new row:", self.view.model().rowCount() - 1)
        self.view.setCurrentIndex(self.view.model().index(
            self.view.model().rowCount() - 1, 0))

    def deleteOperation(self):
        for index in self.view.selectedIndexes():
            operation = self.view.model().workflow.operations[index.row()]
            self.view.model().workflow.remove_operation(operation)
コード例 #14
0
class ViewerWindow(QMainWindow, Ui_ViewerWindow):
    def __init__(self, app_manager, images_list, *args, **kwargs):
        super(ViewerWindow, self).__init__(*args, **kwargs)
        self.setupUi(self)

        # Init self
        self.app = app_manager
        self.settings = self.app.settings.get_viewer_settings()
        self.images_list = images_list

        self.window_moving = False
        self.win_old_pos = None
        self.lbl_old_pos = None

        self.image = next(self.images_list)
        self.viewer_policy = {"scale": 'fit_auto'}

        # Init UI
        self.actions = WindowActions(self.app)
        self.toolbar = QToolBar('toolbar')
        self.init_ui()

        # Init events
        self.label.mouseDoubleClickEvent = self.label_double_click_event
        self.label.mousePressEvent = self.label_mouse_press_event
        self.label.mouseMoveEvent = self.label_mouse_move_event

    def init_ui(self):
        # Setup: window
        self.setWindowTitle(self.app.app_name)
        self.setWindowIcon(self.app.ui.window_icon)
        self.centralwidget.layout().setContentsMargins(0, 0, 0, 0)
        self.statusbar.setVisible(self.settings[V_SHOW_STATUS_BAR])

        # Setup: actions
        self.actions.previous.triggered.connect(self.previous_action)
        self.actions.next.triggered.connect(self.next_action)
        self.actions.fit_to_window.triggered.connect(self.fit_to_window)
        self.actions.fit_to_width.triggered.connect(self.fit_to_width)
        self.actions.fit_to_height.triggered.connect(self.fit_to_height)
        self.actions.show_original_size.triggered.connect(self.original_size)
        self.actions.zoom_in.triggered.connect(self.zoom_in_action)
        self.actions.zoom_out.triggered.connect(self.zoom_out_action)
        self.actions.rotate_right.triggered.connect(self.rotate_right_action)
        self.actions.rotate_left.triggered.connect(self.rotate_left_action)
        self.actions.flip_vertically.triggered.connect(self.flip_vertically_action)
        self.actions.flip_horizontally.triggered.connect(self.flip_horizontally_action)
        self.actions.reload.triggered.connect(self.reload_action)
        self.actions.show_statusbar.triggered.connect(self.show_statusbar_action)
        self.actions.slideshow.triggered.connect(self.slideshow_action)
        self.actions.settings.triggered.connect(self.settings_action)
        self.actions.minimize.triggered.connect(self.minimize_action)
        self.actions.maximize.triggered.connect(self.maximize_action)
        self.actions.about.triggered.connect(self.about_action)
        self.actions.exit.triggered.connect(self.exit_action)

        # Setup: context menu
        self.label.addAction(self.actions.previous)
        self.label.addAction(self.actions.next)
        self.label.addAction(self.actions.fit_to_window)
        self.label.addAction(self.actions.fit_to_width)
        self.label.addAction(self.actions.fit_to_height)
        self.label.addAction(self.actions.show_original_size)
        self.label.addAction(self.actions.zoom_in)
        self.label.addAction(self.actions.zoom_out)
        self.label.addAction(self.actions.rotate_right)
        self.label.addAction(self.actions.rotate_left)
        self.label.addAction(self.actions.flip_vertically)
        self.label.addAction(self.actions.flip_horizontally)
        self.label.addAction(self.actions.reload)
        self.label.addAction(self.actions.show_statusbar)
        self.label.addAction(self.actions.slideshow)
        self.label.addAction(self.actions.settings)
        self.label.addAction(self.actions.about)
        self.label.addAction(self.actions.exit)

        # Setup: toolbar
        self.toolbar.setMovable(False)
        self.toolbar.setContextMenuPolicy(Qt.NoContextMenu)
        self.setContextMenuPolicy(Qt.NoContextMenu)
        self.addToolBar(self.toolbar)
        self.toolbar.addAction(self.actions.previous)
        self.toolbar.addAction(self.actions.next)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.actions.fit_to_window)
        self.toolbar.addAction(self.actions.fit_to_width)
        self.toolbar.addAction(self.actions.fit_to_height)
        self.toolbar.addAction(self.actions.show_original_size)
        self.toolbar.addAction(self.actions.zoom_in)
        self.toolbar.addAction(self.actions.zoom_out)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.actions.rotate_right)
        self.toolbar.addAction(self.actions.rotate_left)
        self.toolbar.addAction(self.actions.flip_vertically)
        self.toolbar.addAction(self.actions.flip_horizontally)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.actions.reload)
        self.toolbar.addWidget(self.actions.separator)
        self.toolbar.addAction(self.actions.show_statusbar)
        self.toolbar.addAction(self.actions.slideshow)

        # Setup Compact theme
        if self.app.ui.app_theme == 'Compact':
            self.setWindowFlags(Qt.FramelessWindowHint)
            self.toolbar.addAction(self.actions.minimize)
            self.toolbar.addAction(self.actions.maximize)
            self.toolbar.addAction(self.actions.exit)

        # Restore last window state
        self._restore_geometry()

    def repaint_image(self):
        width = self.centralWidget().width() - 2
        height = self.centralWidget().height() - 2
        pixmap = self.image.pixmap(self.viewer_policy, width, height)
        self.label.setPixmap(pixmap)

    # Actions
    def previous_action(self):
        self.image = self.images_list.__prev__()
        self.repaint_image()

    def next_action(self):
        self.image = self.images_list.__next__()
        self.repaint_image()

    def zoom_in_action(self):
        self.image.zoom_in()
        self.repaint_image()
        self._center_label()

    def zoom_out_action(self):
        self.image.zoom_out()
        self.repaint_image()
        self._center_label()

    def rotate_right_action(self):
        self.image.rotate_right()
        self.repaint_image()

    def rotate_left_action(self):
        self.image.rotate_left()
        self.repaint_image()

    def flip_vertically_action(self):
        self.image.flip_vertically()
        self.repaint_image()

    def flip_horizontally_action(self):
        self.image.flip_horizontally()
        self.repaint_image()

    def fit_to_window(self):
        if self.actions.fit_to_window.isChecked():
            self.viewer_policy["scale"] = 'fit_to_window'
        else:
            self.viewer_policy["scale"] = 'fit_auto'

        self.actions.fit_to_width.setChecked(False)
        self.actions.fit_to_height.setChecked(False)
        self.actions.show_original_size.setChecked(False)

        self.repaint_image()

    def fit_to_width(self):
        if self.actions.fit_to_width.isChecked():
            self.viewer_policy["scale"] = 'fit_to_width'
        else:
            self.viewer_policy["scale"] = 'fit_auto'

        self.actions.fit_to_window.setChecked(False)
        self.actions.fit_to_height.setChecked(False)
        self.actions.show_original_size.setChecked(False)

        self.repaint_image()

    def fit_to_height(self):
        if self.actions.fit_to_height.isChecked():
            self.viewer_policy["scale"] = 'fit_to_height'
        else:
            self.viewer_policy["scale"] = 'fit_auto'

        self.actions.fit_to_window.setChecked(False)
        self.actions.fit_to_width.setChecked(False)
        self.actions.show_original_size.setChecked(False)

        self.repaint_image()

    def original_size(self):
        if self.actions.show_original_size.isChecked():
            self.viewer_policy["scale"] = 'original_size'
        else:
            self.viewer_policy["scale"] = 'fit_auto'

        self.actions.fit_to_window.setChecked(False)
        self.actions.fit_to_width.setChecked(False)
        self.actions.fit_to_height.setChecked(False)

        self.repaint_image()

    def reload_action(self):
        self.image.reload()
        self.repaint_image()

    def show_statusbar_action(self):
        if self.statusbar.isHidden():
            self.statusbar.show()
        else:
            self.statusbar.hide()
        self.repaint_image()

    def slideshow_action(self):
        if self.isFullScreen():
            self._show_normal()
        else:
            self._show_fullscreen()

    def minimize_action(self):
        self.showMinimized()

    def maximize_action(self):
        if self.isMaximized():
            self._show_normal()
        else:
            self._show_maximized()

    def settings_action(self):
        dialog = SettingsDialog(self.app)
        dialog.exec_()

    def about_action(self):
        dialog = AboutDialog(self.app)
        dialog.exec_()

    def exit_action(self):
        if self.isFullScreen():
            self._show_normal()
        else:
            self._save_geometry()
            self.close()
            self.app.quit()

    # Events

    def resizeEvent(self, event):
        self.repaint_image()

    def label_double_click_event(self, _):
        self._reset_viewer()

    def label_mouse_press_event(self, event):
        if event.button() == Qt.LeftButton:
            self.lbl_old_pos = event.pos()

    def label_mouse_move_event(self, event):
        if event.buttons() == Qt.LeftButton:
            offset = self.lbl_old_pos - event.pos()
            self.lbl_old_pos = event.pos()
            self.scrollArea.verticalScrollBar().setValue(self.scrollArea.verticalScrollBar().value() + offset.y())
            self.scrollArea.horizontalScrollBar().setValue(self.scrollArea.horizontalScrollBar().value() + offset.x())

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.maximize_action()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.win_old_pos = event.globalPos()
            self.window_moving = True

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.setWindowOpacity(1)
            self.window_moving = False

    def mouseMoveEvent(self, event):
        if self.window_moving and not self.isMaximized() and not self.isFullScreen():
            delta = QPoint(event.globalPos() - self.win_old_pos)
            self.move(self.x() + delta.x(), self.y() + delta.y())
            self.win_old_pos = event.globalPos()
            self.setWindowOpacity(0.5)

    # Helpers

    def _show_message(self, msg):
        self.statusBar().showMessage(msg)

    def _show_normal(self):
        self.showNormal()
        self.actions.maximize.setIcon(self.app.ui.maximize_icon)
        self.actions.minimize.setVisible(True)
        self.actions.maximize.setVisible(True)

    def _show_maximized(self):
        self.showMaximized()
        self.actions.maximize.setIcon(self.app.ui.restore_icon)

    def _show_fullscreen(self):
        self.showFullScreen()
        self.actions.minimize.setVisible(False)
        self.actions.maximize.setVisible(False)

    def _save_geometry(self):
        geometry = self.saveGeometry()
        self.app.settings.set(VIEWER_WINDOW_GEOMETRY, geometry)

    def _restore_geometry(self):
        if self.settings[V_SAVE_WINDOW_GEOMETRY]:
            try:
                self.restoreGeometry(self.settings[VIEWER_WINDOW_GEOMETRY])
                if self.isMaximized():
                    self._show_maximized()
                else:
                    self._show_normal()
            except Exception:
                self._center_window()
        else:
            self._center_window()

        self.win_old_pos = self.pos()

    def _center_window(self):
        self.setFixedSize(self.app.ui.best_window_width, self.app.ui.best_window_height)
        frame_geometry = self.frameGeometry()
        frame_geometry.moveCenter(self.app.ui.screen_center)
        self.move(frame_geometry.topLeft())

    def _center_label(self):
        h_max = self.scrollArea.horizontalScrollBar().maximum()
        v_max = self.scrollArea.verticalScrollBar().maximum()
        self.scrollArea.horizontalScrollBar().setValue(h_max / 2)
        self.scrollArea.verticalScrollBar().setValue(v_max / 2)

    def _reset_viewer(self):
        self.viewer_policy["scale"] = 'fit_auto'
        self.image.reload()

        self.actions.fit_to_window.setChecked(False)
        self.actions.fit_to_width.setChecked(False)
        self.actions.fit_to_height.setChecked(False)
        self.actions.show_original_size.setChecked(False)

        self.repaint_image()
コード例 #15
0
class WorkflowWidget(QWidget):
    sigAddFunction = Signal(object)
    sigRunWorkflow = Signal()

    # TODO -- emit Workflow from sigRunWorkflow

    def __init__(self,
                 workflowview: QAbstractItemView,
                 operation_filter: Callable[[OperationPlugin], bool] = None):
        super(WorkflowWidget, self).__init__()

        self.operation_filter = operation_filter
        self.view = workflowview

        self.autorun_checkbox = QCheckBox("Run Automatically")
        self.autorun_checkbox.setCheckState(Qt.Unchecked)
        self.autorun_checkbox.stateChanged.connect(self._autorun_state_changed)
        self.run_button = QPushButton("Run Workflow")
        self.run_button.clicked.connect(self.sigRunWorkflow.emit)
        self.view.model().workflow.attach(self._autorun)
        # TODO -- actually hook up the auto run OR dependent class needs to connect (see SAXSGUIPlugin)

        self.toolbar = QToolBar()
        self.addfunctionmenu = QToolButton()
        self.addfunctionmenu.setIcon(QIcon(path("icons/addfunction.png")))
        self.addfunctionmenu.setText("Add Function")
        # Defer menu population to once the plugins have been loaded; otherwise, the menu may not contain anything
        # if this widget is init'd before all plugins have been loaded.
        self.functionmenu = QMenu()
        self.functionmenu.aboutToShow.connect(self.populateFunctionMenu)
        self.addfunctionmenu.setMenu(self.functionmenu)
        self.addfunctionmenu.setPopupMode(QToolButton.InstantPopup)
        self.toolbar.addWidget(self.addfunctionmenu)
        # self.toolbar.addAction(QIcon(path('icons/up.png')), 'Move Up')
        # self.toolbar.addAction(QIcon(path('icons/down.png')), 'Move Down')
        self.toolbar.addAction(QIcon(path("icons/folder.png")),
                               "Load Workflow")
        self.toolbar.addAction(QIcon(path("icons/trash.png")),
                               "Delete Operation", self.deleteOperation)

        v = QVBoxLayout()
        v.addWidget(self.view)
        h = QHBoxLayout()
        h.addWidget(self.autorun_checkbox)
        h.addWidget(self.run_button)
        v.addLayout(h)
        v.addWidget(self.toolbar)
        v.setContentsMargins(0, 0, 0, 0)
        self.setLayout(v)

    def _autorun_state_changed(self, state):
        if state == Qt.Checked:
            self.run_button.setDisabled(True)
        else:
            self.run_button.setDisabled(False)

    def _autorun(self):
        if self.autorun_checkbox.isChecked():
            self.sigRunWorkflow.emit()

    def populateFunctionMenu(self):
        self.functionmenu.clear()
        sortingDict = MenuDict()
        operations = pluginmanager.get_plugins_of_type("OperationPlugin")
        if self.operation_filter is not None:
            operations = filter(self.operation_filter, operations)
        for operation in operations:

            categories = operation.categories
            if not categories:
                categories = [("Uncategorized", )
                              ]  # put found operations into a default category

            for categories_tuple in categories:
                if isinstance(categories_tuple, str):
                    categories_tuple = (categories_tuple, )
                submenu = sortingDict
                categories_list = list(categories_tuple)
                while categories_list:
                    category = categories_list.pop(0)
                    submenu = submenu[category]

                submenu['___'].append(operation)

        self._mkMenu(sortingDict)

    def _mkMenu(self, sorting_dict, menu=None):
        if menu is None:
            menu = self.functionmenu
            menu.clear()

        for key in sorting_dict:
            if key == '___':
                menu.addSeparator()
                for operation in sorting_dict['___']:
                    menu.addAction(
                        operation.name,
                        partial(self.addOperation,
                                operation,
                                autoconnectall=True))
            else:
                submenu = QMenu(title=key, parent=menu)
                menu.addMenu(submenu)
                self._mkMenu(sorting_dict[key], submenu)

    def addOperation(self, operation: OperationPlugin, autoconnectall=True):
        self.view.model().workflow.add_operation(operation())
        if autoconnectall:
            self.view.model().workflow.auto_connect_all()
        print("selected new row:", self.view.model().rowCount() - 1)
        self.view.setCurrentIndex(self.view.model().index(
            self.view.model().rowCount() - 1, 0))

    def deleteOperation(self):
        index = self.view.currentIndex()
        operation = self.view.model().workflow.operations[index.row()]
        self.view.model().workflow.remove_operation(operation)
        self.view.setCurrentIndex(QModelIndex())