示例#1
0
 def init_toolbar(self):
     # Init ToolBar
     toolbar = QToolBar("My main toolbar")
     self.addToolBar(toolbar)
     toolbar.setContextMenuPolicy(
         Qt.PreventContextMenu)  # prevent users from hiding toolbar
     toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
     """Actions"""
     # terminate App
     action_exit_app = self.actionExit
     action_exit_app.triggered.connect(qApp.quit)
     # Open Single Dcm
     action_openOneImg = self.actionOpen_Single_Image
     action_openOneImg.triggered.connect(self.open_one_dcm)
     # Scan folder for dcm
     action_openSeries = self.actionOpen_Series_Folder
     action_openSeries.triggered.connect(self.openDirUpdateView)
     # Parse DICOMDIR
     action_ParseDcmDir = self.actionParse_DICOMDIR
     action_ParseDcmDir.triggered.connect(self.parseDICOMDIR)
     """" Set Keyboard Short Cut for actions"""
     action_openOneImg.setShortcut(QKeySequence.Open)
     """Link actions to ToolBar as Buttons"""
     toolbar.addAction(action_openOneImg)
     toolbar.addAction(action_openSeries)
     toolbar.addAction(action_ParseDcmDir)
     """"Set ToolBar Buttons Icon"""
     action_openOneImg.setIcon(QApplication.style().standardIcon(
         QStyle.SP_ComputerIcon))
     action_openSeries.setIcon(QApplication.style().standardIcon(
         QStyle.SP_DialogOpenButton))
     action_ParseDcmDir.setIcon(QApplication.style().standardIcon(
         QStyle.SP_DriveCDIcon))
示例#2
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.mTile = None
        self.mMapDocument = None
        self.mMapScene = MapScene(self)
        self.mMapView = MapView(self, MapViewMode.NoStaticContents)
        self.mToolManager = ToolManager(self)
        self.mApplyingChanges = False
        self.mSynchronizing = False

        self.setObjectName("TileCollisionEditor")
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setSpacing(0)
        layout.setContentsMargins(5, 5, 5, 5)
        self.mMapView.setScene(self.mMapScene)
        self.mMapView.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.mMapView.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        rectangleObjectsTool = CreateRectangleObjectTool(self)
        ellipseObjectsTool = CreateEllipseObjectTool(self)
        polygonObjectsTool = CreatePolygonObjectTool(self)
        polylineObjectsTool = CreatePolylineObjectTool(self)
        toolBar = QToolBar(self)
        toolBar.setMovable(False)
        toolBar.setFloatable(False)
        toolBar.setContextMenuPolicy(Qt.ActionsContextMenu)
        self.mToolManager = ToolManager(self)
        toolBar.addAction(
            self.mToolManager.registerTool(ObjectSelectionTool(self)))
        toolBar.addAction(self.mToolManager.registerTool(
            EditPolygonTool(self)))
        toolBar.addAction(self.mToolManager.registerTool(rectangleObjectsTool))
        toolBar.addAction(self.mToolManager.registerTool(ellipseObjectsTool))
        toolBar.addAction(self.mToolManager.registerTool(polygonObjectsTool))
        toolBar.addAction(self.mToolManager.registerTool(polylineObjectsTool))
        self.setCentralWidget(self.mMapView)
        self.addToolBar(toolBar)
        self.mMapScene.setSelectedTool(self.mToolManager.selectedTool())
        self.mToolManager.selectedToolChanged.connect(self.setSelectedTool)
        zoomComboBox = QComboBox()
        self.statusBar().addPermanentWidget(zoomComboBox)
        zoomable = self.mMapView.zoomable()
        zoomable.connectToComboBox(zoomComboBox)
        undoShortcut = QShortcut(QKeySequence.Undo, self)
        redoShortcut = QShortcut(QKeySequence.Redo, self)
        cutShortcut = QShortcut(QKeySequence.Cut, self)
        copyShortcut = QShortcut(QKeySequence.Copy, self)
        pasteShortcut = QShortcut(QKeySequence.Paste, self)
        deleteShortcut = QShortcut(QKeySequence.Delete, self)
        deleteShortcut2 = QShortcut(QKeySequence.Back, self)
        undoShortcut.activated.connect(self.undo)
        redoShortcut.activated.connect(self.redo)
        cutShortcut.activated.connect(self.cut)
        copyShortcut.activated.connect(self.copy)
        pasteShortcut.activated.connect(self.paste)
        deleteShortcut.activated.connect(self.delete_)
        deleteShortcut2.activated.connect(self.delete_)
        self.retranslateUi()
        self.resize(300, 300)
        Utils.restoreGeometry(self)
    def __init__(self, parent = None):
        super().__init__(parent)
        self.mTile = None
        self.mMapDocument = None
        self.mMapScene = MapScene(self)
        self.mMapView = MapView(self, MapViewMode.NoStaticContents)
        self.mToolManager = ToolManager(self)
        self.mApplyingChanges = False
        self.mSynchronizing = False

        self.setObjectName("TileCollisionEditor")
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setSpacing(0)
        layout.setContentsMargins(5, 5, 5, 5)
        self.mMapView.setScene(self.mMapScene)
        self.mMapView.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.mMapView.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        rectangleObjectsTool = CreateRectangleObjectTool(self)
        ellipseObjectsTool = CreateEllipseObjectTool(self)
        polygonObjectsTool = CreatePolygonObjectTool(self)
        polylineObjectsTool = CreatePolylineObjectTool(self)
        toolBar = QToolBar(self)
        toolBar.setMovable(False)
        toolBar.setFloatable(False)
        toolBar.setContextMenuPolicy(Qt.ActionsContextMenu)
        self.mToolManager = ToolManager(self)
        toolBar.addAction(self.mToolManager.registerTool(ObjectSelectionTool(self)))
        toolBar.addAction(self.mToolManager.registerTool(EditPolygonTool(self)))
        toolBar.addAction(self.mToolManager.registerTool(rectangleObjectsTool))
        toolBar.addAction(self.mToolManager.registerTool(ellipseObjectsTool))
        toolBar.addAction(self.mToolManager.registerTool(polygonObjectsTool))
        toolBar.addAction(self.mToolManager.registerTool(polylineObjectsTool))
        self.setCentralWidget(self.mMapView)
        self.addToolBar(toolBar)
        self.mMapScene.setSelectedTool(self.mToolManager.selectedTool())
        self.mToolManager.selectedToolChanged.connect(self.setSelectedTool)
        zoomComboBox = QComboBox()
        self.statusBar().addPermanentWidget(zoomComboBox)
        zoomable = self.mMapView.zoomable()
        zoomable.connectToComboBox(zoomComboBox)
        undoShortcut = QShortcut(QKeySequence.Undo, self)
        redoShortcut = QShortcut(QKeySequence.Redo, self)
        cutShortcut = QShortcut(QKeySequence.Cut, self)
        copyShortcut = QShortcut(QKeySequence.Copy, self)
        pasteShortcut = QShortcut(QKeySequence.Paste, self)
        deleteShortcut = QShortcut(QKeySequence.Delete, self)
        deleteShortcut2 = QShortcut(QKeySequence.Back, self)
        undoShortcut.activated.connect(self.undo)
        redoShortcut.activated.connect(self.redo)
        cutShortcut.activated.connect(self.cut)
        copyShortcut.activated.connect(self.copy)
        pasteShortcut.activated.connect(self.paste)
        deleteShortcut.activated.connect(self.delete_)
        deleteShortcut2.activated.connect(self.delete_)
        self.retranslateUi()
        self.resize(300, 300)
        Utils.restoreGeometry(self)
示例#4
0
class SessionManager(QMainWindow):
    def __init__(self, parent=None):
        QListWidget.__init__(self, parent)
        self.setWindowTitle(tr("Saved Sessions"))
        self.setWindowFlags(Qt.Dialog)
        hideAction = QAction(self)
        hideAction.setShortcuts(["Esc", "Ctrl+W"])
        hideAction.triggered.connect(self.hide)
        self.addAction(hideAction)
        self.sessionList = QListWidget(self)
        self.sessionList.itemActivated.connect(self.loadSession)
        self.setCentralWidget(self.sessionList)
        self.toolBar = QToolBar(self)
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.addToolBar(Qt.BottomToolBarArea, self.toolBar)
        self.loadButton = QPushButton(tr("&Load"), self)
        self.loadButton.clicked.connect(
            lambda: self.loadSession(self.sessionList.currentItem()))
        self.toolBar.addWidget(self.loadButton)
        self.saveButton = QPushButton(tr("&Save"), self)
        self.saveButton.clicked.connect(saveSessionManually)
        self.saveButton.clicked.connect(self.refresh)
        self.toolBar.addWidget(self.saveButton)
        deleteAction = QAction(self)
        deleteAction.setShortcut("Del")
        deleteAction.triggered.connect(self.delete)
        self.addAction(deleteAction)

    def refresh(self):
        self.sessionList.clear()
        if os.path.exists(settings.session_folder):
            sessions = os.listdir(settings.session_folder)
            for session in sessions:
                self.sessionList.addItem(session)

    def delete(self):
        if self.sessionList.hasFocus():
            try:
                os.remove(
                    os.path.join(settings.session_folder,
                                 self.sessionList.currentItem().text()))
            except:
                pass
            self.refresh()

    def show(self):
        self.refresh()
        QMainWindow.show(self)

    def loadSession(self, item):
        if os.path.exists(settings.session_folder):
            loadSession(os.path.join(settings.session_folder, item.text()))
        self.hide()
示例#5
0
class SessionManager(QMainWindow):
    def __init__(self, parent=None):
        QListWidget.__init__(self, parent)
        self.setWindowTitle(tr("Saved Sessions"))
        self.setWindowFlags(Qt.Dialog)
        hideAction = QAction(self)
        hideAction.setShortcuts(["Esc", "Ctrl+W"])
        hideAction.triggered.connect(self.hide)
        self.addAction(hideAction)
        self.sessionList = QListWidget(self)
        self.sessionList.itemActivated.connect(self.loadSession)
        self.setCentralWidget(self.sessionList)
        self.toolBar = QToolBar(self)
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.addToolBar(Qt.BottomToolBarArea, self.toolBar)
        self.loadButton = QPushButton(tr("&Load"), self)
        self.loadButton.clicked.connect(lambda: self.loadSession(self.sessionList.currentItem()))
        self.toolBar.addWidget(self.loadButton)
        self.saveButton = QPushButton(tr("&Save"), self)
        self.saveButton.clicked.connect(saveSessionManually)
        self.saveButton.clicked.connect(self.refresh)
        self.toolBar.addWidget(self.saveButton)
        deleteAction = QAction(self)
        deleteAction.setShortcut("Del")
        deleteAction.triggered.connect(self.delete)
        self.addAction(deleteAction)
    def refresh(self):
        self.sessionList.clear()
        if os.path.exists(settings.session_folder):
            sessions = os.listdir(settings.session_folder)
            for session in sessions:
                self.sessionList.addItem(session)
    def delete(self):
        if self.sessionList.hasFocus():
            try: os.remove(os.path.join(settings.session_folder, self.sessionList.currentItem().text()))
            except: pass
            self.refresh()
    def show(self):
        self.refresh()
        QMainWindow.show(self)
    def loadSession(self, item):
        if os.path.exists(settings.session_folder):
            loadSession(os.path.join(settings.session_folder, item.text()))
        self.hide()
示例#6
0
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.setWindowTitle("My Awesome App")

        label = QLabel("This is a PyQt5 window!")
        label.setAlignment(Qt.AlignCenter)
        self.setCentralWidget(label)

        toolbar = QToolBar("My main toolbar")
        toolbar.setIconSize(QSize(16, 16))
        self.addToolBar(toolbar)
        path_to_icon1 = 'fugue-icons-3/icons/bug.png'
        button_action = QAction(QIcon(path_to_icon1), "Your button", self)
        button_action.setStatusTip("This is Bug Button")
        button_action.triggered.connect(self.onMyToolBarButtonClick)
        button_action.setCheckable(True)
        toolbar.addAction(button_action)
        toolbar.setContextMenuPolicy(
            Qt.PreventContextMenu
        )  #Stop from toolbar disapearing from a right clicking it

        toolbar.addSeparator()

        path_to_icon2 = 'fugue-icons-3/icons/beer.png'
        button_action2 = QAction(QIcon(path_to_icon2), "Your button2", self)
        button_action2.setStatusTip("This is Beer Button")
        button_action2.triggered.connect(self.onMyToolBarButtonClick)
        button_action2.setCheckable(True)
        toolbar.addAction(button_action2)

        toolbar.addWidget(QLabel("Hello"))
        box = QCheckBox()
        box.stateChanged.connect(self.clickBox)
        toolbar.addWidget(box)

        path_to_icon3 = 'fugue-icons-3/icons/prohibition.png'
        action4 = QAction(QIcon(path_to_icon3), "Quit", self)
        action4.triggered.connect(app.quit)
        toolbar.addAction(action4)

        self.setStatusBar(QStatusBar(self))
示例#7
0
class MainWindow(QMainWindow):
    """
    Main UI window

    Class creates window elements, fills main menu with items.

    If you need to access to some existing menu items - check action path
    in the class constructor, than use next code: ::

        core.actionManager().action("mFile/aOpen").setEnabled(True)
        core.actionManager().action("mFile/aOpen").triggered.connect(self.myCoolMethod)

    MainWindow instance is accessible as: ::

        from enki.core.core import core
        core.mainwindow()

    Created by the core
    """

    hideAllWindows = pyqtSignal()
    """
    hideAllWindows()

    **Signal** emitted, when user toggled "Hide all" .
    Dock widgets are closed automatically, but other widgets, i.e. search widget, must catch this signal and close
    themselves.
    """  # pylint: disable=W0105

    directoryDropt = pyqtSignal(str)
    """
    directoryDropt()

    **Signal** emitted, when user drag-n-dropt directory to main windowd.
    FileBrowser shows directory
    """  # pylint: disable=W0105

    _STATE_FILE = os.path.join(enki.core.defines.CONFIG_DIR, "main_window_state.bin")
    _GEOMETRY_FILE = os.path.join(enki.core.defines.CONFIG_DIR, "main_window_geometry.bin")

    def __init__(self):
        QMainWindow.__init__(self)

        self._queuedMessageToolBar = None
        self._createdMenuPathes = []
        self._createdActions = []

        self._addedDockWidgets = []

        if hasattr(self, 'setUnifiedTitleAndToolBarOnMac'):  # missing on some PyQt5 versions
            self.setUnifiedTitleAndToolBarOnMac(True)
        self.setIconSize(QSize(16, 16))
        self.setAcceptDrops(True)

        # Set corner settings for dock widgets
        self.setCorner(Qt.TopLeftCorner, Qt.LeftDockWidgetArea)
        self.setCorner(Qt.TopRightCorner, Qt.RightDockWidgetArea)
        self.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea)
        self.setCorner(Qt.BottomRightCorner, Qt.RightDockWidgetArea)

        self.setWindowTitle(self.defaultTitle())  # overwriten by workspace when file or it's modified state changes
        self.setWindowIcon(QIcon(':/enkiicons/logo/enki.svg'))

        # Create top tool bar
        self._topToolBar = QToolBar("topToolBar")
        self._topToolBar.setObjectName("topToolBar")
        self._topToolBar.setMovable(False)
        self._topToolBar.setIconSize(QSize(16, 16))
        self._topToolBar.setContextMenuPolicy(Qt.PreventContextMenu)  # to avoid possibility to hide the toolbar

        # Create menu bar
        self._menuBar = ActionMenuBar(self, core.actionManager())
        self._initMenubarAndStatusBarLayout()

        # create central layout
        widget = QWidget(self)
        self._centralLayout = QVBoxLayout(widget)
        self._centralLayout.setContentsMargins(0, 0, 0, 0)
        self.setCentralWidget(widget)
        self.setStyleSheet('QMainWindow::separator{width: 4px}')

    def _initActions(self):
        """ Public method for actionManager. """

        self._createMenuStructure()
        core.actionManager().action('mView/aOpenMainMenu').triggered.connect(self._openMainMenu)
        core.actionManager().action('mFile/aQuit').triggered.connect(self.onQuit)

    def terminate(self):
        """Explicitly called destructor
        """
        if self._queuedMessageToolBar:
            self.removeToolBar(self._queuedMessageToolBar)
            del self._queuedMessageToolBar

        for act in self._createdActions:
            core.actionManager().removeAction(act)
        for menuPath in self._createdMenuPathes[::-1]:
            core.actionManager().removeMenu(menuPath)

    @staticmethod
    def _isMenuEmbeddedToTaskBar():
        """On Unity (Ubuntu) and MacOS menu bar is embedded to task bar
        """
        return 'UBUNTU_MENUPROXY' in os.environ or \
               os.environ.get('XDG_CURRENT_DESKTOP') == 'Unity' or \
               'darwin' == sys.platform

    def _initMenubarAndStatusBarLayout(self):
        """Create top widget and put it on its place
        """
        if not 'darwin' == sys.platform:
            # on Ubuntu toolbar, docs and editor area look as one widget. Ugly
            # Therefore it is separated with line. On Mac seems OK
            # I can't predict, how it will look on other platforms, therefore line is used for all, except Mac
            toolBarStyleSheet = "QToolBar {border: 0; border-bottom-width: 1; border-bottom-style: solid}"""
            self._topToolBar.setStyleSheet(toolBarStyleSheet)

        area = Qt.BottomToolBarArea if self._isMenuEmbeddedToTaskBar() else Qt.TopToolBarArea
        self.addToolBar(area, self._topToolBar)

        if self._isMenuEmbeddedToTaskBar():  # separate menu bar
            self.setMenuBar(self._menuBar)
        else:  # menubar, statusbar and editor tool bar on one line
            self._menuBar.setAutoFillBackground(False)
            menuBarStyleSheet = """
            QMenuBar {background-color: transparent;
                      color: %s}
            QMenuBar::item:!selected {background: transparent;}
            """ % self.palette().color(QPalette.WindowText).name()
            self._menuBar.setStyleSheet(menuBarStyleSheet)
            self._menuBar.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Minimum)

            self._topToolBar.addWidget(self._menuBar)

        # Create status bar
        self._statusBar = _StatusBar(self)
        self._topToolBar.addWidget(self._statusBar)

    def _initQueuedMessageToolBar(self):
        from enki.core.queued_msg_tool_bar import QueuedMessageToolBar

        self._queuedMessageToolBar = QueuedMessageToolBar(self)
        area = Qt.TopToolBarArea if self._isMenuEmbeddedToTaskBar() else Qt.BottomToolBarArea
        self.addToolBar(area, self._queuedMessageToolBar)
        self._queuedMessageToolBar.setVisible(False)

    def _createMenuStructure(self):
        """Fill menu bar with items. The majority of items are not connected to the slots,
        Connections made by module, which implements menu item functionality, but, all items are in one place,
        because it's easier to create clear menu layout
        """
        # create menubar menus and actions

        def menu(path, name, icon, visible=True):
            """Subfunction for create a menu in the main menu"""
            menuObject = core.actionManager().addMenu(path, name)
            if icon:
                menuObject.setIcon(QIcon(':/enkiicons/' + icon))
            self._createdMenuPathes.append(path)
            if not visible:
                menuObject.setVisible(False)

        def action(path, name, icon, shortcut, tooltip, enabled, checkable=False):  # pylint: disable=R0913
            """Subfunction for create an action in the main menu"""
            if icon:  # has icon
                actObject = core.actionManager().addAction(path, name, QIcon(':/enkiicons/' + icon), shortcut)
            else:
                actObject = core.actionManager().addAction(path, name, shortcut=shortcut)
            if tooltip:
                actObject.setStatusTip(tooltip)
            actObject.setEnabled(enabled)
            actObject.setCheckable(checkable)
            self._createdActions.append(actObject)

        def separator(menu):
            """Subfunction for insert separator to the menu"""
            core.actionManager().action(menu).menu().addSeparator()

        # pylint: disable=C0301
        # enable long lines for menu items
        # Menu or action path                          Name                     Icon            Shortcut        Hint                     enabled  checkable
        menu  ("mFile",                               "File"                  , ""           )
        action("mFile/aOpenProject",                  "Open Pro&ject..."      , "open.png",     "Shift+Ctrl+O" ,"Open a project"         , True)
        separator("mFile")
        menu  ("mFile/mUndoClose",                    "Undo Close"            , "recents.png")
        separator("mFile")
        action("mFile/aNew",                          "&New file..."          , "new.png",      'Ctrl+N',       "New file"               , True)
        action("mFile/aOpen",                         "&Open..."              , "open.png",     "Ctrl+O" ,      "Open a file"            , True)
        menu  ("mFile/mSave",                         "&Save"                 , "save.png"   )
        action("mFile/mSave/aCurrent",                "&Save"                 , "save.png" ,    "Ctrl+S" ,      "Save the current file"  , False)
        action("mFile/mSave/aSaveAs",                 "Save As..."            , "save.png" ,    "Ctrl+Alt+S" ,  ""                           , False)
        action("mFile/mSave/aAll",                    "Save &All"             , "saveall.png",  'Shift+Ctrl+S', "Save all files"         , False)
        menu  ("mFile/mReload",                       "&Reload"               , "reload.png"   )
        action("mFile/mReload/aCurrent",              "Reload"                , "reload.png"  , 'F5',           "Reload the current file", False)
        action("mFile/mReload/aAll",                  "Reload All"            , "reload.png"  , 'Shift+F5',     "Reload all files"       , True)
        menu  ("mFile/mClose",                        "&Close"                , "close.png"  )
        action("mFile/mClose/aCurrent",               "&Close"                , "close.png",    "Ctrl+W",       "Close the current file" , False)
        action("mFile/mClose/aAll",                   "Close &All"            , "closeall.png", 'Shift+Ctrl+W', "Close all files"        , False)
        menu  ("mFile/mFileSystem",                   "File System"           , "filesystem.png")
        action("mFile/mFileSystem/aRename",           "Rename"                , "edit.png",     '',             "Rename current file"    , False)
        if platform.system() != 'Windows':
            action("mFile/mFileSystem/aToggleExecutable", "Make executable"   , "",            '',             "Toggle executable mode" , False)
        separator("mFile")
        action("mFile/aQuit",                         "Quit"                  , "quit.png",     'Ctrl+Q',       "Quit"                  , True)
        separator("mFile")

        menu  ("mView",                               "View"                  , ""           )
        action("mView/aShowIncorrectIndentation",      "Show incorrect indentation", "",       "",              ""                       , False, True)
        action("mView/aShowAnyWhitespaces",     "Show any whitespace",        "",              "",              ""                       , False, True)
        separator("mView")
        action("mView/aHideAll",                      "Hide all / Restore"   , "",             "Shift+Esc",   "Hide all widgets"          , True)
        action("mView/aOpenMainMenu",                 "Open main menu"       , "",             "F10",         ""                          , True)
        separator("mView")

        menu  ("mEdit",                               "Edit"                  , ""           )
        action("mEdit/aStripTrailingWhitespace",      "Strip trailing whitespace when saving", "", "",            ""                   , True, True)
        separator("mEdit")
        menu  ("mEdit/mCopyPasteLines",               "Copy-paste lines"      , ""           )
        menu  ("mEdit/mIndentation",                  "Indentation"           , ""           )
        separator("mEdit")
        action("mEdit/aEnableVimMode",                "Enable Vim mode"       , "",             "",             ""                      , False, True)

        menu  ("mNavigation",                          "Navigation"            , ""          )
        action("mNavigation/aFocusCurrentDocument",   "Focus to editor"       , "text.png",     "Ctrl+Return",  "Focus current document" , False)

        menu  ("mNavigation/mSearchReplace",           "&Search && Replace"    , "search-replace-directory.png")
        menu  ("mNavigation/mBookmarks",               "&Bookmarks"            , "bookmark.png")

        separator("mNavigation"),
        action("mNavigation/aNext",                   "&Next file"            , "next.png",     "Ctrl+PgDown",    "Next file"              , False)
        action("mNavigation/aPrevious",               "&Previous file"        , "previous.png", "Ctrl+PgUp",     "Previous file"          , False)
        separator("mNavigation")
        action("mNavigation/aGoto",                   "Go go line..."         , "goto.png",     "Ctrl+G",       "Go to line..."          , False)
        menu  ("mNavigation/mFileBrowser",            "File browser"          , ':/enkiicons/open.png', visible=False)
        menu  ("mNavigation/mScroll",                 "Scroll file"           , '')

        menu  ("mSettings",                           "Settings"              , ""           )

        menu  ("mTools",                              "Tools"                 , ""           )
        menu  ("mHelp",                               "Help"                  , ""           )

    @pyqtSlot()
    def _openMainMenu(self):
        fileMenu = core.actionManager().menu('mFile')
        self._menuBar.setActiveAction(fileMenu.menuAction())

    def menuBar(self):
        """Reference to menuBar
        """
        return self._menuBar

    def topToolBar(self):
        """Top tool bar. Contains main menu, position indicator, etc
        """
        return self._topToolBar

    def statusBar(self):
        """Return main window status bar.
        It is located on the top tool bar
        """
        return self._statusBar

    def setWorkspace(self, workspace):
        """Set central widget of the main window.
        Normally called only by core when initializing system
        """
        self._centralLayout.addWidget(workspace)
        self.setFocusProxy(workspace)

    def defaultTitle(self):
        """Default title. Contains  name and version
        """
        return "%s v.%s" % (enki.core.defines.PACKAGE_NAME, enki.core.defines.PACKAGE_VERSION)

    def centralLayout(self):
        """Layout of the central widget. Contains Workspace and search widget
        """
        return self._centralLayout

    def appendMessage(self, text, timeoutMs=10000):
        """Append message to the queue. It will be shown as non-modal at the bottom of the window.
        Use such notifications, which are too long or too important for status bar
        but, not so important, to interrupt an user with QMessageBox
        """
        if self._queuedMessageToolBar is None:
            self._initQueuedMessageToolBar()

        self._queuedMessageToolBar.appendMessage(text, timeoutMs)

    def closeEvent(self, event):
        """NOT A PUBLIC API
        Close event handler.
        Shows save files dialog. Cancels close, if dialog was rejected
        """

        # saving geometry BEFORE closing widgets, because state might be changed, when docks are closed
        self._saveState()
        self._saveGeometry()

        # request close all documents
        if not core.workspace().askToCloseAll():
            event.ignore()
            return

        core.aboutToTerminate.emit()
        self.hide()

        core.workspace().forceCloseAllDocuments()

        return QMainWindow.closeEvent(self, event)

    def onQuit(self):
        # saving geometry BEFORE closing widgets, because state might be changed, when docks are closed
        self._saveState()
        self._saveGeometry()

        # request close all documents
        if not core.workspace().askToCloseAll():
            return

        core.aboutToTerminate.emit()
        self.hide()

        core.workspace().forceCloseAllDocuments()

        return QApplication.quit()

    def _saveByteArray(self, path, title, data):
        """Load data, show error and return None if failed"""
        try:
            with open(path, 'wb') as f:
                f.write(data)
        except (OSError, IOError) as ex:
            error = str(ex)
            QMessageBox.critical(None,
                                 self.tr("Cannot save {}".format(title)),
                                 self.tr("Cannot create file '%s'\nError: %s" % (path, error)))
            return

    def _loadByteArray(self, path, title):
        """Load data, show error and return None if failed"""
        if os.path.exists(path):
            try:
                with open(path, 'rb') as f:
                    return f.read()
            except (OSError, IOError) as ex:
                error = str(ex)
                QMessageBox.critical(None,
                                     self.tr("Cannot restore {}".format(title)),
                                     self.tr("Cannot read file '%s'\nError: %s" % (path, error)))

        return None

    def _saveState(self):
        """Save window state to main_window_state.bin file in the config directory
        """
        self._saveByteArray(self._STATE_FILE, "main window state", self.saveState())

    def loadState(self):
        """Restore window state from main_window_state.bin and config.
        Called by the core after all plugins had been initialized
        """
        self._restoreGeometry()

        state = self._loadByteArray(self._STATE_FILE, "main window state")

        if state is not None:
            self.restoreState(state)
        else:  # no state, first start
            self.showMaximized()
            for dock in self.findChildren(DockWidget):
                dock.show()

    def _saveGeometry(self):
        """Save window geometry to the config file
        """
        self._saveByteArray(self._GEOMETRY_FILE, "main window geometry", self.saveGeometry())

    def _restoreGeometry(self):
        """Restore window geometry to the config file
        """
        geometry = self._loadByteArray(self._GEOMETRY_FILE, "main window geometry")
        if geometry is not None:
            self.restoreGeometry(geometry)

    def sizeHint(self):
        return QSize(900, 560)

    def dragEnterEvent(self, event):
        """QMainWindow method reimplementation.
        Say, that we are ready to accept dragged urls
        """
        if event.mimeData().hasUrls():
            # accept drag
            event.acceptProposedAction()

        # default handler
        QMainWindow.dragEnterEvent(self, event)

    def dropEvent(self, event):
        """QMainWindow method reimplementation.
        Open dropt files
        """
        if event.mimeData().hasUrls():
            for url in event.mimeData().urls():
                localFile = url.toLocalFile()
                if os.path.isfile(localFile):
                    core.workspace().openFile(localFile)
                elif os.path.isdir(localFile):
                    self.directoryDropt.emit(localFile)

        # default handler
        QMainWindow.dropEvent(self, event)

    def addDockWidget(self, area, dock):
        pass  # not a plugin API method
        """Add dock widget to previous position, if known.
        Otherwise add to specified area
        """
        assert not dock in self._addedDockWidgets
        self._addedDockWidgets.append(dock)

        if not self.restoreDockWidget(dock):
            QMainWindow.addDockWidget(self, area, dock)

        """ Scroll view to make the cursor visible.
        Otherwise cursor can disappear from the viewport.
        QTimer is used because ensureCursorVisible works only after the dock has been drawn.
        A bad fix for #319
        """
        QTimer.singleShot(0, self._ensureCursorVisible)

    def _ensureCursorVisible(self):
        # When the timer fires, first check that there's still a workspace/document.
        if core.workspace() is not None:
            document = core.workspace().currentDocument()
            if document is not None:
                document.qutepart.ensureCursorVisible

    def removeDockWidget(self, dock):
        pass  # not a plugin API method
        """Remove dock widget"""
        assert dock in self._addedDockWidgets
        self._addedDockWidgets.remove(dock)
        QMainWindow.removeDockWidget(self, dock)

    def restoreState(self, state):
        pass  # not a plugin API method
        """Restore state shows widgets, which exist
        but shall not be installed on main window
        """
        QMainWindow.restoreState(self, state)
        for dock in self.findChildren(DockWidget):
            if not dock in self._addedDockWidgets:
                dock.hide()
示例#8
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__()
        self.setWindowTitle("RainbowBB")
        self.setParent(parent)
        self.initUI()

    def initUI(self):
        self.setStyleSheet(
            "QCheckBox { background: palette(window); border-radius: 4px; padding: 2px; margin-right: 2px; }"
        )

        self.toolBar = QToolBar(self)
        self.toolBar.setStyleSheet(stylesheet % (create_gradient("pastel"), ))
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.addToolBar(self.toolBar)

        self.reverseBox = QCheckBox("&Reverse", self)
        self.reverseBox.clicked.connect(lambda: self.updateGradient())
        self.toolBar.addWidget(self.reverseBox)

        self.byWordBox = QCheckBox("By &word", self)
        self.toolBar.addWidget(self.byWordBox)

        self.bounceBox = QCheckBox("&Bounce", self)
        self.bounceBox.clicked.connect(lambda: self.updateGradient())
        self.toolBar.addWidget(self.bounceBox)

        self.sizeList = QComboBox(self)
        self.sizeList.addItem("None")
        for num in range(1, 8):
            self.sizeList.addItem(str(num))
        self.toolBar.addWidget(self.sizeList)

        self.cycleList = QComboBox(self)
        self.toolBar.addWidget(self.cycleList)
        self.cycleList.currentIndexChanged.connect(self.updateGradient)
        self.loadCycles()

        self.convertButton = QPushButton("&Convert", self)
        self.convertButton.clicked.connect(self.convert)
        self.toolBar.addWidget(self.convertButton)

        self.reloadButton = QPushButton("Reload", self)
        self.reloadButton.setShortcut("Alt+Shift+R")
        self.reloadButton.clicked.connect(self.loadCycles)
        self.toolBar.addWidget(self.reloadButton)

        self.inputDock = QDockWidget("Input", self)
        self.inputDock.setFeatures(QDockWidget.NoDockWidgetFeatures)
        self.inputDock.setContextMenuPolicy(Qt.CustomContextMenu)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.inputDock)

        self.inputField = QTextEdit(self)
        self.inputField.setAcceptRichText(False)
        self.inputDock.setWidget(self.inputField)

        self.outputField = QTextEdit(self)
        self.outputField.setReadOnly(True)
        self.setCentralWidget(self.outputField)

    def updateGradient(self, index=None):
        if not index:
            index = self.cycleList.currentIndex()
        self.toolBar.setStyleSheet(stylesheet % (create_gradient(
            self.cycleList.itemText(index), self.reverseBox.isChecked(),
            self.bounceBox.isChecked()), ))

    def loadCycles(self):
        rainbowbb.load_cycles()
        self.cycleList.clear()
        self.cycleList.addItem("pastel")
        for cycle in sorted(list(rainbowbb.cycles.keys())):
            if cycle != "pastel":
                self.cycleList.addItem(cycle)

    def show(self):
        self.setVisible(True)
        self.inputField.setFocus()

    def convert(self):
        self.outputField.setPlainText(
            rainbowbb.size(
                rainbowbb.colorize(self.inputField.toPlainText(),
                                   self.cycleList.currentText(),
                                   self.reverseBox.isChecked(),
                                   not self.byWordBox.isChecked(),
                                   self.bounceBox.isChecked()),
                self.sizeList.currentText()
                if self.sizeList.currentText() != "None" else None))
class ClearHistoryDialog(QMainWindow):
    def __init__(self, parent=None):
        super(ClearHistoryDialog, self).__init__(parent)

        self.setWindowFlags(Qt.Dialog)

        self.setWindowTitle(tr("Clear Data"))

        closeWindowAction = QAction(self)
        closeWindowAction.setShortcuts(["Esc", "Ctrl+W", "Ctrl+Shift+Del"])
        closeWindowAction.triggered.connect(self.close)
        self.addAction(closeWindowAction)

        self.contents = QWidget()
        self.layout = QVBoxLayout()
        self.contents.setLayout(self.layout)
        self.setCentralWidget(self.contents)
        label = QLabel(tr("What to clear:"), self)
        self.layout.addWidget(label)
        self.dataType = QComboBox(self)
        self.dataType.addItem(tr("History"))
        self.dataType.addItem(tr("Cookies"))
        self.dataType.addItem(tr("Cache"))
        self.dataType.addItem(tr("Persistent Storage"))
        self.dataType.addItem(tr("Everything"))
        self.layout.addWidget(self.dataType)
        self.toolBar = QToolBar(self)
        self.toolBar.setStyleSheet(common.blank_toolbar)
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.addToolBar(Qt.BottomToolBarArea, self.toolBar)
        self.clearHistoryButton = QPushButton(tr("Clear"), self)
        self.clearHistoryButton.clicked.connect(self.clearHistory)
        self.toolBar.addWidget(self.clearHistoryButton)
        self.closeButton = QPushButton(tr("Close"), self)
        self.closeButton.clicked.connect(self.close)
        self.toolBar.addWidget(self.closeButton)

    def show(self):
        self.setVisible(True)

    def display(self):
        self.show()
        self.activateWindow()

    def clearHistory(self):
        clear_everything = (self.dataType.currentIndex() == 5)
        if self.dataType.currentIndex() == 0 or clear_everything:
            data.clearHistory()
        if self.dataType.currentIndex() == 1 or clear_everything:
            data.clearCookies()
        if self.dataType.currentIndex() == 2 or clear_everything:
            network.clear_cache()
            path = settings.offline_cache_folder
            if os.path.isdir(path):
                if sys.platform.startswith("win"):
                    try: subprocess.Popen(["rd", path])
                    except: pass
                else:
                    try: subprocess.Popen(["rm", "-rf", path])
                    except: pass
        if self.dataType.currentIndex() == 3 or clear_everything:
            for subpath in ("WebpageIcons.db", "LocalStorage", "Databases",):
                path = os.path.abspath(os.path.join(settings.settings_folder, subpath))
                if os.path.isfile(path):
                    try: os.remove(path)
                    except: pass
                elif os.path.isdir(path):
                    if sys.platform.startswith("win"):
                        try: subprocess.Popen(["rd", path])
                        except: pass
                    else:
                        try: subprocess.Popen(["rm", "-rf", path])
                        except: pass
示例#10
0
class SearchEditor(QMainWindow):
    searchChanged = Signal(str)
    searchManager = SearchManager()
    def __init__(self, parent=None):
        super(SearchEditor, self).__init__(parent)
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Popup)
        self.parent = parent
        self.setWindowTitle(tr('Search Editor'))
        self.styleSheet = "QMainWindow { background: palette(window); border: 1px solid palette(dark); }"
        self.setStyleSheet(self.styleSheet)
        try: self.setWindowIcon(common.app_icon)
        except: pass

        closeWindowAction = QAction(self)
        closeWindowAction.setShortcuts(["Ctrl+W", "Ctrl+Shift+K"])
        closeWindowAction.triggered.connect(self.close)
        self.addAction(closeWindowAction)

        self.entryBar = QToolBar(self)
        self.entryBar.setIconSize(QSize(16, 16))
        self.entryBar.setStyleSheet(common.blank_toolbar)
        self.entryBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.entryBar.setMovable(False)
        self.addToolBar(self.entryBar)

        eLabel = QLabel(" " + tr('New expression:'), self)
        self.entryBar.addWidget(eLabel)
        self.expEntry = custom_widgets.LineEdit(self)
        self.expEntry.returnPressed.connect(self.addSearch)
        self.entryBar.addWidget(self.expEntry)
        self.addSearchButton = QToolButton(self)
        self.addSearchButton.setText(tr("Add"))
        self.addSearchButton.setIcon(common.complete_icon("list-add"))
        self.addSearchButton.clicked.connect(self.addSearch)
        self.entryBar.addWidget(self.addSearchButton)

        self.engineList = QListWidget(self)
        self.engineList.setAlternatingRowColors(True)
        self.engineList.itemClicked.connect(self.applySearch)
        self.engineList.itemActivated.connect(self.applySearch)
        self.engineList.itemActivated.connect(self.close)
        self.setCentralWidget(self.engineList)

        self.takeSearchAction = QAction(self)
        self.takeSearchAction.triggered.connect(self.takeSearch)
        self.takeSearchAction.setShortcut("Del")
        self.addAction(self.takeSearchAction)

        self.hideAction = QAction(self)
        self.hideAction.triggered.connect(self.hide)
        self.hideAction.setShortcut("Esc")
        self.addAction(self.hideAction)

        self.reload_()

    def show(self):
        self.setVisible(True)
        y = QDesktopWidget()
        self.move(max(0, QCursor.pos().x() - self.width()), min(QCursor.pos().y(), y.height() - self.height()))
        y.deleteLater()

    def primeDisplay(self):
        self.reload_()
        self.expEntry.setFocus()

    def focusOutEvent(self, e):
        e.accept()
        self.hide()

    def reload_(self):
        self.engineList.clear()
        keys = self.searchManager.searchEngines.keys()
        if type(keys) is not list:
            keys = [key for key in keys]
        for name in sorted(keys):
            keyword = "None"
            if self.searchManager.searchEngines[name][0] != "":
                keyword = self.searchManager.searchEngines[name][0]
            self.engineList.addItem("%s\nKeyword: %s" % (name, keyword))
        for item in range(0, self.engineList.count()):
            if self.searchManager.searchEngines[unicode(self.engineList.item(item).text()).split("\n")[0]][1] == self.searchManager.currentSearch:
                self.engineList.setCurrentItem(self.engineList.item(item))
                self.searchChanged.emit(str(unicode(self.engineList.item(item).text()).split("\n")[0]))
                break

    def addSearch(self):
        if "%s" in self.expEntry.text():
            name = QInputDialog.getText(self, tr('Query'), tr('Enter a name here:'))
            if name[1] and name[0] != "":
                name = name[0]
                keyword = QInputDialog.getText(self, tr('Query'), tr('Enter a keyword here:'))[0]
                self.searchManager.add(name, self.expEntry.text(), keyword)
                self.expEntry.clear()
            self.reload_()
        else:
            QMessageBox.warning(self, tr('Error'), tr('Search expression must contain a <b>%s</b> to indicate the search terms.'))

    def applySearch(self, item=False, old=False):
        if item:
            try: unicode(item.text()).split("\n")[0]
            except:
                notificationMessage(tr('searchError'))
            else:
                self.searchManager.change(unicode(item.text()).split("\n")[0])
        if item != None:
            self.searchChanged.emit(str(unicode(item.text()).split("\n")[0]))

    def takeSearch(self):
        self.searchManager.remove(unicode(self.engineList.currentItem().text()).split("\n")[0])
        self.reload_()
示例#11
0
class LicenseDialog(QMainWindow):
    def __init__(self, parent=None):
        super(LicenseDialog, self).__init__(parent)
        self.resize(420, 320)
        self.setWindowTitle(tr("Credits & Licensing"))
        self.setWindowFlags(Qt.Dialog)
        self.readme = ""
        self.license = ""
        self.thanks = ""
        self.authors = ""
        self.tabWidget = QTabWidget(self)
        self.setCentralWidget(self.tabWidget)
        for folder in (app_folder, os.path.dirname(app_folder)):
            for fname in os.listdir(folder):
                if fname.startswith("LICENSE"):
                    try: f = open(os.path.join(folder, fname), "r")
                    except: pass
                    else:
                        self.license = f.read()
                        f.close()
                elif fname.startswith("THANKS"):
                    try: f = open(os.path.join(folder, fname), "r")
                    except: pass
                    else:
                        self.thanks = f.read()
                        f.close()
                elif fname.startswith("AUTHORS"):
                    try: f = open(os.path.join(folder, fname), "r")
                    except: pass
                    else:
                        self.authors = f.read()
                        f.close()
                elif fname.startswith("README"):
                    try: f = open(os.path.join(folder, fname), "r")
                    except: pass
                    else:
                        self.readme = f.read()
                        f.close()
        self.readmeView = ReadOnlyTextEdit(self)
        self.readmeView.setText(self.readme)
        self.tabWidget.addTab(self.readmeView, tr("&README"))
        self.authorsView = ReadOnlyTextEdit(self)
        self.authorsView.setText(self.authors)
        self.tabWidget.addTab(self.authorsView, tr("&Authors"))
        self.thanksView = ReadOnlyTextEdit(self)
        self.thanksView.setText(self.thanks)
        self.tabWidget.addTab(self.thanksView, tr("&Thanks"))
        self.licenseView = ReadOnlyTextEdit(self)
        self.licenseView.setText(self.license)
        self.tabWidget.addTab(self.licenseView, tr("&License"))
        closeAction = QAction(self)
        closeAction.setShortcuts(["Esc", "Ctrl+W"])
        closeAction.triggered.connect(self.hide)
        self.addAction(closeAction)
        self.toolBar = QToolBar(self)
        self.toolBar.setStyleSheet(blank_toolbar)
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.addToolBar(Qt.BottomToolBarArea, self.toolBar)
        self.toolBar.addWidget(HorizontalExpander(self))
        self.closeButton = QPushButton(tr("&OK"), self)
        self.closeButton.clicked.connect(self.close)
        self.toolBar.addWidget(self.closeButton)
        self.closeButton.setFocus()
示例#12
0
class ListLayout(QWidget, CueLayout):

    NAME = 'List Layout'
    DESCRIPTION = '''
                    This layout organize the cues in a list:
                    <ul>
                        <li>Unlimited cues;
                        <li>Side panel with playing media-cues;
                        <li>Cues can be moved in the list;
                        <li>Keyboard control;
                    </ul>'''

    HEADER = ['', 'Cue', 'Duration', 'Progress']

    # I need to redefine those from CueLayout
    key_pressed = CueLayout.key_pressed
    cue_added = CueLayout.cue_added
    cue_removed = CueLayout.cue_removed
    focus_changed = CueLayout.focus_changed

    def __init__(self, app, **kwds):
        super().__init__(**kwds)

        self.mainWindow = app.mainWindow
        self.menuLayout = self.mainWindow.menuLayout

        self._cue_items = []
        self._playing_widgets = {}
        self._context_item = None

        self._show_dbmeter = config['ListLayout']['ShowDbMeters'] == 'True'
        self._show_seek = config['ListLayout']['ShowSeek'] == 'True'
        self._accurate_time = config['ListLayout']['ShowAccurate'] == 'True'
        self._auto_next = config['ListLayout']['AutoNext'] == 'True'

        # Add layout-specific menus
        self.showDbMeterAction = QAction(self)
        self.showDbMeterAction.setCheckable(True)
        self.showDbMeterAction.setChecked(self._show_dbmeter)
        self.showDbMeterAction.triggered.connect(self.set_dbmeter_visible)

        self.showSeekAction = QAction(self)
        self.showSeekAction.setCheckable(True)
        self.showSeekAction.setChecked(self._show_seek)
        self.showSeekAction.triggered.connect(self.set_seek_visible)

        self.accurateTimingAction = QAction(self)
        self.accurateTimingAction.setCheckable(True)
        self.accurateTimingAction.setChecked(self._accurate_time)
        self.accurateTimingAction.triggered.connect(self.set_accurate_time)

        self.autoNextAction = QAction(self)
        self.autoNextAction.setCheckable(True)
        self.autoNextAction.setChecked(self._auto_next)
        self.autoNextAction.triggered.connect(self.set_auto_next)

        self.menuLayout.addAction(self.showDbMeterAction)
        self.menuLayout.addAction(self.showSeekAction)
        self.menuLayout.addAction(self.accurateTimingAction)
        self.menuLayout.addAction(self.autoNextAction)

        # Add a toolbar to MainWindow
        self.toolBar = QToolBar(self.mainWindow)
        self.toolBar.setContextMenuPolicy(QtCore.Qt.PreventContextMenu)

        self.playAction = QAction(self)
        self.playAction.setIcon(QIcon.fromTheme("media-playback-start"))
        self.playAction.triggered.connect(self.play_current)

        self.pauseAction = QAction(self)
        self.pauseAction.setIcon(QIcon.fromTheme("media-playback-pause"))
        self.pauseAction.triggered.connect(self.pause_current)

        self.stopAction = QAction(self)
        self.stopAction.setIcon(QIcon.fromTheme("media-playback-stop"))
        self.stopAction.triggered.connect(self.stop_current)

        self.stopAllAction = QAction(self)
        self.stopAllAction.font().setBold(True)
        self.stopAllAction.triggered.connect(self.stop_all)

        self.pauseAllAction = QAction(self)
        self.pauseAllAction.font().setBold(True)
        self.pauseAllAction.triggered.connect(self.pause_all)

        self.restartAllAction = QAction(self)
        self.restartAllAction.font().setBold(True)
        self.restartAllAction.triggered.connect(self.restart_all)

        self.toolBar.addAction(self.playAction)
        self.toolBar.addAction(self.pauseAction)
        self.toolBar.addAction(self.stopAction)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.stopAllAction)
        self.toolBar.addAction(self.pauseAllAction)
        self.toolBar.addAction(self.restartAllAction)

        self.mainWindow.addToolBar(self.toolBar)

        self.hLayout = QHBoxLayout(self)
        self.hLayout.setContentsMargins(5, 5, 5, 5)

        # On the left (cue list)
        self.listView = ListWidget(self)
        self.listView.context_event.connect(self.context_event)
        self.listView.key_event.connect(self.onKeyPressEvent)
        self.listView.drop_move_event.connect(self.move_cue_at)
        self.listView.drop_copy_event.connect(self._copy_cue_at)
        self.listView.setHeaderLabels(self.HEADER)
        self.listView.header().setSectionResizeMode(QHeaderView.Fixed)
        self.listView.header().setSectionResizeMode(self.HEADER.index('Cue'),
                                                    QHeaderView.Stretch)
        self.listView.setColumnWidth(0, 40)
        self.hLayout.addWidget(self.listView)

        self.vLayout = QVBoxLayout()
        self.vLayout.setContentsMargins(0, 0, 0, 0)
        self.vLayout.setSpacing(2)

        # On the right (playing media-cues)
        self.label = QLabel('Playing', self)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setStyleSheet('font-size: 17pt; font-weight: bold;')
        self.vLayout.addWidget(self.label)

        self.playView = QListWidget(self)
        self.playView.setMinimumWidth(300)
        self.playView.setMaximumWidth(300)
        self.playView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.playView.setFocusPolicy(QtCore.Qt.NoFocus)
        self.playView.setSelectionMode(QAbstractItemView.NoSelection)
        self.vLayout.addWidget(self.playView)

        self.hLayout.addLayout(self.vLayout)

        # Add cue preferences widgets
        self.add_settings_section(MediaCueGeneral, MediaCue)
        self.add_settings_section(Appearance)

        # Context menu actions
        self.edit_action = QAction(self)
        self.edit_action.triggered.connect(self.edit_context_cue)

        self.remove_action = QAction(self)
        self.remove_action.triggered.connect(self.remove_context_cue)

        self.select_action = QAction(self)
        self.select_action.triggered.connect(self.select_context_cue)

        self.add_context_item(self.edit_action)
        self.sep1 = self.add_context_separator()
        self.add_context_item(self.remove_action)
        self.add_context_item(self.select_action)

        self.retranslateUi()

    def retranslateUi(self):
        self.showDbMeterAction.setText("Show Db-meters")
        self.showSeekAction.setText("Show seek bars")
        self.accurateTimingAction.setText('Accurate timing')
        self.autoNextAction.setText('Auto select next cue')
        self.playAction.setText("Go")
        self.pauseAction.setText("Pause")
        self.stopAction.setText("Stop")
        self.stopAllAction.setText("Stop All")
        self.pauseAllAction.setText("Pause All")
        self.restartAllAction.setText("Restart All")

        self.edit_action.setText('Edit option')
        self.remove_action.setText('Remove')
        self.select_action.setText('Select')

    def current_cue(self):
        item = self.current_item()
        if item is not None:
            return item.cue

    def current_item(self):
        if len(self._cue_items) > 0:
            return self._cue_items[self.listView.currentIndex().row()]

    def select_context_cue(self):
        self._context_item.select()

    def __add_cue__(self, cue, index):
        if isinstance(cue, MediaCue):
            item = MediaItem(cue, self.listView)

            # Use weak-references for avoid cyclic-references with lambda(s)
            wself = weakref.ref(self)
            wcue = weakref.ref(cue)

            cue.media.on_play.connect(lambda: wself().show_playing(wcue()))
            cue.media.interrupted.connect(lambda: wself().hide_playing(wcue()))
            cue.media.stopped.connect(lambda: wself().hide_playing(wcue()))
            cue.media.error.connect(lambda: wself().hide_playing(wcue()))
            cue.media.eos.connect(lambda: wself().hide_playing(wcue()))
        elif isinstance(cue, ActionCue):
            item = ActionItem(cue)
            item.cue = cue
        else:
            raise Exception('Cue type not supported')

        item.setFlags(item.flags() & ~QtCore.Qt.ItemIsDropEnabled)

        if index is None or (index < 0 or index >= len(self._cue_items)):
            cue['index'] = len(self._cue_items)
            self.listView.addTopLevelItem(item)
            self._cue_items.append(item)
        else:
            self.listView.insertTopLevelItem(index, item)
            self._cue_items.insert(index, item)
            for n in range(index, len(self._cue_items)):
                self._cue_items[n].cue['index'] = n

        if isinstance(item, MediaItem):
            item.init()

        if len(self._cue_items) == 1:
            self.listView.setCurrentItem(item)
            self.listView.setFocus()
            self.listView.resizeColumnToContents(1)

        self.cue_added.emit(cue)

    def set_accurate_time(self, enable):
        self._accurate_time = enable

        for i in range(self.playView.count()):
            widget = self.playView.itemWidget(self.playView.item(i))
            widget.set_accurate_time(enable)

        for item in self._cue_items:
            if isinstance(item, MediaItem):
                item.set_accurate_time(enable)

    def set_auto_next(self, enable):
        self._auto_next = enable

    def set_seek_visible(self, visible):
        self._show_seek = visible
        for i in range(self.playView.count()):
            widget = self.playView.itemWidget(self.playView.item(i))
            widget.set_seek_visible(visible)

    def set_dbmeter_visible(self, visible):
        self._show_dbmeter = visible
        for i in range(self.playView.count()):
            widget = self.playView.itemWidget(self.playView.item(i))
            widget.set_dbmeter_visible(visible)

    def show_playing(self, cue):
        if cue not in self._playing_widgets:
            media_time = self._cue_items[cue['index']].media_time
            widget = PlayingMediaWidget(cue, media_time, self.playView)
            widget.set_dbmeter_visible(self._show_dbmeter)
            widget.set_seek_visible(self._show_seek)
            widget.set_accurate_time(self._accurate_time)

            list_item = QListWidgetItem()
            list_item.setSizeHint(widget.size())

            self.playView.addItem(list_item)
            self.playView.setItemWidget(list_item, widget)
            self._playing_widgets[cue] = list_item

    def hide_playing(self, cue):
        if cue in self._playing_widgets:
            list_item = self._playing_widgets.pop(cue)
            widget = self.playView.itemWidget(list_item)
            row = self.playView.indexFromItem(list_item).row()

            self.playView.removeItemWidget(list_item)
            self.playView.takeItem(row)

            widget.destroy_widget()

    def onKeyPressEvent(self, e):
        if e.key() == QtCore.Qt.Key_Space:
            if qApp.keyboardModifiers() == Qt.ShiftModifier:
                cue = self.current_cue()
                if cue is not None:
                    self.edit_cue(cue)
            elif qApp.keyboardModifiers() == Qt.ControlModifier:
                item = self.current_item()
                if item is not None:
                    item.select()
            else:
                cue = self.current_cue()
                if cue is not None:
                    cue.execute()
                if self._auto_next:
                    nextitem = self.listView.currentIndex().row() + 1
                    if nextitem < self.listView.topLevelItemCount():
                        nextitem = self.listView.topLevelItem(nextitem)
                        self.listView.setCurrentItem(nextitem)
        else:
            self.key_pressed.emit(e)

        e.accept()

    def play_current(self):
        cue = self.current_cue()
        if isinstance(cue, MediaCue):
            cue.media.play()
        else:
            cue.execute()

    def pause_current(self):
        cue = self.current_cue()
        if isinstance(cue, MediaCue):
            cue.media.pause()

    def stop_current(self):
        cue = self.current_cue()
        if isinstance(cue, MediaCue):
            cue.media.stop()

    def context_event(self, event):
        item = self.listView.itemAt(event.pos())
        if item is not None:
            index = self.listView.indexOfTopLevelItem(item)
            self._context_item = self._cue_items[index]
            self.show_context_menu(event.globalPos())
        event.accept()

    def remove_context_cue(self):
        self.remove_cue(self.get_context_cue())

    def edit_context_cue(self):
        self.edit_cue(self.get_context_cue())

    def stop_all(self):
        for item in self._cue_items:
            if isinstance(item.cue, MediaCue):
                item.cue.media.stop()

    def pause_all(self):
        for item in self._cue_items:
            if isinstance(item.cue, MediaCue):
                item.cue.media.pause()

    def restart_all(self):
        for item in self._cue_items:
            if isinstance(item.cue, MediaCue):
                if item.cue.media.state == Media.PAUSED:
                    item.cue.media.play()

    def __remove_cue__(self, cue):
        index = cue['index']
        self.listView.takeTopLevelItem(index)
        self._cue_items.pop(index)

        if isinstance(cue, MediaCue):
            cue.media.interrupt()
            if cue in self._playing_widgets:
                self.hide_playing(self._playing_widgets[cue])

        for item in self._cue_items[index:]:
            item.cue['index'] = item.cue['index'] - 1

        cue.finalize()

        self.cue_removed.emit(cue)

    def move_cue_at(self, old_index, index):
        self.move_cue(self._cue_items[old_index].cue, index)

    def _copy_cue_at(self, old_index, index):
        newcue = CueFactory.clone_cue(self._cue_items[old_index].cue)
        self.add_cue(newcue, index)

    def __move_cue__(self, cue, index):
        item = self._cue_items.pop(cue['index'])
        self._cue_items.insert(index, item)
        self.listView.setCurrentItem(item)

        if isinstance(item, MediaItem):
            item.init()

        for n, item in enumerate(self._cue_items):
            item.cue['index'] = n

    def get_cues(self, cue_class=Cue):
        # i -> item
        return [i.cue for i in self._cue_items if isinstance(i.cue, cue_class)]

    def get_cue_at(self, index):
        if index < len(self._cue_items):
            return self._cue_items[index].cue

    def get_cue_by_id(self, cue_id):
        for item in self._cue_items:
            if item.cue.cue_id() == cue_id:
                return item.cue

    def get_selected_cues(self, cue_class=Cue):
        cues = []
        for item in self._cue_items:
            if item.selected and isinstance(item.cue, cue_class):
                cues.append(item.cue)
        return cues

    def clear_layout(self):
        while len(self._cue_items) > 0:
            self.__remove_cue__(self._cue_items[-1].cue)

    def destroy_layout(self):
        self.clear_layout()
        self.menuLayout.clear()
        self.mainWindow.removeToolBar(self.toolBar)
        self.toolBar.deleteLater()

        # Remove context-items
        self.remove_context_item(self.edit_action)
        self.remove_context_item(self.sep1)
        self.remove_context_item(self.remove_action)
        self.remove_context_item(self.select_action)

        # Remove settings-sections
        self.remove_settings_section(Appearance)
        self.remove_settings_section(MediaCueGeneral)

        # !! Delete the layout references !!
        self.deleteLater()

    def get_context_cue(self):
        return self._context_item.cue

    def select_all(self):
        for item in self._cue_items:
            if not item.selected:
                item.select()

    def deselect_all(self):
        for item in self._cue_items:
            if item.selected:
                item.select()

    def invert_selection(self):
        for item in self._cue_items:
            item.select()
    def __init__(self, parent=None):
        """Defaults the application window to be 500X500"""
        super(MyMainWindow, self).__init__(parent=parent)
        self.left = 500
        self.top = 500
        self.width = 500
        self.height = 500
        self.ui_widget = UIWidget()
        self.popup_settings = PopupSettings(self.ui_widget.graphix)
        self.glossary = Glossary(2)
        self.save_rules = SaveRules(self.ui_widget)
        self.getting_started = GettingStarted()
        self.init_window()

        toolbar = QToolBar("Settings Toolbar")
        toolbar.setIconSize(QSize(16,16))
        self.addToolBar(toolbar)
        toolbar.setMovable(False)
        toolbar.setContextMenuPolicy(Qt.PreventContextMenu)

        self.button_action = QAction("2D", self)
        self.button_action.setStatusTip("Click to use 2D L-Systems!")
        self.button_action.triggered.connect(self.toggle_dim2D)

        self.button_action2 = QAction("3D", self)
        self.button_action2.setStatusTip("Click to use 3D L-Systems!")
        self.button_action2.triggered.connect(self.toggle_dim3D)

        self.save_action = QAction('Save Rules', self)
        self.save_action.setStatusTip("Click to save the grammar of the L-System!")
        self.save_action.triggered.connect(lambda: self.save_rules.show())

        self.glossary_action = QAction("Glossary", self)
        self.glossary_action.setStatusTip("Click to see the glossary!")
        self.glossary_action.triggered.connect(lambda: self.glossary.show())

        self.tutorial = QAction("Tutorial", self)
        self.tutorial.setStatusTip("Click here to see how to get started!")
        self.tutorial.triggered.connect(lambda: self.getting_started.show())

        self.reset_zoom_button = QAction("Reset Zoom",self)
        self.reset_zoom_button.setStatusTip("Click here to reset zoom!")
        self.reset_zoom_button.triggered.connect(self.reset_zoom)

        self.reset_txtbox_button = QAction("Reset Rules",self)
        self.reset_txtbox_button.setStatusTip("Click here to clear the rules!")
        self.reset_txtbox_button.triggered.connect(self.ui_widget.reset_input_boxes)

        if sys.platform == 'win32' :
          self.screenshot_button = QAction("Screenshot",self)
          self.screenshot_button.setStatusTip("Click here to take a screenshot!")
          self.screenshot_button.triggered.connect(self.screenshot)
          toolbar.addAction(self.screenshot_button)

        toolbar.addAction(self.tutorial)
        toolbar.addAction(self.glossary_action)
        toolbar.addAction(self.save_action)
        toolbar.addAction(self.reset_zoom_button)
        toolbar.addAction(self.reset_txtbox_button)

        toolbar.addSeparator()


        toolbar.addAction(self.button_action)
        toolbar.addAction(self.button_action2)

        self.button_action.setCheckable(True)
        self.button_action2.setCheckable(True)
        self.button_action.setChecked(True)

        self.setStatusBar(QStatusBar(self))

        self.setCentralWidget(self.ui_widget)
示例#14
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setObjectName("myGitClone")
        root = QFileInfo.path(QFileInfo(QCoreApplication.arguments()[0]))
        print("root", root)
        self.icon = QIcon(f"{root}/favicon.ico")
        self.setWindowIcon(self.icon)
        self.setGeometry(0, 0, 800, 600)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setMinimumSize(400, 300)
        self.setDocumentMode(True)
        self.settings = QSettings('Axel Schneider', self.objectName())
        self.createStatusbar()
        self.createActions()
        self.createWidgets()
        QMetaObject.connectSlotsByName(self)
        self.readSettings()
        self.statusbar.showMessage("Ready")
        self.setWindowTitle("myGitClone")

        ### process
        ### shell settings
        self.process = QProcess(self)
        self.process.setProcessChannelMode(QProcess.MergedChannels)
        self.process.readyReadStandardError.connect(lambda: self.msg("Error"))
        self.process.started.connect(lambda: self.msg("starting shell"))
        self.process.finished.connect(lambda: self.msg("shell ended"))

    ### widgets ###
    def createWidgets(self):
        self.username = ""
        self.url = "https://github.com/%s?tab=repositories" % self.username
        self.repoList = []
        self.gitList = []
        self.dlFolder = QDir.homePath() + "/Downloads"

        ### table ###
        self.lb = QTableWidget()
        self.lb.setColumnCount(2)
        self.lb.setColumnWidth(0, 60)
        self.lb.horizontalHeader().setStretchLastSection(True)
        self.lb.setHorizontalHeaderItem(0, QTableWidgetItem("Select"))
        self.lb.setHorizontalHeaderItem(1, QTableWidgetItem("Repository Name"))

        ### username field ###
        self.uname = QLineEdit("")
        self.uname.setFixedWidth(180)
        self.uname.setPlaceholderText("insert user name")
        self.uname.returnPressed.connect(self.listRepos)

        ### get repos button ###
        self.uBtn = QPushButton(QIcon(self.icon), "get Repos List")
        self.uBtn.setToolTip("get all repos from user")
        self.uBtn.clicked.connect(self.listRepos)

        ### get repos button ###
        self.dlBtn = QPushButton(QIcon.fromTheme("download"),
                                 "download selected Repos")
        self.dlBtn.setToolTip("download selected repos from user")
        self.dlBtn.setFixedWidth(180)
        self.dlBtn.clicked.connect(self.create_dl_list)

        ### Layout
        self.ubox = QHBoxLayout()
        self.ubox.addWidget(self.uname)
        self.ubox.addWidget(self.uBtn)
        self.ubox.addStretch(1)
        self.ubox.addWidget(self.dlBtn)

        self.layout = QVBoxLayout()
        self.wid = QWidget()

        self.layout.addLayout(self.ubox)
        self.layout.addWidget(self.lb)
        self.wid.setLayout(self.layout)

        self.setCentralWidget(self.wid)

    ### actions ###
    def createActions(self):
        self.tbar = QToolBar()
        self.tbar.setIconSize(QSize(16, 16))
        self.tbar.setMovable(False)
        self.tbar.setToolButtonStyle(0)
        self.tbar.setContextMenuPolicy(Qt.PreventContextMenu)
        self.tbar.setObjectName("tbar")
        self.addToolBar(self.tbar)

        self.actionSettings = QAction(self,
                                      triggered=self.appSettings,
                                      toolTip="set output directory")
        icon = QIcon.fromTheme("preferences-system")
        self.actionSettings.setIcon(icon)
        self.actionSettings.setObjectName("actionSettings")

        self.actionAbout = QAction(self, triggered=self.aboutApp)
        icon = QIcon.fromTheme("help-about")
        self.actionAbout.setIcon(icon)

        self.tbar.addAction(self.actionSettings)
        self.tbar.addAction(self.actionAbout)

        ### statusbar###
    def createStatusbar(self):
        self.statusbar = QStatusBar(self)
        font = QFont()
        font.setPointSize(7)
        self.statusbar.setFont(font)
        self.statusbar.setObjectName("statusbar")
        self.setStatusBar(self.statusbar)

    ### get username from textfield
    def changeUsername(self):
        self.username = self.uname.text()
        self.url = "https://github.com/%s?tab=repositories" % self.username

    ### get user repos ##
    def listRepos(self):
        self.changeUsername()
        if self.username == "":
            self.msgBox("please type a username")
        else:
            self.lb.setRowCount(0)
            self.repoList = []
            repositories = self.get_repositories()
            print("%s %s" % ("get repos from", self.username))
            self.repoList = list(repositories)
            self.fillTable()
            self.msg("repos loaded")

    ### fill table with user repos
    def fillTable(self):
        self.lb.setRowCount(len(self.repoList))
        if self.lb.rowCount() > 0:
            for x in range(len(self.repoList)):
                rep = QTableWidgetItem(self.repoList[x])
                checkbox = QCheckBox(self.lb)
                checkbox.setStyleSheet("margin-left:20%; margin-right:10%;")
                checkbox.setCheckState(0)
                self.lb.setCellWidget(x, 0, checkbox)
                self.lb.setItem(x, 1, rep)

    ### table context menu
    def contextMenuEvent(self, event):
        self.menu = QMenu(self)
        if self.lb.selectionModel().hasSelection():
            # copy
            downloadAction = QAction(QIcon.fromTheme("download"),
                                     'download Repo', self)
            downloadAction.triggered.connect(
                lambda: self.downloadRepoFromList())
            ###
            self.menu.addAction(downloadAction)
            self.menu.popup(QCursor.pos())

    def listChanged(self):
        self.create_dl_list()

    ### get download list from selected repos
    def create_dl_list(self):
        r = ""
        self.gitList = []
        for x in range(self.lb.rowCount()):
            if self.lb.cellWidget(x, 0).checkState() == 2:
                r = self.lb.item(x, 1).text()
                self.gitList.append(r)
                print("%s %s" % (r, "is selected"))
                self.downloadRepo(r)

    ### download repo
    def downloadRepo(self, gitrepo):
        merror = ""
        cmd = "git clone --progress --verbose https://github.com/" + str(
            self.username) + "/" + str(gitrepo) + " " + str(
                self.dlFolder) + "/" + str(gitrepo)
        print("%s %s" % ("username is:", self.username))
        print(cmd)
        try:
            self.process.execute(cmd)
        except Exception as e:
            s = str(e)
            self.errorBox(s)

    ### download selected repo (context menu)
    def downloadRepoFromList(self):
        row = self.lb.selectionModel().selectedIndexes()[0].row()
        gitrepo = self.lb.item(row, 1).text()
        cmd = "git clone --progress --verbose https://github.com/" + str(
            self.username) + "/" + str(gitrepo) + " " + str(
                self.dlFolder) + "/" + str(gitrepo)
        print(cmd)
        self.process.execute(cmd)

    ### preferences
    def appSettings(self):
        if self.dlFolder == "":
            self.dlFolder = QDir.homePath()
        self.msg("settings called")
        path = QFileDialog.getExistingDirectory(self, "select Folder",
                                                self.dlFolder)
        if path:
            self.dlFolder = path
            print("%s %s" % ("download folder changed to", self.dlFolder))

    def closeEvent(self, e):
        self.writeSettings()
        e.accept()

    ### read settings from config file
    def readSettings(self):
        print("reading settings")
        if self.settings.contains('geometry'):
            self.setGeometry(self.settings.value('geometry'))
        if self.settings.contains('downloadFolder'):
            self.dlFolder = self.settings.value('downloadFolder')
            self.msg(self.dlFolder)
            print("%s %s" % ("download folder:", self.dlFolder))

    ### write settings to config file
    def writeSettings(self):
        print("writing settings")
        self.settings.setValue('geometry', self.geometry())
        self.settings.setValue('downloadFolder', self.dlFolder)

    ### about window
    def aboutApp(self):
        title = "about myGitClone"
        message = """
                    <span style='color: #3465a4; font-size: 18pt;font-weight: bold;'
                    >myGitClone</strong></span></p>
                    <h3>based on <a title='git_clones' href='https://github.com/rootVIII/git_clones' target='_blank'> git_clones</a> by James</h3>
                    <h4>created by  <a title='Axel Schneider' href='http://goodoldsongs.jimdo.com' target='_blank'>Axel Schneider</a> with PyQt5</h3>
                    <br>
                    <span style='color: #555753; font-size: 9pt;'>©2019 Axel Schneider, James</strong></span></p>
                        """
        self.infobox(title, message)

    ### error messagebox
    def errorBox(self, message):
        mwin = QMessageBox.warning(self, "Error", message)

    ### messagebox
    def infobox(self, title, message):
        QMessageBox.about(self, title, message).show()

    ### set statusbar text
    def msg(self, message):
        self.statusbar.showMessage(message)

    def msgBox(self, message):
        msg = QMessageBox.warning(self, "Information", message)

    ### begin from git_clones ###
    def http_get(self):
        if version_info[0] != 2:
            req = urlopen(self.url)
            return req.read().decode('utf-8')
        req = Request(self.url)
        request = urlopen(req)
        return request.read()

    def get_repo_data(self):
        try:
            response = self.http_get()
        except Exception as e:
            s = str(e)
            self.errorBox(s)
            print("Unable to make request to %s's Github page" % self.username)
            exit(1)
        else:
            pattern = r"<a\s?href\W+%s/(.*)\"\s+" % self.username
            for line in findall(pattern, response):
                yield line.split('\"')[0]

    def get_repositories(self):
        return set([repo for repo in self.get_repo_data()])
示例#15
0
class MainWindow(QMainWindow):
    """
    Main UI window

    Class creates window elements, fills main menu with items.

    If you need to access to some existing menu items - check action path
    in the class constructor, than use next code: ::

        core.actionManager().action("mFile/aOpen").setEnabled(True)
        core.actionManager().action("mFile/aOpen").triggered.connect(self.myCoolMethod)

    MainWindow instance is accessible as: ::

        from enki.core.core import core
        core.mainwindow()

    Created by the core
    """

    hideAllWindows = pyqtSignal()
    """
    hideAllWindows()

    **Signal** emitted, when user toggled "Hide all" .
    Dock widgets are closed automatically, but other widgets, i.e. search widget, must catch this signal and close
    themselves.
    """  # pylint: disable=W0105

    directoryDropt = pyqtSignal(str)
    """
    directoryDropt()

    **Signal** emitted, when user drag-n-dropt directory to main windowd.
    FileBrowser shows directory
    """  # pylint: disable=W0105

    _STATE_FILE = os.path.join(enki.core.defines.CONFIG_DIR,
                               "main_window_state.bin")
    _GEOMETRY_FILE = os.path.join(enki.core.defines.CONFIG_DIR,
                                  "main_window_geometry.bin")

    def __init__(self):
        QMainWindow.__init__(self)

        self._queuedMessageToolBar = None
        self._createdMenuPathes = []
        self._createdActions = []

        self._addedDockWidgets = []

        if hasattr(self, 'setUnifiedTitleAndToolBarOnMac'
                   ):  # missing on some PyQt5 versions
            self.setUnifiedTitleAndToolBarOnMac(True)
        self.setIconSize(QSize(16, 16))
        self.setAcceptDrops(True)

        # Set corner settings for dock widgets
        self.setCorner(Qt.TopLeftCorner, Qt.LeftDockWidgetArea)
        self.setCorner(Qt.TopRightCorner, Qt.RightDockWidgetArea)
        self.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea)
        self.setCorner(Qt.BottomRightCorner, Qt.RightDockWidgetArea)

        self.setWindowTitle(self.defaultTitle(
        ))  # overwriten by workspace when file or it's modified state changes
        self.setWindowIcon(QIcon(':/enkiicons/logo/enki.svg'))

        # Create top tool bar
        self._topToolBar = QToolBar("topToolBar")
        self._topToolBar.setObjectName("topToolBar")
        self._topToolBar.setMovable(False)
        self._topToolBar.setIconSize(QSize(16, 16))
        self._topToolBar.setContextMenuPolicy(
            Qt.PreventContextMenu)  # to avoid possibility to hide the toolbar

        # Create menu bar
        self._menuBar = ActionMenuBar(self, core.actionManager())
        self._initMenubarAndStatusBarLayout()

        # create central layout
        widget = QWidget(self)
        self._centralLayout = QVBoxLayout(widget)
        self._centralLayout.setContentsMargins(0, 0, 0, 0)
        self.setCentralWidget(widget)
        self.setStyleSheet('QMainWindow::separator{width: 4px}')

    def _initActions(self):
        """ Public method for actionManager. """

        self._createMenuStructure()
        core.actionManager().action('mView/aOpenMainMenu').triggered.connect(
            self._openMainMenu)
        core.actionManager().action('mFile/aQuit').triggered.connect(
            self.onQuit)

    def terminate(self):
        """Explicitly called destructor
        """
        if self._queuedMessageToolBar:
            self.removeToolBar(self._queuedMessageToolBar)
            del self._queuedMessageToolBar

        for act in self._createdActions:
            core.actionManager().removeAction(act)
        for menuPath in self._createdMenuPathes[::-1]:
            core.actionManager().removeMenu(menuPath)

    @staticmethod
    def _isMenuEmbeddedToTaskBar():
        """On Unity (Ubuntu) and MacOS menu bar is embedded to task bar
        """
        return 'UBUNTU_MENUPROXY' in os.environ or \
               os.environ.get('XDG_CURRENT_DESKTOP') == 'Unity' or \
               'darwin' == sys.platform

    def _initMenubarAndStatusBarLayout(self):
        """Create top widget and put it on its place
        """
        if not 'darwin' == sys.platform:
            # on Ubuntu toolbar, docs and editor area look as one widget. Ugly
            # Therefore it is separated with line. On Mac seems OK
            # I can't predict, how it will look on other platforms, therefore line is used for all, except Mac
            toolBarStyleSheet = "QToolBar {border: 0; border-bottom-width: 1; border-bottom-style: solid}" ""
            self._topToolBar.setStyleSheet(toolBarStyleSheet)

        area = Qt.BottomToolBarArea if self._isMenuEmbeddedToTaskBar(
        ) else Qt.TopToolBarArea
        self.addToolBar(area, self._topToolBar)

        if self._isMenuEmbeddedToTaskBar():  # separate menu bar
            self.setMenuBar(self._menuBar)
        else:  # menubar, statusbar and editor tool bar on one line
            self._menuBar.setAutoFillBackground(False)
            menuBarStyleSheet = """
            QMenuBar {background-color: transparent;
                      color: %s}
            QMenuBar::item:!selected {background: transparent;}
            """ % self.palette().color(QPalette.WindowText).name()
            self._menuBar.setStyleSheet(menuBarStyleSheet)
            self._menuBar.setSizePolicy(QSizePolicy.MinimumExpanding,
                                        QSizePolicy.Minimum)

            self._topToolBar.addWidget(self._menuBar)

        # Create status bar
        self._statusBar = _StatusBar(self)
        self._topToolBar.addWidget(self._statusBar)

    def _initQueuedMessageToolBar(self):
        from enki.core.queued_msg_tool_bar import QueuedMessageToolBar

        self._queuedMessageToolBar = QueuedMessageToolBar(self)
        area = Qt.TopToolBarArea if self._isMenuEmbeddedToTaskBar(
        ) else Qt.BottomToolBarArea
        self.addToolBar(area, self._queuedMessageToolBar)
        self._queuedMessageToolBar.setVisible(False)

    def _createMenuStructure(self):
        """Fill menu bar with items. The majority of items are not connected to the slots,
        Connections made by module, which implements menu item functionality, but, all items are in one place,
        because it's easier to create clear menu layout
        """

        # create menubar menus and actions

        def menu(path, name, icon, visible=True):
            """Subfunction for create a menu in the main menu"""
            menuObject = core.actionManager().addMenu(path, name)
            if icon:
                menuObject.setIcon(QIcon(':/enkiicons/' + icon))
            self._createdMenuPathes.append(path)
            if not visible:
                menuObject.setVisible(False)

        def action(path,
                   name,
                   icon,
                   shortcut,
                   tooltip,
                   enabled,
                   checkable=False):  # pylint: disable=R0913
            """Subfunction for create an action in the main menu"""
            if icon:  # has icon
                actObject = core.actionManager().addAction(
                    path, name, QIcon(':/enkiicons/' + icon), shortcut)
            else:
                actObject = core.actionManager().addAction(path,
                                                           name,
                                                           shortcut=shortcut)
            if tooltip:
                actObject.setStatusTip(tooltip)
            actObject.setEnabled(enabled)
            actObject.setCheckable(checkable)
            self._createdActions.append(actObject)

        def separator(menu):
            """Subfunction for insert separator to the menu"""
            core.actionManager().action(menu).menu().addSeparator()

        # pylint: disable=C0301
        # enable long lines for menu items
        # Menu or action path                          Name                     Icon            Shortcut        Hint                     enabled  checkable
        menu("mFile", "File", "")
        action("mFile/aOpenProject", "Open Pro&ject...", "open.png",
               "Shift+Ctrl+O", "Open a project", True)
        separator("mFile")
        menu("mFile/mUndoClose", "Undo Close", "recents.png")
        separator("mFile")
        action("mFile/aNew", "&New file...", "new.png", 'Ctrl+N', "New file",
               True)
        action("mFile/aOpen", "&Open...", "open.png", "Ctrl+O", "Open a file",
               True)
        menu("mFile/mSave", "&Save", "save.png")
        action("mFile/mSave/aCurrent", "&Save", "save.png", "Ctrl+S",
               "Save the current file", False)
        action("mFile/mSave/aSaveAs", "Save As...", "save.png", "Ctrl+Alt+S",
               "", False)
        action("mFile/mSave/aAll", "Save &All", "saveall.png", 'Shift+Ctrl+S',
               "Save all files", False)
        menu("mFile/mReload", "&Reload", "reload.png")
        action("mFile/mReload/aCurrent", "Reload", "reload.png", 'F5',
               "Reload the current file", False)
        action("mFile/mReload/aAll", "Reload All", "reload.png", 'Shift+F5',
               "Reload all files", True)
        menu("mFile/mClose", "&Close", "close.png")
        action("mFile/mClose/aCurrent", "&Close", "close.png", "Ctrl+W",
               "Close the current file", False)
        action("mFile/mClose/aAll", "Close &All", "closeall.png",
               'Shift+Ctrl+W', "Close all files", False)
        menu("mFile/mFileSystem", "File System", "filesystem.png")
        action("mFile/mFileSystem/aRename", "Rename", "edit.png", '',
               "Rename current file", False)
        if platform.system() != 'Windows':
            action("mFile/mFileSystem/aToggleExecutable", "Make executable",
                   "", '', "Toggle executable mode", False)
        separator("mFile")
        action("mFile/aQuit", "Quit", "quit.png", 'Ctrl+Q', "Quit", True)
        separator("mFile")

        menu("mView", "View", "")
        action("mView/aShowIncorrectIndentation", "Show incorrect indentation",
               "", "", "", False, True)
        action("mView/aShowAnyWhitespaces", "Show any whitespace", "", "", "",
               False, True)
        separator("mView")
        action("mView/aHideAll", "Hide all / Restore", "", "Shift+Esc",
               "Hide all widgets", True)
        action("mView/aOpenMainMenu", "Open main menu", "", "F10", "", True)
        separator("mView")

        menu("mEdit", "Edit", "")
        action("mEdit/aStripTrailingWhitespace",
               "Strip trailing whitespace when saving", "", "", "", True, True)
        separator("mEdit")
        menu("mEdit/mCopyPasteLines", "Copy-paste lines", "")
        menu("mEdit/mIndentation", "Indentation", "")
        separator("mEdit")
        action("mEdit/aEnableVimMode", "Enable Vim mode", "", "", "", False,
               True)

        menu("mNavigation", "Navigation", "")
        action("mNavigation/aFocusCurrentDocument", "Focus to editor",
               "text.png", "Ctrl+Return", "Focus current document", False)

        menu("mNavigation/mSearchReplace", "&Search && Replace",
             "search-replace-directory.png")
        menu("mNavigation/mBookmarks", "&Bookmarks", "bookmark.png")

        separator("mNavigation"),
        action("mNavigation/aNext", "&Next file", "next.png", "Ctrl+PgDown",
               "Next file", False)
        action("mNavigation/aPrevious", "&Previous file", "previous.png",
               "Ctrl+PgUp", "Previous file", False)
        separator("mNavigation")
        action("mNavigation/aGoto", "Go go line...", "goto.png", "Ctrl+G",
               "Go to line...", False)
        menu("mNavigation/mFileBrowser",
             "File browser",
             ':/enkiicons/open.png',
             visible=False)
        menu("mNavigation/mScroll", "Scroll file", '')

        menu("mSettings", "Settings", "")

        menu("mTools", "Tools", "")
        menu("mHelp", "Help", "")

    @pyqtSlot()
    def _openMainMenu(self):
        fileMenu = core.actionManager().menu('mFile')
        self._menuBar.setActiveAction(fileMenu.menuAction())

    def menuBar(self):
        """Reference to menuBar
        """
        return self._menuBar

    def topToolBar(self):
        """Top tool bar. Contains main menu, position indicator, etc
        """
        return self._topToolBar

    def statusBar(self):
        """Return main window status bar.
        It is located on the top tool bar
        """
        return self._statusBar

    def setWorkspace(self, workspace):
        """Set central widget of the main window.
        Normally called only by core when initializing system
        """
        self._centralLayout.addWidget(workspace)
        self.setFocusProxy(workspace)

    def defaultTitle(self):
        """Default title. Contains  name and version
        """
        return "%s v.%s" % (enki.core.defines.PACKAGE_NAME,
                            enki.core.defines.PACKAGE_VERSION)

    def centralLayout(self):
        """Layout of the central widget. Contains Workspace and search widget
        """
        return self._centralLayout

    def appendMessage(self, text, timeoutMs=10000):
        """Append message to the queue. It will be shown as non-modal at the bottom of the window.
        Use such notifications, which are too long or too important for status bar
        but, not so important, to interrupt an user with QMessageBox
        """
        if self._queuedMessageToolBar is None:
            self._initQueuedMessageToolBar()

        self._queuedMessageToolBar.appendMessage(text, timeoutMs)

    def closeEvent(self, event):
        """NOT A PUBLIC API
        Close event handler.
        Shows save files dialog. Cancels close, if dialog was rejected
        """

        # saving geometry BEFORE closing widgets, because state might be changed, when docks are closed
        self._saveState()
        self._saveGeometry()

        # request close all documents
        if not core.workspace().askToCloseAll():
            event.ignore()
            return

        core.aboutToTerminate.emit()
        self.hide()

        core.workspace().forceCloseAllDocuments()

        return QMainWindow.closeEvent(self, event)

    def onQuit(self):
        # saving geometry BEFORE closing widgets, because state might be changed, when docks are closed
        self._saveState()
        self._saveGeometry()

        # request close all documents
        if not core.workspace().askToCloseAll():
            return

        core.aboutToTerminate.emit()
        self.hide()

        core.workspace().forceCloseAllDocuments()

        return QApplication.quit()

    def _saveByteArray(self, path, title, data):
        """Load data, show error and return None if failed"""
        try:
            with open(path, 'wb') as f:
                f.write(data)
        except (OSError, IOError) as ex:
            error = str(ex)
            QMessageBox.critical(
                None, self.tr("Cannot save {}".format(title)),
                self.tr("Cannot create file '%s'\nError: %s" % (path, error)))
            return

    def _loadByteArray(self, path, title):
        """Load data, show error and return None if failed"""
        if os.path.exists(path):
            try:
                with open(path, 'rb') as f:
                    return f.read()
            except (OSError, IOError) as ex:
                error = str(ex)
                QMessageBox.critical(
                    None, self.tr("Cannot restore {}".format(title)),
                    self.tr("Cannot read file '%s'\nError: %s" %
                            (path, error)))

        return None

    def _saveState(self):
        """Save window state to main_window_state.bin file in the config directory
        """
        self._saveByteArray(self._STATE_FILE, "main window state",
                            self.saveState())

    def loadState(self):
        """Restore window state from main_window_state.bin and config.
        Called by the core after all plugins had been initialized
        """
        self._restoreGeometry()

        state = self._loadByteArray(self._STATE_FILE, "main window state")

        if state is not None:
            self.restoreState(state)
        else:  # no state, first start
            self.showMaximized()
            for dock in self.findChildren(DockWidget):
                dock.show()

    def _saveGeometry(self):
        """Save window geometry to the config file
        """
        self._saveByteArray(self._GEOMETRY_FILE, "main window geometry",
                            self.saveGeometry())

    def _restoreGeometry(self):
        """Restore window geometry to the config file
        """
        geometry = self._loadByteArray(self._GEOMETRY_FILE,
                                       "main window geometry")
        if geometry is not None:
            self.restoreGeometry(geometry)

    def sizeHint(self):
        return QSize(900, 560)

    def dragEnterEvent(self, event):
        """QMainWindow method reimplementation.
        Say, that we are ready to accept dragged urls
        """
        if event.mimeData().hasUrls():
            # accept drag
            event.acceptProposedAction()

        # default handler
        QMainWindow.dragEnterEvent(self, event)

    def dropEvent(self, event):
        """QMainWindow method reimplementation.
        Open dropt files
        """
        if event.mimeData().hasUrls():
            for url in event.mimeData().urls():
                localFile = url.toLocalFile()
                if os.path.isfile(localFile):
                    core.workspace().openFile(localFile)
                elif os.path.isdir(localFile):
                    self.directoryDropt.emit(localFile)

        # default handler
        QMainWindow.dropEvent(self, event)

    def addDockWidget(self, area, dock):
        pass  # not a plugin API method
        """Add dock widget to previous position, if known.
        Otherwise add to specified area
        """
        assert not dock in self._addedDockWidgets
        self._addedDockWidgets.append(dock)

        if not self.restoreDockWidget(dock):
            QMainWindow.addDockWidget(self, area, dock)
        """ Scroll view to make the cursor visible.
        Otherwise cursor can disappear from the viewport.
        QTimer is used because ensureCursorVisible works only after the dock has been drawn.
        A bad fix for #319
        """
        QTimer.singleShot(0, self._ensureCursorVisible)

    def _ensureCursorVisible(self):
        # When the timer fires, first check that there's still a workspace/document.
        if core.workspace() is not None:
            document = core.workspace().currentDocument()
            if document is not None:
                document.qutepart.ensureCursorVisible

    def removeDockWidget(self, dock):
        pass  # not a plugin API method
        """Remove dock widget"""
        assert dock in self._addedDockWidgets
        self._addedDockWidgets.remove(dock)
        QMainWindow.removeDockWidget(self, dock)

    def restoreState(self, state):
        pass  # not a plugin API method
        """Restore state shows widgets, which exist
        but shall not be installed on main window
        """
        QMainWindow.restoreState(self, state)
        for dock in self.findChildren(DockWidget):
            if not dock in self._addedDockWidgets:
                dock.hide()
示例#16
0
class SimulationGui(QMainWindow):
    """
    class for the graphical user interface
    """
    # TODO enable closing plot docks by right-clicking their name

    runSimulation = pyqtSignal()
    stopSimulation = pyqtSignal()
    playbackTimeChanged = pyqtSignal()
    regimeFinished = pyqtSignal()
    finishedRegimeBatch = pyqtSignal(bool)

    def __init__(self):
        # constructor of the base class
        QMainWindow.__init__(self)

        QCoreApplication.setOrganizationName("RST")
        QCoreApplication.setOrganizationDomain("https://tu-dresden.de/rst")
        QCoreApplication.setApplicationVersion(
            pkg_resources.require("PyMoskito")[0].version)
        QCoreApplication.setApplicationName(globals()["__package__"])

        # load settings
        self._settings = QSettings()
        self._read_settings()

        # initialize logger
        self._logger = logging.getLogger(self.__class__.__name__)

        # Create Simulation Backend
        self.guiProgress = None
        self.cmdProgress = None
        self.sim = SimulatorInteractor(self)
        self.runSimulation.connect(self.sim.run_simulation)
        self.stopSimulation.connect(self.sim.stop_simulation)
        self.sim.simulation_finalized.connect(self.new_simulation_data)
        self.currentDataset = None
        self.interpolator = None

        # sim setup viewer
        self.targetView = SimulatorView(self)
        self.targetView.setModel(self.sim.target_model)
        self.targetView.expanded.connect(self.target_view_changed)
        self.targetView.collapsed.connect(self.target_view_changed)

        # sim results viewer
        self.result_view = QTreeView()

        # the docking area allows to rearrange the user interface at runtime
        self.area = pg.dockarea.DockArea()

        # Window properties
        icon_size = QSize(25, 25)
        self.setCentralWidget(self.area)
        self.resize(1000, 700)
        self.setWindowTitle("PyMoskito")
        res_path = get_resource("mosquito.png")
        icon = QIcon(res_path)
        self.setWindowIcon(icon)

        # create docks
        self.propertyDock = pg.dockarea.Dock("Properties")
        self.animationDock = pg.dockarea.Dock("Animation")
        self.regimeDock = pg.dockarea.Dock("Regimes")
        self.dataDock = pg.dockarea.Dock("Data")
        self.logDock = pg.dockarea.Dock("Log")
        self.plotDockPlaceholder = pg.dockarea.Dock("Placeholder")

        # arrange docks
        self.area.addDock(self.animationDock, "right")
        self.area.addDock(self.regimeDock, "left", self.animationDock)
        self.area.addDock(self.propertyDock, "bottom", self.regimeDock)
        self.area.addDock(self.dataDock, "bottom", self.propertyDock)
        self.area.addDock(self.plotDockPlaceholder, "bottom",
                          self.animationDock)
        self.area.addDock(self.logDock, "bottom", self.dataDock)
        self.non_plotting_docks = list(self.area.findAll()[1].keys())

        # add widgets to the docks
        self.propertyDock.addWidget(self.targetView)

        if not vtk_available:
            self._logger.error(
                "loading vtk failed with:{}".format(vtk_error_msg))

        # check if there is a registered visualizer
        available_vis = get_registered_visualizers()
        self._logger.info("found visualizers: {}".format(
            [name for cls, name in available_vis]))
        if available_vis:
            # instantiate the first visualizer
            self._logger.info("loading visualizer '{}'".format(
                available_vis[0][1]))
            self.animationLayout = QVBoxLayout()

            if issubclass(available_vis[0][0], MplVisualizer):
                self.animationWidget = QWidget()
                self.visualizer = available_vis[0][0](self.animationWidget,
                                                      self.animationLayout)
                self.animationDock.addWidget(self.animationWidget)
            elif issubclass(available_vis[0][0], VtkVisualizer):
                if vtk_available:
                    # vtk window
                    self.animationFrame = QFrame()
                    self.vtkWidget = QVTKRenderWindowInteractor(
                        self.animationFrame)
                    self.animationLayout.addWidget(self.vtkWidget)
                    self.animationFrame.setLayout(self.animationLayout)
                    self.animationDock.addWidget(self.animationFrame)
                    self.vtk_renderer = vtkRenderer()
                    self.vtkWidget.GetRenderWindow().AddRenderer(
                        self.vtk_renderer)
                    self.visualizer = available_vis[0][0](self.vtk_renderer)
                    self.vtkWidget.Initialize()
                else:
                    self._logger.warning("visualizer depends on vtk which is "
                                         "not available on this system!")
            elif available_vis:
                raise NotImplementedError
        else:
            self.visualizer = None

        # regime window
        self.regime_list = QListWidget(self)
        self.regime_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.regimeDock.addWidget(self.regime_list)
        self.regime_list.itemDoubleClicked.connect(self.regime_dclicked)
        self._regimes = []
        self.regime_file_name = ""

        self.actDeleteRegimes = QAction(self.regime_list)
        self.actDeleteRegimes.setText("&Delete Selected Regimes")
        # TODO shortcut works always, not only with focus on the regime list
        # self.actDeleteRegimes.setShortcutContext(Qt.WindowShortcut)
        self.actDeleteRegimes.setShortcut(QKeySequence(Qt.Key_Delete))
        self.actDeleteRegimes.triggered.connect(self.remove_regime_items)

        self.actSave = QAction(self)
        self.actSave.setText('Save Results As')
        self.actSave.setIcon(QIcon(get_resource("save.png")))
        self.actSave.setDisabled(True)
        self.actSave.setShortcut(QKeySequence.Save)
        self.actSave.triggered.connect(self.export_simulation_data)

        self.actLoadRegimes = QAction(self)
        self.actLoadRegimes.setText("Load Regimes from File")
        self.actLoadRegimes.setIcon(QIcon(get_resource("load.png")))
        self.actLoadRegimes.setDisabled(False)
        self.actLoadRegimes.setShortcut(QKeySequence.Open)
        self.actLoadRegimes.triggered.connect(self.load_regime_dialog)

        self.actExitOnBatchCompletion = QAction(self)
        self.actExitOnBatchCompletion.setText("&Exit On Batch Completion")
        self.actExitOnBatchCompletion.setCheckable(True)
        self.actExitOnBatchCompletion.setChecked(
            self._settings.value("control/exit_on_batch_completion") == "True")
        self.actExitOnBatchCompletion.changed.connect(
            self.update_exit_on_batch_completion_setting)

        # regime management
        self.runningBatch = False
        self._current_regime_index = None
        self._current_regime_name = None
        self._regimes = []

        self.regimeFinished.connect(self.run_next_regime)
        self.finishedRegimeBatch.connect(self.regime_batch_finished)

        # data window
        self.dataList = QListWidget(self)
        self.dataDock.addWidget(self.dataList)
        self.dataList.itemDoubleClicked.connect(self.create_plot)

        # actions for simulation control
        self.actSimulateCurrent = QAction(self)
        self.actSimulateCurrent.setText("&Simulate Current Regime")
        self.actSimulateCurrent.setIcon(QIcon(get_resource("simulate.png")))
        self.actSimulateCurrent.setShortcut(QKeySequence("F5"))
        self.actSimulateCurrent.triggered.connect(self.start_simulation)

        self.actSimulateAll = QAction(self)
        self.actSimulateAll.setText("Simulate &All Regimes")
        self.actSimulateAll.setIcon(QIcon(get_resource("execute_regimes.png")))
        self.actSimulateAll.setShortcut(QKeySequence("F6"))
        self.actSimulateAll.setDisabled(True)
        self.actSimulateAll.triggered.connect(self.start_regime_execution)

        # actions for animation control
        self.actAutoPlay = QAction(self)
        self.actAutoPlay.setText("&Autoplay Simulation")
        self.actAutoPlay.setCheckable(True)
        self.actAutoPlay.setChecked(
            self._settings.value("control/autoplay_animation") == "True")
        self.actAutoPlay.changed.connect(self.update_autoplay_setting)

        self.actPlayPause = QAction(self)
        self.actPlayPause.setText("Play Animation")
        self.actPlayPause.setIcon(QIcon(get_resource("play.png")))
        self.actPlayPause.setDisabled(True)
        self.actPlayPause.setShortcut(QKeySequence(Qt.Key_Space))
        self.actPlayPause.triggered.connect(self.play_animation)

        self.actStop = QAction(self)
        self.actStop.setText("Stop")
        self.actStop.setIcon(QIcon(get_resource("stop.png")))
        self.actStop.setDisabled(True)
        self.actStop.triggered.connect(self.stop_animation)

        self.actSlow = QAction(self)
        self.actSlow.setText("Slowest")
        self.actSlow.setIcon(QIcon(get_resource("slow.png")))
        self.actSlow.setDisabled(False)
        self.actSlow.triggered.connect(self.set_slowest_playback_speed)

        self.actFast = QAction(self)
        self.actFast.setText("Fastest")
        self.actFast.setIcon(QIcon(get_resource("fast.png")))
        self.actFast.setDisabled(False)
        self.actFast.triggered.connect(self.set_fastest_playback_speed)

        self.speedControl = QSlider(Qt.Horizontal, self)
        self.speedControl.setMaximumSize(200, 25)
        self.speedControl.setTickPosition(QSlider.TicksBothSides)
        self.speedControl.setDisabled(False)
        self.speedControl.setMinimum(0)
        self.speedControl.setMaximum(12)
        self.speedControl.setValue(6)
        self.speedControl.setTickInterval(6)
        self.speedControl.setSingleStep(2)
        self.speedControl.setPageStep(3)
        self.speedControl.valueChanged.connect(self.update_playback_speed)

        self.timeSlider = QSlider(Qt.Horizontal, self)
        self.timeSlider.setMinimum(0)
        self.timeSliderRange = 1000
        self.timeSlider.setMaximum(self.timeSliderRange)
        self.timeSlider.setTickInterval(1)
        self.timeSlider.setTracking(True)
        self.timeSlider.setDisabled(True)
        self.timeSlider.valueChanged.connect(self.update_playback_time)

        self.playbackTime = .0
        self.playbackGain = 1
        self.currentStepSize = .0
        self.currentEndTime = .0
        self.playbackTimer = QTimer()
        self.playbackTimer.timeout.connect(self.increment_playback_time)
        self.playbackTimeChanged.connect(self.update_gui)
        self.playbackTimeout = 33  # in [ms] -> 30 fps

        self.actResetCamera = QAction(self)
        self.actResetCamera.setText("Reset Camera")
        self.actResetCamera.setIcon(QIcon(get_resource("reset_camera.png")))
        self.actResetCamera.setDisabled(True)
        if available_vis:
            self.actResetCamera.setEnabled(self.visualizer.can_reset_view)
        self.actResetCamera.triggered.connect(self.reset_camera_clicked)

        # postprocessing
        self.actPostprocessing = QAction(self)
        self.actPostprocessing.setText("Launch Postprocessor")
        self.actPostprocessing.setIcon(QIcon(get_resource("processing.png")))
        self.actPostprocessing.setDisabled(False)
        self.actPostprocessing.triggered.connect(self.postprocessing_clicked)
        self.actPostprocessing.setShortcut(QKeySequence("F7"))

        self.postprocessor = None

        # toolbar
        self.toolbarSim = QToolBar("Simulation")
        self.toolbarSim.setContextMenuPolicy(Qt.PreventContextMenu)
        self.toolbarSim.setMovable(False)
        self.toolbarSim.setIconSize(icon_size)
        self.addToolBar(self.toolbarSim)
        self.toolbarSim.addAction(self.actLoadRegimes)
        self.toolbarSim.addAction(self.actSave)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actSimulateCurrent)
        self.toolbarSim.addAction(self.actSimulateAll)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actPlayPause)
        self.toolbarSim.addAction(self.actStop)
        self.toolbarSim.addWidget(self.timeSlider)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actSlow)
        self.toolbarSim.addWidget(self.speedControl)
        self.toolbarSim.addAction(self.actFast)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actPostprocessing)
        self.toolbarSim.addAction(self.actResetCamera)
        self.postprocessor = None

        # log dock
        self.logBox = QPlainTextEdit(self)
        self.logBox.setReadOnly(True)
        self.logDock.addWidget(self.logBox)

        # init logger for logging box
        self.textLogger = PlainTextLogger(logging.INFO)
        self.textLogger.set_target_cb(self.logBox.appendPlainText)
        logging.getLogger().addHandler(self.textLogger)

        # menu bar
        fileMenu = self.menuBar().addMenu("&File")
        fileMenu.addAction(self.actLoadRegimes)
        fileMenu.addAction(self.actSave)
        fileMenu.addAction("&Quit", self.close)

        editMenu = self.menuBar().addMenu("&Edit")
        editMenu.addAction(self.actDeleteRegimes)

        simMenu = self.menuBar().addMenu("&Simulation")
        simMenu.addAction(self.actSimulateCurrent)
        simMenu.addAction(self.actSimulateAll)
        simMenu.addAction(self.actExitOnBatchCompletion)
        simMenu.addAction(self.actPostprocessing)

        animMenu = self.menuBar().addMenu("&Animation")
        animMenu.addAction(self.actPlayPause)
        animMenu.addAction("&Increase Playback Speed",
                           self.increment_playback_speed,
                           QKeySequence(Qt.CTRL + Qt.Key_Plus))
        animMenu.addAction("&Decrease Playback Speed",
                           self.decrement_playback_speed,
                           QKeySequence(Qt.CTRL + Qt.Key_Minus))
        animMenu.addAction("&Reset Playback Speed", self.reset_playback_speed,
                           QKeySequence(Qt.CTRL + Qt.Key_0))
        animMenu.addAction(self.actAutoPlay)
        animMenu.addAction(self.actResetCamera)

        helpMenu = self.menuBar().addMenu("&Help")
        helpMenu.addAction("&Online Documentation", self.show_online_docs)
        helpMenu.addAction("&About", self.show_info)

        # status bar
        self.status = QStatusBar(self)
        self.setStatusBar(self.status)
        self.statusLabel = QLabel("Ready.")
        self.statusBar().addPermanentWidget(self.statusLabel)
        self.timeLabel = QLabel("current time: 0.0")
        self.statusBar().addPermanentWidget(self.timeLabel)

        self._logger.info("Simulation GUI is up and running.")

    def _read_settings(self):

        # add default settings if none are present
        if not self._settings.contains("path/simulation_results"):
            self._settings.setValue(
                "path/simulation_results",
                os.path.join(os.path.curdir, "results", "simulation"))
        if not self._settings.contains("path/postprocessing_results"):
            self._settings.setValue(
                "path/postprocessing_results",
                os.path.join(os.path.curdir, "results", "postprocessing"))
        if not self._settings.contains("path/metaprocessing_results"):
            self._settings.setValue(
                "path/metaprocessing_results",
                os.path.join(os.path.curdir, "results", "metaprocessing"))

        if not self._settings.contains("control/autoplay_animation"):
            self._settings.setValue("control/autoplay_animation", "False")

        if not self._settings.contains("control/exit_on_batch_completion"):
            self._settings.setValue("control/exit_on_batch_completion",
                                    "False")

    def _write_settings(self):
        """ Store the application state. """
        pass

    @pyqtSlot()
    def update_autoplay_setting(self):
        self._settings.setValue("control/autoplay_animation",
                                str(self.actAutoPlay.isChecked()))

    @pyqtSlot()
    def update_exit_on_batch_completion_setting(self, state=None):
        if state is None:
            state = self.actExitOnBatchCompletion.isChecked()
        self._settings.setValue("control/exit_on_batch_completion", str(state))

    def set_visualizer(self, vis):
        self.visualizer = vis
        self.vtkWidget.Initialize()

    @pyqtSlot()
    def play_animation(self):
        """
        play the animation
        """
        self._logger.debug("Starting Playback")

        # if we are at the end, start from the beginning
        if self.playbackTime == self.currentEndTime:
            self.timeSlider.setValue(0)

        self.actPlayPause.setText("Pause Animation")
        self.actPlayPause.setIcon(QIcon(get_resource("pause.png")))
        self.actPlayPause.triggered.disconnect(self.play_animation)
        self.actPlayPause.triggered.connect(self.pause_animation)
        self.playbackTimer.start(self.playbackTimeout)

    @pyqtSlot()
    def pause_animation(self):
        """
        pause the animation
        """
        self._logger.debug("Pausing Playback")
        self.playbackTimer.stop()
        self.actPlayPause.setText("Play Animation")
        self.actPlayPause.setIcon(QIcon(get_resource("play.png")))
        self.actPlayPause.triggered.disconnect(self.pause_animation)
        self.actPlayPause.triggered.connect(self.play_animation)

    def stop_animation(self):
        """
        Stop the animation if it is running and reset the playback time.
        """
        self._logger.debug("Stopping Playback")
        if self.actPlayPause.text() == "Pause Animation":
            # animation is playing -> stop it
            self.playbackTimer.stop()
            self.actPlayPause.setText("Play Animation")
            self.actPlayPause.setIcon(QIcon(get_resource("play.png")))
            self.actPlayPause.triggered.disconnect(self.pause_animation)
            self.actPlayPause.triggered.connect(self.play_animation)

        self.timeSlider.setValue(0)

    @pyqtSlot()
    def start_simulation(self):
        """
        start the simulation and disable start button
        """
        if self._current_regime_index is None:
            regime_name = ""
        else:
            regime_name = str(
                self.regime_list.item(self._current_regime_index).text())

        self.statusLabel.setText("simulating {}".format(regime_name))
        self._logger.info("Simulating: {}".format(regime_name))

        self.actSimulateCurrent.setIcon(
            QIcon(get_resource("stop_simulation.png")))
        self.actSimulateCurrent.setText("Abort &Simulation")
        self.actSimulateCurrent.triggered.disconnect(self.start_simulation)
        self.actSimulateCurrent.triggered.connect(self.stop_simulation)

        if not self.runningBatch:
            self.actSimulateAll.setDisabled(True)

        self.guiProgress = QProgressBar(self)
        self.sim.simulationProgressChanged.connect(self.guiProgress.setValue)
        self.statusBar().addWidget(self.guiProgress)
        self.runSimulation.emit()

    @pyqtSlot()
    def stop_simulation(self):
        self.stopSimulation.emit()

    def export_simulation_data(self, ok):
        """
        Query the user for a custom name and export the current simulation
        results.

        :param ok: unused parameter from QAction.triggered() Signal
        """
        self._save_data()

    def _save_data(self, file_path=None):
        """
        Save the current simulation results.

        If *fie_name* is given, the result will be saved to the specified
        location, making automated exporting easier.

        Args:
            file_path(str): Absolute path of the target file. If `None` the
                use will be asked for a storage location.
        """
        regime_name = self._regimes[self._current_regime_index]["Name"]

        if file_path is None:
            # get default path
            path = self._settings.value("path/simulation_results")

            # create canonic file name
            suggestion = self._simfile_name(regime_name)
        else:
            path = os.path.dirname(file_path)
            suggestion = os.path.basename(file_path)

        # check if path exists otherwise create it
        if not os.path.isdir(path):
            box = QMessageBox()
            box.setText("Export Folder does not exist yet.")
            box.setInformativeText("Do you want to create it? \n"
                                   "{}".format(os.path.abspath(path)))
            box.setStandardButtons(QMessageBox.Ok | QMessageBox.No)
            box.setDefaultButton(QMessageBox.Ok)
            ret = box.exec_()
            if ret == QMessageBox.Ok:
                os.makedirs(path)
            else:
                path = os.path.abspath(os.path.curdir)
                file_path = None

        # If no path was given, present the default and let the user choose
        if file_path is None:
            dialog = QFileDialog(self)
            dialog.setAcceptMode(QFileDialog.AcceptSave)
            dialog.setFileMode(QFileDialog.AnyFile)
            dialog.setDirectory(path)
            dialog.setNameFilter("PyMoskito Results (*.pmr)")
            dialog.selectFile(suggestion)

            if dialog.exec_():
                file_path = dialog.selectedFiles()[0]
            else:
                self._logger.warning("Export Aborted")
                return -1

        # ask whether this should act as new default
        path = os.path.abspath(os.path.dirname(file_path))
        if path != self._settings.value("path/simulation_results"):
            box = QMessageBox()
            box.setText("Use this path as new default?")
            box.setInformativeText("{}".format(path))
            box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            box.setDefaultButton(QMessageBox.Yes)
            ret = box.exec_()
            if ret == QMessageBox.Yes:
                self._settings.setValue("path/simulation_results", path)

        self.currentDataset.update({"regime name": regime_name})
        with open(file_path, "wb") as f:
            pickle.dump(self.currentDataset, f, protocol=4)

        self.statusLabel.setText("results saved to {}".format(file_path))
        self._logger.info("results saved to {}".format(file_path))

    def _simfile_name(self, regime_name):
        """ Create a canonical name for a simulation result file
        """
        suggestion = (time.strftime("%Y%m%d-%H%M%S") + "_" + regime_name +
                      ".pmr")
        return suggestion

    def load_regime_dialog(self):
        regime_path = os.path.join(os.curdir)

        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setDirectory(regime_path)
        dialog.setNameFilter("Simulation Regime files (*.sreg)")

        if dialog.exec_():
            file = dialog.selectedFiles()[0]
            self.load_regimes_from_file(file)

    def load_regimes_from_file(self, file_name):
        """
        load simulation regime from file
        :param file_name:
        """
        self.regime_file_name = os.path.split(file_name)[-1][:-5]
        self._logger.info("loading regime file: {0}".format(
            self.regime_file_name))
        with open(file_name.encode(), "r") as f:
            self._regimes += yaml.load(f)

        self._update_regime_list()

        if self._regimes:
            self.actSimulateAll.setDisabled(False)

        self._logger.info("loaded {} regimes".format(len(self._regimes)))
        self.statusBar().showMessage(
            "loaded {} regimes.".format(len(self._regimes)), 1000)
        return

    def _update_regime_list(self):
        self.regime_list.clear()
        for reg in self._regimes:
            self._logger.debug("adding '{}' to regime list".format(
                reg["Name"]))
            self.regime_list.addItem(reg["Name"])

    def remove_regime_items(self):
        if self.regime_list.currentRow() >= 0:
            # flag all selected files as invalid
            items = self.regime_list.selectedItems()
            for item in items:
                del self._regimes[self.regime_list.row(item)]
                self.regime_list.takeItem(self.regime_list.row(item))

    @pyqtSlot(QListWidgetItem)
    def regime_dclicked(self, item):
        """
        Apply the selected regime to the current target.
        """
        self.apply_regime_by_name(str(item.text()))

    def apply_regime_by_name(self, regime_name):
        """
        Apply the regime given by `regime_name` und update the regime index.

        Returns:
            bool: `True` if successful, `False` if errors occurred.
        """
        # get regime idx
        try:
            idx = list(map(itemgetter("Name"),
                           self._regimes)).index(regime_name)
        except ValueError as e:
            self._logger.error(
                "apply_regime_by_name(): Error no regime called "
                "'{0}'".format(regime_name))
            return False

        # apply
        return self._apply_regime_by_idx(idx)

    def _apply_regime_by_idx(self, index=0):
        """
        Apply the given regime.

        Args:
            index(int): Index of the regime in the `RegimeList` .

        Returns:
            bool: `True` if successful, `False` if errors occurred.
        """
        if index >= len(self._regimes):
            self._logger.error("applyRegime: index error! ({})".format(index))
            return False

        reg_name = self._regimes[index]["Name"]
        self.statusBar().showMessage("regime {} applied.".format(reg_name),
                                     1000)
        self._logger.info("applying regime '{}'".format(reg_name))

        self._current_regime_index = index
        self._current_regime_name = reg_name

        return self.sim.set_regime(self._regimes[index])

    @pyqtSlot()
    def start_regime_execution(self):
        """
        Simulate all regimes in the regime list.
        """
        self.actSimulateAll.setText("Stop Simulating &All Regimes")
        self.actSimulateAll.setIcon(QIcon(get_resource("stop_batch.png")))
        self.actSimulateAll.triggered.disconnect(self.start_regime_execution)
        self.actSimulateAll.triggered.connect(self.stop_regime_excecution)

        self.runningBatch = True
        self._current_regime_index = -1
        self.regimeFinished.emit()

    def run_next_regime(self):
        """
        Execute the next regime in the regime batch.
        """
        # are we finished?
        if self._current_regime_index == len(self._regimes) - 1:
            self.finishedRegimeBatch.emit(True)
            return

        suc = self._apply_regime_by_idx(self._current_regime_index + 1)
        if not suc:
            self.finishedRegimeBatch.emit(False)
            return

        self.start_simulation()

    @pyqtSlot()
    def stop_regime_excecution(self):
        """ Stop the batch process.
        """
        self.stopSimulation.emit()
        self.finishedRegimeBatch.emit(False)

    def regime_batch_finished(self, status):
        self.runningBatch = False
        self.actSimulateAll.setDisabled(False)
        self.actSave.setDisabled(True)

        self.actSimulateAll.setText("Simulate &All Regimes")
        self.actSimulateAll.setIcon(QIcon(get_resource("execute_regimes.png")))
        self.actSimulateAll.triggered.disconnect(self.stop_regime_excecution)
        self.actSimulateAll.triggered.connect(self.start_regime_execution)

        if status:
            self.statusLabel.setText("All regimes have been simulated")
            self._logger.info("All Regimes have been simulated")
        else:
            self._logger.error("Batch simulation has been aborted")

        if self._settings.value("control/exit_on_batch_completion") == "True":
            self._logger.info("Shutting down SimulationGUI")
            self.close()

    @pyqtSlot(str, dict, name="new_simulation_data")
    def new_simulation_data(self, status, data):
        """
        Slot to be called when the simulation interface has completed the
        current job and new data is available.

        Args:
            status (str): Status of the simulation, either
                - `finished` : Simulation has been finished successfully or
                - `failed` : Simulation has failed.
            data (dict): Dictionary, holding the simulation data.
        """
        self._logger.info("Simulation {}".format(status))
        self.statusLabel.setText("Simulation {}".format(status))

        self.actSimulateCurrent.setText("&Simulate Current Regime")
        self.actSimulateCurrent.setIcon(QIcon(get_resource("simulate.png")))
        self.actSimulateCurrent.triggered.disconnect(self.stop_simulation)
        self.actSimulateCurrent.triggered.connect(self.start_simulation)

        self.actPlayPause.setDisabled(False)
        self.actStop.setDisabled(False)
        self.actSave.setDisabled(False)
        self.speedControl.setDisabled(False)
        self.timeSlider.setDisabled(False)

        self.sim.simulationProgressChanged.disconnect(
            self.guiProgress.setValue)
        self.statusBar().removeWidget(self.guiProgress)

        self.stop_animation()

        self.currentDataset = data
        if data:
            self._read_results()
            self._update_data_list()
            self._update_plots()

        if self._settings.value("control/autoplay_animation") == "True":
            self.actPlayPause.trigger()

        if self.runningBatch:
            regime_name = self._regimes[self._current_regime_index]["Name"]
            file_name = self._simfile_name(regime_name)
            self._save_data(
                os.path.join(self._settings.value("path/simulation_results"),
                             file_name))
            self.regimeFinished.emit()
        else:
            self.actSimulateAll.setDisabled(False)

    def _read_results(self):
        state = self.currentDataset["results"]["Solver"]
        self.interpolator = interp1d(self.currentDataset["results"]["time"],
                                     state,
                                     axis=0,
                                     bounds_error=False,
                                     fill_value=(state[0], state[-1]))
        self.currentStepSize = 1.0 / self.currentDataset["simulation"][
            "measure rate"]
        self.currentEndTime = self.currentDataset["simulation"]["end time"]
        self.validData = True

    def increment_playback_speed(self):
        self.speedControl.setValue(self.speedControl.value() +
                                   self.speedControl.singleStep())

    def decrement_playback_speed(self):
        self.speedControl.setValue(self.speedControl.value() -
                                   self.speedControl.singleStep())

    def reset_playback_speed(self):
        self.speedControl.setValue(
            (self.speedControl.maximum() - self.speedControl.minimum()) / 2)

    def set_slowest_playback_speed(self):
        self.speedControl.setValue(self.speedControl.minimum())

    def set_fastest_playback_speed(self):
        self.speedControl.setValue(self.speedControl.maximum())

    def update_playback_speed(self, val):
        """
        adjust playback time to slider value

        :param val:
        """
        maximum = self.speedControl.maximum()
        self.playbackGain = 10**(3.0 * (val - maximum / 2) / maximum)

    @pyqtSlot()
    def increment_playback_time(self):
        """
        go one time step forward in playback
        """
        if self.playbackTime == self.currentEndTime:
            self.pause_animation()
            return

        increment = self.playbackGain * self.playbackTimeout / 1000
        self.playbackTime = min(self.currentEndTime,
                                self.playbackTime + increment)
        pos = int(self.playbackTime / self.currentEndTime *
                  self.timeSliderRange)
        self.timeSlider.blockSignals(True)
        self.timeSlider.setValue(pos)
        self.timeSlider.blockSignals(False)
        self.playbackTimeChanged.emit()

    def update_playback_time(self):
        """
        adjust playback time to slider value
        """
        self.playbackTime = self.timeSlider.value(
        ) / self.timeSliderRange * self.currentEndTime
        self.playbackTimeChanged.emit()
        return

    def update_gui(self):
        """
        updates the graphical user interface, including:
            - timestamp
            - visualisation
            - time cursor in diagrams
        """
        if not self.validData:
            return

        self.timeLabel.setText("current time: %4f" % self.playbackTime)

        # update time cursor in plots
        self._update_time_cursors()

        # update state of rendering
        if self.visualizer:
            state = self.interpolator(self.playbackTime)
            self.visualizer.update_scene(state)
            if isinstance(self.visualizer, MplVisualizer):
                pass
            elif isinstance(self.visualizer, VtkVisualizer):
                self.vtkWidget.GetRenderWindow().Render()

    def _update_data_list(self):
        self.dataList.clear()
        for module_name, results in self.currentDataset["results"].items():
            if not isinstance(results, np.ndarray):
                continue
            if len(results.shape) == 1:
                self.dataList.insertItem(0, module_name)
            elif len(results.shape) == 2:
                for col in range(results.shape[1]):
                    self.dataList.insertItem(
                        0, self._build_entry_name(module_name, (col, )))
            elif len(results.shape) == 3:
                for col in range(results.shape[1]):
                    for der in range(results.shape[2]):
                        self.dataList.insertItem(
                            0, self._build_entry_name(module_name, (col, der)))

    def _build_entry_name(self, module_name, idx):
        """
        Construct an identifier for a given entry of a module.
        Args:
            module_name (str): name of the module the entry belongs to.
            idx (tuple): Index of the entry.

        Returns:
            str: Identifier to use for display.
        """
        # save the user from defining 1d entries via tuples
        if len(idx) == 1:
            m_idx = idx[0]
        else:
            m_idx = idx

        mod_settings = self.currentDataset["modules"]
        info = mod_settings.get(module_name, {}).get("output_info", None)
        if info:
            if m_idx in info:
                return ".".join([module_name, info[m_idx]["Name"]])

        return ".".join([module_name] + [str(i) for i in idx])

    def _get_index_from_suffix(self, module_name, suffix):
        info = self.currentDataset["modules"].get(module_name,
                                                  {}).get("output_info", None)
        idx = next((i for i in info if info[i]["Name"] == suffix), None)
        return idx

    def _get_units(self, entry):
        """
        Return the unit that corresponds to a given entry.

        If no information is available, None is returned.

        Args:
            entry (str): Name of the entry. This can either be "Model.a.b" where
                a and b are numbers or if information is available "Model.Signal"
                where signal is the name of that part.

        Returns:

        """
        args = entry.split(".")
        module_name = args.pop(0)
        info = self.currentDataset["modules"].get(module_name,
                                                  {}).get("output_info", None)
        if info is None:
            return None

        if len(args) == 1:
            try:
                idx = int(args[0])
            except ValueError:
                idx = next((i for i in info if info[i]["Name"] == args[0]),
                           None)
        else:
            idx = (int(a) for a in args)

        return info[idx]["Unit"]

    def create_plot(self, item):
        """
        Creates a plot widget based on the given item.

        If a plot for this item is already open no new plot is created but the
        existing one is raised up again.

        Args:
            item(Qt.ListItem): Item to plot.
        """
        title = str(item.text())
        if title in self.non_plotting_docks:
            self._logger.error("Title '{}' not allowed for a plot window since"
                               "it would shadow on of the reserved "
                               "names".format(title))

        # check if plot has already been opened
        if title in self.area.findAll()[1]:
            self.area.docks[title].raiseDock()
            return

        # collect data
        data = self._get_data_by_name(title)
        t = self.currentDataset["results"]["time"]
        unit = self._get_units(title)
        if "." in title:
            name = title.split(".")[1]
        else:
            name = title

        # create plot widget
        widget = pg.PlotWidget(title=title)
        widget.showGrid(True, True)
        widget.plot(x=t, y=data)
        widget.getPlotItem().getAxis("bottom").setLabel(text="Time", units="s")
        widget.getPlotItem().getAxis("left").setLabel(text=name, units=unit)

        # add a time line
        time_line = pg.InfiniteLine(self.playbackTime,
                                    angle=90,
                                    movable=False,
                                    pen=pg.mkPen("#FF0000", width=2.0))
        widget.getPlotItem().addItem(time_line)

        # create dock container and add it to dock area
        dock = pg.dockarea.Dock(title, closable=True)
        dock.addWidget(widget)
        self.area.addDock(dock, "above", self.plotDockPlaceholder)

    def _get_data_by_name(self, name):
        tmp = name.split(".")
        module_name = tmp[0]
        if len(tmp) == 1:
            data = np.array(self.currentDataset["results"][module_name])
        elif len(tmp) == 2:
            try:
                idx = int(tmp[1])
            except ValueError:
                idx = self._get_index_from_suffix(module_name, tmp[1])
            finally:
                data = self.currentDataset["results"][module_name][..., idx]
        elif len(tmp) == 3:
            idx = int(tmp[1])
            der = int(tmp[2])
            data = self.currentDataset["results"][module_name][..., idx, der]
        else:
            raise ValueError("Format not supported")

        return data

    def _update_time_cursors(self):
        """
        Update the time lines of all plot windows
        """
        for title, dock in self.area.findAll()[1].items():
            if title in self.non_plotting_docks:
                continue
            for widget in dock.widgets:
                for item in widget.getPlotItem().items:
                    if isinstance(item, pg.InfiniteLine):
                        item.setValue(self.playbackTime)

    def _update_plots(self):
        """
        Update the data in all plot windows
        """
        for title, dock in self.area.findAll()[1].items():
            if title in self.non_plotting_docks:
                continue

            if not self.dataList.findItems(dock.name(), Qt.MatchExactly):
                # no data for this plot -> remove it
                dock.close()
                continue

            for widget in dock.widgets:
                for item in widget.getPlotItem().items:
                    if isinstance(item, pg.PlotDataItem):
                        x_data = self.currentDataset["results"]["time"]
                        y_data = self._get_data_by_name(dock.name())
                        item.setData(x=x_data, y=y_data)

    @pyqtSlot(QModelIndex)
    def target_view_changed(self, index):
        self.targetView.resizeColumnToContents(0)

    def postprocessing_clicked(self):
        """
        starts the post- and metaprocessing application
        """
        self._logger.info("launching postprocessor")
        self.statusBar().showMessage("launching postprocessor", 1000)
        if self.postprocessor is None:
            self.postprocessor = PostProcessor()

        self.postprocessor.show()

    def reset_camera_clicked(self):
        """
        reset camera in vtk window
        """
        self.visualizer.reset_camera()
        self.vtkWidget.GetRenderWindow().Render()

    def show_info(self):
        icon_lic = open(get_resource("license.txt"), "r").read()
        text = "This application was build using PyMoskito ver. {} .<br />" \
               "PyMoskito is free software distributed under GPLv3. <br />" \
               "It is developed by members of the " \
               "<a href=\'https://tu-dresden.de/ing/elektrotechnik/rst'>" \
               "Institute of Control Theory</a>" \
               " at the <a href=\'https://tu-dresden.de'>" \
               "Dresden University of Technology</a>. <br />" \
               "".format(pkg_resources.require("PyMoskito")[0].version) \
               + "<br />" + icon_lic
        box = QMessageBox.about(self, "PyMoskito", text)

    def show_online_docs(self):
        webbrowser.open("https://pymoskito.readthedocs.org")

    def closeEvent(self, QCloseEvent):
        self._logger.info("Close Event received, shutting down.")
        logging.getLogger().removeHandler(self.textLogger)
        super().closeEvent(QCloseEvent)
示例#17
0
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        
        self.webView = QWebView(self)
        self.webView.settings().setAttribute(self.webView.settings().globalSettings().DeveloperExtrasEnabled, True)
        self.webView.settings().setUserStyleSheetUrl(QUrl.fromUserInput(os.path.join(app_folder, "style.css")))
        self.webView.loadFinished.connect(self.jsHack)
        self.setCentralWidget(self.webView)
        
        # Main toolbar
        self.toolBar = QToolBar(self)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.addToolBar(Qt.LeftToolBarArea, self.toolBar)
        
        page = self.webView.page()

        backAction = page.action(page.Back)
        backAction.setShortcut("Alt+Left")
        self.toolBar.addAction(backAction)
        
        nextAction = page.action(page.Forward)
        nextAction.setShortcut("Alt+Right")
        self.toolBar.addAction(nextAction)
        
        reloadAction = page.action(page.Reload)
        reloadAction.setShortcuts(["Ctrl+R", "F5"])
        self.toolBar.addAction(reloadAction)
        
        stopAction = page.action(page.Stop)
        stopAction.setShortcut("Esc")
        self.toolBar.addAction(stopAction)
        
        self.toolBar.addSeparator()

        style = QApplication.style()

        self.uploadAction = QAction(self, text="Upload", icon=style.standardIcon(style.SP_ArrowUp))
        self.uploadAction.setShortcut("Alt+Up")
        self.uploadAction.triggered.connect(self.upload)
        self.toolBar.addAction(self.uploadAction)

        self.setGitHubSiteAction = QAction(self, text="Set Page", icon=style.standardIcon(style.SP_FileIcon))
        self.setGitHubSiteAction.setShortcut("Ctrl+L")
        self.setGitHubSiteAction.triggered.connect(self.setGitHubSite)
        self.toolBar.addAction(self.setGitHubSiteAction)

        self.setGitDirectoryAction = QAction(self, text="Set Directory", icon=style.standardIcon(style.SP_DirIcon))
        self.setGitDirectoryAction.setShortcut("Ctrl+O")
        self.setGitDirectoryAction.triggered.connect(self.setGitDirectory)
        self.toolBar.addAction(self.setGitDirectoryAction)
        
        self.webView.load(QUrl.fromUserInput(settings.value("settings/GitUrl")))

    def setGitHubSite(self):
        url = QInputDialog.getText(self, "Githost", "Enter the URL of your project page here:")
        if url[1]:
            settings.setValue("settings/GitUrl", url[0])
            self.webView.load(QUrl.fromUserInput(settings.value("settings/GitUrl")))
            settings.sync()

    def setGitDirectory(self):
        gitRepo = QFileDialog.getExistingDirectory(self, "Select directory...", os.path.expanduser("~"))
        if not os.path.isdir(gitRepo):
            pass
        else:
            settings.setValue("settings/GitRepo", gitRepo)
            settings.sync()

    def upload(self):
        if not settings.value("settings/GitRepo"):
            QMessageBox.information(self, "Githost", "Please select the directory of your Git repository.")
            self.setGitDirectory()
        repo = settings.value("settings/GitRepo")
        if repo:
            fnames = QFileDialog.getOpenFileNames(self, "Select files to upload...", os.path.expanduser("~"), "All files (*)")
            if type(fnames) is tuple:
                fnames = fnames[0]
            if not settings.value("settings/NoPromptForGitRepo") and len(fnames) > 0:
                confirm = QMessageBox.question(self, "Confirm selection", "Commit files to repository?", QMessageBox.Yes | QMessageBox.YesToAll | QMessageBox.No)
            else:
                confirm = QMessageBox.Yes
            if confirm == QMessageBox.YesToAll:
                settings.setValue("settings/NoPromptForGitRepo", True)
            if len(fnames) > 0 and confirm in (QMessageBox.Yes, QMessageBox.YesToAll):
                for fname in fnames:
                    os.system("cp %s %s" % (fname, repo))
                os.system("cd %s && git add . && git commit -m \"Added %s new file%s.\"" % (repo, len(fnames), ("s" if len(fnames) > 1 else "")))
                os.system("cd %s && xterm -e \"git push --all\" &" % (repo,))

    def jsHack(self):
        self.webView.page().mainFrame().evaluateJavaScript("""String.prototype.endsWith = function(suffix) {
        return this.indexOf(suffix, this.length - suffix.length) !== -1;
        };
        
        contents = document.getElementsByClassName("content");
        links = document.getElementsByClassName("js-directory-link");
        for(i=0; i<contents.length;i++) {
            br = document.createElement("br");
            contents[i+1].appendChild(br);
            imgLink = document.location.href.replace("github.com", "raw.githubusercontent.com") + "/master/" + links[i].innerHTML;
            input = document.createElement("input");
            input.setAttribute("style", "width: 100%;");
            lowerLink = imgLink.toLowerCase();
            if (lowerLink.endsWith(".jpg") || lowerLink.endsWith(".jpeg") || lowerLink.endsWith(".png") || lowerLink.endsWith(".gif") || lowerLink.endsWith(".mng") || lowerLink.endsWith(".apng") || lowerLink.endsWith(".webp")) {
                input.setAttribute("value", "[IMG]" + imgLink + "[/IMG]");
            }
            else {
                input.setAttribute("value", "[URL]" + imgLink + "[/URL]");
            }
            contents[i+1].appendChild(input);
        }""")
class UploadWindowUI(object):

    title = "DERIVA File Uploader"

    def __init__(self, MainWin):

        # Main Window
        MainWin.setObjectName("UploadWindow")
        MainWin.setWindowTitle(MainWin.tr(self.title))
        MainWin.resize(1024, 768)
        self.centralWidget = QWidget(MainWin)
        self.centralWidget.setObjectName("centralWidget")
        MainWin.setCentralWidget(self.centralWidget)
        self.verticalLayout = QVBoxLayout(self.centralWidget)
        self.verticalLayout.setContentsMargins(11, 11, 11, 11)
        self.verticalLayout.setSpacing(6)
        self.verticalLayout.setObjectName("verticalLayout")

        self.horizontalLayout = QHBoxLayout()
        self.pathLabel = QLabel("Directory:")
        self.horizontalLayout.addWidget(self.pathLabel)
        self.pathTextBox = QLineEdit()
        self.pathTextBox.setReadOnly(True)
        self.horizontalLayout.addWidget(self.pathTextBox)
        self.browseButton = QPushButton("Browse", self.centralWidget)
        self.browseButton.clicked.connect(MainWin.on_actionBrowse_triggered)
        self.horizontalLayout.addWidget(self.browseButton)
        self.verticalLayout.addLayout(self.horizontalLayout)

        # Splitter for Upload list/Log
        self.splitter = QSplitter(Qt.Vertical)

        # Table View (Upload list)
        self.uploadList = TableWidget(self.centralWidget)
        self.uploadList.setObjectName("uploadList")
        self.uploadList.setStyleSheet(
            """
            QTableWidget {
                    border: 2px solid grey;
                    border-radius: 5px;
            }
            """)
        self.uploadList.setEditTriggers(QAbstractItemView.NoEditTriggers)  # use NoEditTriggers to disable editing
        self.uploadList.setAlternatingRowColors(True)
        self.uploadList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.uploadList.setSelectionMode(QAbstractItemView.NoSelection)
        self.uploadList.verticalHeader().setDefaultSectionSize(18)  # tighten up the row size
        self.uploadList.horizontalHeader().setStretchLastSection(True)
        self.uploadList.setSortingEnabled(True)  # allow sorting
        self.splitter.addWidget(self.uploadList)

        # Log Widget
        self.logTextBrowser = QPlainTextEditLogger(self.centralWidget)
        self.logTextBrowser.widget.setObjectName("logTextBrowser")
        self.logTextBrowser.widget.setStyleSheet(
            """
            QPlainTextEdit {
                    border: 2px solid grey;
                    border-radius: 5px;
                    background-color: lightgray;
            }
            """)
        self.splitter.addWidget(self.logTextBrowser.widget)

        # add splitter
        self.splitter.setSizes([400, 200])
        self.verticalLayout.addWidget(self.splitter)

    # Actions

        # Browse
        self.actionBrowse = QAction(MainWin)
        self.actionBrowse.setObjectName("actionBrowse")
        self.actionBrowse.setText(MainWin.tr("Browse"))
        self.actionBrowse.setToolTip(MainWin.tr("Set the upload directory"))
        self.actionBrowse.setShortcut(MainWin.tr("Ctrl+B"))

        # Upload
        self.actionUpload = QAction(MainWin)
        self.actionUpload.setObjectName("actionUpload")
        self.actionUpload.setText(MainWin.tr("Upload"))
        self.actionUpload.setToolTip(MainWin.tr("Upload files"))
        self.actionUpload.setShortcut(MainWin.tr("Ctrl+L"))
        self.actionUpload.setEnabled(False)

        # Rescan
        self.actionRescan = QAction(MainWin)
        self.actionRescan.setObjectName("actionRescan")
        self.actionRescan.setText(MainWin.tr("Rescan"))
        self.actionRescan.setToolTip(MainWin.tr("Rescan the upload directory"))
        self.actionRescan.setShortcut(MainWin.tr("Ctrl+R"))
        self.actionRescan.setEnabled(False)

        # Cancel
        self.actionCancel = QAction(MainWin)
        self.actionCancel.setObjectName("actionCancel")
        self.actionCancel.setText(MainWin.tr("Cancel"))
        self.actionCancel.setToolTip(MainWin.tr("Cancel any upload(s) in-progress"))
        self.actionCancel.setShortcut(MainWin.tr("Ctrl+C"))

        # Options
        self.actionOptions = QAction(MainWin)
        self.actionOptions.setObjectName("actionOptions")
        self.actionOptions.setText(MainWin.tr("Options"))
        self.actionOptions.setToolTip(MainWin.tr("Configuration Options"))
        self.actionOptions.setShortcut(MainWin.tr("Ctrl+P"))

        # Login
        self.actionLogin = QAction(MainWin)
        self.actionLogin.setObjectName("actionLogin")
        self.actionLogin.setText(MainWin.tr("Login"))
        self.actionLogin.setToolTip(MainWin.tr("Login to the server"))
        self.actionLogin.setShortcut(MainWin.tr("Ctrl+G"))
        self.actionLogin.setEnabled(False)

        # Logout
        self.actionLogout = QAction(MainWin)
        self.actionLogout.setObjectName("actionLogout")
        self.actionLogout.setText(MainWin.tr("Logout"))
        self.actionLogout.setToolTip(MainWin.tr("Logout of the server"))
        self.actionLogout.setShortcut(MainWin.tr("Ctrl+O"))
        self.actionLogout.setEnabled(False)

        # Exit
        self.actionExit = QAction(MainWin)
        self.actionExit.setObjectName("actionExit")
        self.actionExit.setText(MainWin.tr("Exit"))
        self.actionExit.setToolTip(MainWin.tr("Exit the application"))
        self.actionExit.setShortcut(MainWin.tr("Ctrl+Z"))

        # Help
        self.actionHelp = QAction(MainWin)
        self.actionHelp.setObjectName("actionHelp")
        self.actionHelp.setText(MainWin.tr("Help"))
        self.actionHelp.setToolTip(MainWin.tr("Help"))
        self.actionHelp.setShortcut(MainWin.tr("Ctrl+H"))

    # Menu Bar

        """
        self.menuBar = QMenuBar(MainWin)
        self.menuBar.setObjectName("menuBar")
        MainWin.setMenuBar(self.menuBar)
        self.menuBar.setStyleSheet(
            "QMenuBar{font-family: Arial;font-style: normal;font-size: 10pt;font-weight: bold;};")
        """

    # Tool Bar

        self.mainToolBar = QToolBar(MainWin)
        self.mainToolBar.setObjectName("mainToolBar")
        self.mainToolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.mainToolBar.setContextMenuPolicy(Qt.PreventContextMenu)
        MainWin.addToolBar(Qt.TopToolBarArea, self.mainToolBar)

        # Upload
        self.mainToolBar.addAction(self.actionUpload)
        self.actionUpload.setIcon(qApp.style().standardIcon(QStyle.SP_FileDialogToParent))

        # Rescan
        self.mainToolBar.addAction(self.actionRescan)
        self.actionRescan.setIcon(qApp.style().standardIcon(QStyle.SP_BrowserReload))

        # Cancel
        self.mainToolBar.addAction(self.actionCancel)
        self.actionCancel.setIcon(qApp.style().standardIcon(QStyle.SP_BrowserStop))
        self.actionCancel.setEnabled(False)

        # Options
        self.mainToolBar.addAction(self.actionOptions)
        self.actionOptions.setIcon(qApp.style().standardIcon(QStyle.SP_FileDialogDetailedView))

        # this spacer right justifies everything that comes after it
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.mainToolBar.addWidget(spacer)

        # Login
        self.mainToolBar.addAction(self.actionLogin)
        self.actionLogin.setIcon(qApp.style().standardIcon(QStyle.SP_DialogApplyButton))

        # Logout
        self.mainToolBar.addAction(self.actionLogout)
        self.actionLogout.setIcon(qApp.style().standardIcon(QStyle.SP_DialogOkButton))

        # Help
        #self.mainToolBar.addAction(self.actionHelp)
        self.actionHelp.setIcon(qApp.style().standardIcon(QStyle.SP_MessageBoxQuestion))

        # Exit
        self.mainToolBar.addAction(self.actionExit)
        self.actionExit.setIcon(qApp.style().standardIcon(QStyle.SP_DialogCancelButton))

    # Status Bar

        self.statusBar = QStatusBar(MainWin)
        self.statusBar.setToolTip("")
        self.statusBar.setStatusTip("")
        self.statusBar.setObjectName("statusBar")
        MainWin.setStatusBar(self.statusBar)

    # configure logging
        self.logTextBrowser.widget.log_update_signal.connect(MainWin.updateLog)
        self.logTextBrowser.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
        logging.getLogger().addHandler(self.logTextBrowser)

    # finalize UI setup
        QMetaObject.connectSlotsByName(MainWin)
示例#19
0
class LicenseDialog(QMainWindow):
    def __init__(self, parent=None):
        super(LicenseDialog, self).__init__(parent)
        self.resize(420, 320)
        self.setWindowTitle(tr("Credits & Licensing"))
        self.setWindowFlags(Qt.Dialog)
        self.readme = ""
        self.license = ""
        self.thanks = ""
        self.authors = ""
        self.tabWidget = QTabWidget(self)
        self.setCentralWidget(self.tabWidget)
        for folder in (app_folder, os.path.dirname(app_folder)):
            for fname in os.listdir(folder):
                if fname.startswith("LICENSE"):
                    try:
                        f = open(os.path.join(folder, fname), "r")
                    except:
                        pass
                    else:
                        self.license = f.read()
                        f.close()
                elif fname.startswith("THANKS"):
                    try:
                        f = open(os.path.join(folder, fname), "r")
                    except:
                        pass
                    else:
                        self.thanks = f.read()
                        f.close()
                elif fname.startswith("AUTHORS"):
                    try:
                        f = open(os.path.join(folder, fname), "r")
                    except:
                        pass
                    else:
                        self.authors = f.read()
                        f.close()
                elif fname.startswith("README"):
                    try:
                        f = open(os.path.join(folder, fname), "r")
                    except:
                        pass
                    else:
                        self.readme = f.read()
                        f.close()
        self.readmeView = ReadOnlyTextEdit(self)
        self.readmeView.setText(self.readme)
        self.tabWidget.addTab(self.readmeView, tr("&README"))
        self.authorsView = ReadOnlyTextEdit(self)
        self.authorsView.setText(self.authors)
        self.tabWidget.addTab(self.authorsView, tr("&Authors"))
        self.thanksView = ReadOnlyTextEdit(self)
        self.thanksView.setText(self.thanks)
        self.tabWidget.addTab(self.thanksView, tr("&Thanks"))
        self.licenseView = ReadOnlyTextEdit(self)
        self.licenseView.setText(self.license)
        self.tabWidget.addTab(self.licenseView, tr("&License"))
        closeAction = QAction(self)
        closeAction.setShortcuts(["Esc", "Ctrl+W"])
        closeAction.triggered.connect(self.hide)
        self.addAction(closeAction)
        self.toolBar = QToolBar(self)
        self.toolBar.setStyleSheet(blank_toolbar)
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.addToolBar(Qt.BottomToolBarArea, self.toolBar)
        self.toolBar.addWidget(HorizontalExpander(self))
        self.closeButton = QPushButton(tr("&OK"), self)
        self.closeButton.clicked.connect(self.close)
        self.toolBar.addWidget(self.closeButton)
        self.closeButton.setFocus()
class AuthWindowUI(object):
    def __init__(self, MainWin):
        # Main Window
        MainWin.setObjectName("AuthWindow")
        MainWin.setWindowIcon(MainWin.window_icon)
        MainWin.setWindowTitle(MainWin.tr(MainWin.window_title))
        MainWin.resize(1024, 860)
        self.config = MainWin.config
        self.centralWidget = QWidget(MainWin)
        self.centralWidget.setObjectName("centralWidget")
        MainWin.setCentralWidget(self.centralWidget)
        self.verticalLayout = QVBoxLayout(self.centralWidget)
        self.verticalLayout.setContentsMargins(11, 11, 11, 11)
        self.verticalLayout.setSpacing(6)
        self.verticalLayout.setObjectName("verticalLayout")

        self.tabWidget = QTabWidget(MainWin)
        self.tabWidget.currentChanged.connect(MainWin.onTabChanged)
        self.tabWidget.tabCloseRequested.connect(MainWin.onTabClosed)
        self.tabWidget.setTabsClosable(True)
        # workaround for https://bugreports.qt.io/browse/QTBUG-58267
        if "darwin" in sys.platform:
            self.tabWidget.setDocumentMode(True)

        # Splitter for log
        self.splitter = QSplitter(Qt.Vertical)
        self.splitter.addWidget(self.tabWidget)

        # Log Widget
        self.logTextBrowser = QPlainTextEditLogger(self.centralWidget)
        self.logTextBrowser.widget.setObjectName("logTextBrowser")
        self.logTextBrowser.widget.setStyleSheet("""
            QPlainTextEdit {
                    border: 2px solid grey;
                    border-radius: 5px;
                    background-color: lightgray;
            }
            """)
        self.splitter.addWidget(self.logTextBrowser.widget)

        # add splitter
        self.splitter.setSizes([800, 100])
        self.verticalLayout.addWidget(self.splitter)

        # Tool Bar
        self.mainToolBar = QToolBar(MainWin)
        self.mainToolBar.setObjectName("mainToolBar")
        self.mainToolBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.mainToolBar.setContextMenuPolicy(Qt.PreventContextMenu)
        MainWin.addToolBar(Qt.TopToolBarArea, self.mainToolBar)

        # Servers
        self.serverWidget = QWidget(MainWin)
        self.serverLayout = QHBoxLayout()
        self.serverLabel = QLabel("Server:")
        self.serverLayout.addWidget(self.serverLabel)
        self.serverComboBox = QComboBox()
        self.serverComboBox.setEditable(True)
        self.serverComboBox.setDuplicatesEnabled(False)
        self.serverComboBox.setMinimumContentsLength(50)
        self.serverComboBox.currentIndexChanged.connect(
            MainWin.onServerListChanged)
        lineEdit = self.serverComboBox.lineEdit()
        lineEdit.returnPressed.connect(MainWin.on_actionAdd_triggered)
        self.serverLayout.addWidget(self.serverComboBox)
        self.serverWidget.setLayout(self.serverLayout)
        self.mainToolBar.addWidget(self.serverWidget)

        # Add
        self.actionAdd = QAction(MainWin)
        self.actionAdd.setObjectName("actionAdd")
        self.actionAdd.setText(MainWin.tr("Add"))
        self.actionAdd.setToolTip(MainWin.tr("Add to server list"))
        self.actionAdd.setShortcut(MainWin.tr("Ctrl+A"))

        # Remove
        self.actionRemove = QAction(MainWin)
        self.actionRemove.setObjectName("actionRemove")
        self.actionRemove.setText(MainWin.tr("Remove"))
        self.actionRemove.setToolTip(MainWin.tr("Remove from server list"))
        self.actionRemove.setShortcut(MainWin.tr("Ctrl+X"))

        # Show Token
        self.actionShowToken = QAction(MainWin)
        self.actionShowToken.setEnabled(False)
        self.actionShowToken.setObjectName("actionShowToken")
        self.actionShowToken.setText(MainWin.tr("Show Token"))
        self.actionShowToken.setToolTip(
            MainWin.tr("Display the current authentication token"))
        self.actionShowToken.setShortcut(MainWin.tr("Ctrl+S"))

        # Login
        self.actionLogin = QAction(MainWin)
        self.actionLogin.setObjectName("actionLogin")
        self.actionLogin.setText(MainWin.tr("Login"))
        self.actionLogin.setToolTip(
            MainWin.tr("Login to the currently selected server"))
        self.actionLogin.setShortcut(MainWin.tr("Ctrl+L"))

        # Logout
        self.actionLogout = QAction(MainWin)
        self.actionLogout.setObjectName("actionLogout")
        self.actionLogout.setText(MainWin.tr("Logout"))
        self.actionLogout.setToolTip(
            MainWin.tr("Logout of the currently selected server"))
        self.actionLogout.setShortcut(MainWin.tr("Ctrl+O"))

        # Add
        self.mainToolBar.addAction(self.actionAdd)
        self.actionAdd.setIcon(qApp.style().standardIcon(
            QStyle.SP_FileDialogNewFolder))

        # Remove
        self.mainToolBar.addAction(self.actionRemove)
        self.actionRemove.setIcon(qApp.style().standardIcon(
            QStyle.SP_DialogDiscardButton))

        # Show Token
        self.mainToolBar.addAction(self.actionShowToken)
        self.actionShowToken.setIcon(qApp.style().standardIcon(
            QStyle.SP_FileDialogInfoView))
        self.mainToolBar.addSeparator()

        # this spacer right justifies everything that comes after it
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.mainToolBar.addWidget(spacer)

        # Login
        self.mainToolBar.addSeparator()
        self.mainToolBar.addAction(self.actionLogin)
        self.actionLogin.setIcon(qApp.style().standardIcon(
            QStyle.SP_DialogApplyButton))

        # Logout
        self.mainToolBar.addSeparator()
        self.mainToolBar.addAction(self.actionLogout)
        self.actionLogout.setIcon(qApp.style().standardIcon(
            QStyle.SP_DialogOkButton))

        # Status Bar
        self.statusBar = QStatusBar(MainWin)
        self.statusBar.setToolTip("")
        self.statusBar.setStatusTip("")
        self.statusBar.setObjectName("statusBar")
        MainWin.setStatusBar(self.statusBar)

        # configure logging
        self.logTextBrowser.widget.log_update_signal.connect(MainWin.updateLog)
        self.logTextBrowser.setFormatter(
            logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
        logging.getLogger().addHandler(self.logTextBrowser)
        logging.getLogger().setLevel(logging.INFO)

        # finalize UI setup
        QMetaObject.connectSlotsByName(MainWin)
示例#21
0
class SettingsDialog(QDialog):
    def __init__(self, parent=None):
        super(SettingsDialog, self).__init__(parent)

        # Set layout.
        _layout = QVBoxLayout(self)
        _layout.setContentsMargins(0,0,0,0)
        self.setLayout(_layout)

        # Set window title.
        self.setWindowTitle(tr("Settings"))

        # Tab widget
        self.tabs = QTabWidget(self)
        self.layout().addWidget(self.tabs)

        self.tabs.addTab(GeneralSettingsPanel(self), tr("&General"))
        self.tabs.addTab(ContentSettingsPanel(self), tr("Con&tent"))
        self.tabs.addTab(AdremoverSettingsPanel(self), tr("Ad &Remover"))
        self.tabs.addTab(DataSettingsPanel(self), tr("&Data && Privacy"))
        self.tabs.addTab(NetworkSettingsPanel(self), tr("N&etwork"))
        self.tabs.addTab(ExtensionsSettingsPanel(self), tr("E&xtensions"))

        # Toolbar
        self.toolBar = QToolBar(self)
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.toolBar.setStyleSheet(common.blank_toolbar)
        self.layout().addWidget(self.toolBar)

        # Apply button
        applyButton = QPushButton(tr("&Apply"), self)
        applyButton.clicked.connect(self.saveSettings)
        self.toolBar.addWidget(applyButton)

        # Reload settings button
        closeButton = QPushButton(tr("&Close"), self)
        closeButton.clicked.connect(self.hide)
        self.toolBar.addWidget(closeButton)

        # Load settings
        self.loadSettings()

    def show(self):
        super(SettingsDialog, self).show()
        self.loadSettings()

    def url(self):
        return QUrl("")

    def icon(self):
        return common.complete_icon("preferences-system")

    # Method to load all settings.
    def loadSettings(self):
        for index in range(0, self.tabs.count()):
            self.tabs.widget(index).loadSettings()
    
    # Method to save all settings.
    def saveSettings(self):
        for index in range(0, self.tabs.count()):
            self.tabs.widget(index).saveSettings()
        settings.reset_extensions()
        settings.reload_userscripts()
        for window in browser.windows:
            try: window.reloadExtensions()
            except: pass
            try: window.applySettings()
            except: pass
示例#22
0
class ClearHistoryDialog(QDialog):
    def __init__(self, parent=None):
        super(ClearHistoryDialog, self).__init__(parent)

        self.setWindowFlags(Qt.Dialog)

        self.setWindowTitle(tr("Clear Data"))

        closeWindowAction = QAction(self)
        closeWindowAction.setShortcuts(["Esc", "Ctrl+W", "Ctrl+Shift+Del"])
        closeWindowAction.triggered.connect(self.close)
        self.addAction(closeWindowAction)

        self.layout = QVBoxLayout()
        self.setLayout(self.layout)
        label = QLabel(tr("What to clear:"), self)
        self.layout.addWidget(label)
        self.dataType = QComboBox(self)
        self.dataType.addItem(tr("History"))
        self.dataType.addItem(tr("Cookies"))
        self.dataType.addItem(tr("Memory Caches"))
        self.dataType.addItem(tr("Persistent Storage"))
        self.dataType.addItem(tr("Everything"))
        self.layout.addWidget(self.dataType)
        self.toolBar = QToolBar(self)
        self.toolBar.setStyleSheet(common.blank_toolbar)
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.layout.addWidget(self.toolBar)
        self.clearHistoryButton = QPushButton(tr("Clear"), self)
        self.clearHistoryButton.clicked.connect(self.clearHistory)
        self.toolBar.addWidget(self.clearHistoryButton)
        self.closeButton = QPushButton(tr("Close"), self)
        self.closeButton.clicked.connect(self.close)
        self.toolBar.addWidget(self.closeButton)

    def display(self):
        self.show()
        self.activateWindow()

    def clearHistory(self):
        clear_everything = (self.dataType.currentIndex() == self.dataType.count()-1)
        if self.dataType.currentIndex() == 0 or clear_everything:
            data.clearHistory()
        if self.dataType.currentIndex() == 1 or clear_everything:
            data.clearCookies()
        if self.dataType.currentIndex() == 2 or clear_everything:
            QWebSettings.globalSettings().clearMemoryCaches()
        if self.dataType.currentIndex() == 3 or clear_everything:
            QWebSettings.globalSettings().setIconDatabasePath("")
            QWebSettings.globalSettings().setLocalStoragePath("")
            QWebSettings.globalSettings().setOfflineStoragePath("")
            QWebSettings.globalSettings().setOfflineWebApplicationCachePath("")
            for subpath in ("WebpageIcons.db", "LocalStorage", "Databases",):
                path = os.path.abspath(os.path.join(settings.settings_folder, subpath))
                if os.path.isfile(path):
                    try: os.remove(path)
                    except: pass
                elif os.path.isdir(path):
                    if sys.platform.startswith("win"):
                        args = ["rmdir", "/s", "/q", "\"" + path + "\""]
                        try: os.system(" ".join(args))
                        except: pass
                    else:
                        try: subprocess.Popen(["rm", "-rf", path])
                        except: pass
            QWebSettings.globalSettings().enablePersistentStorage(settings.settings_folder)
示例#23
0
class SimulationGui(QMainWindow):
    """
    class for the graphical user interface
    """
    # TODO enable closing plot docks by right-clicking their name

    runSimulation = pyqtSignal()
    stopSimulation = pyqtSignal()
    playbackTimeChanged = pyqtSignal()
    regimeFinished = pyqtSignal()
    finishedRegimeBatch = pyqtSignal(bool)

    def __init__(self):
        # constructor of the base class
        QMainWindow.__init__(self)

        QCoreApplication.setOrganizationName("RST")
        QCoreApplication.setOrganizationDomain("https://tu-dresden.de/rst")
        QCoreApplication.setApplicationVersion(
            pkg_resources.require("PyMoskito")[0].version)
        QCoreApplication.setApplicationName(globals()["__package__"])

        # load settings
        self._settings = QSettings()
        self._read_settings()

        # initialize logger
        self._logger = logging.getLogger(self.__class__.__name__)

        # Create Simulation Backend
        self.guiProgress = None
        self.cmdProgress = None
        self.sim = SimulatorInteractor(self)
        self.runSimulation.connect(self.sim.run_simulation)
        self.stopSimulation.connect(self.sim.stop_simulation)
        self.sim.simulation_finalized.connect(self.new_simulation_data)
        self.currentDataset = None
        self.interpolator = None

        # sim setup viewer
        self.targetView = SimulatorView(self)
        self.targetView.setModel(self.sim.target_model)
        self.targetView.expanded.connect(self.target_view_changed)
        self.targetView.collapsed.connect(self.target_view_changed)

        # sim results viewer
        self.result_view = QTreeView()

        # the docking area allows to rearrange the user interface at runtime
        self.area = pg.dockarea.DockArea()

        # Window properties
        icon_size = QSize(25, 25)
        self.setCentralWidget(self.area)
        self.resize(1000, 700)
        self.setWindowTitle("PyMoskito")
        res_path = get_resource("mosquito.png")
        icon = QIcon(res_path)
        self.setWindowIcon(icon)

        # create docks
        self.propertyDock = pg.dockarea.Dock("Properties")
        self.animationDock = pg.dockarea.Dock("Animation")
        self.regimeDock = pg.dockarea.Dock("Regimes")
        self.dataDock = pg.dockarea.Dock("Data")
        self.logDock = pg.dockarea.Dock("Log")
        self.plotDockPlaceholder = pg.dockarea.Dock("Placeholder")

        # arrange docks
        self.area.addDock(self.animationDock, "right")
        self.area.addDock(self.regimeDock, "left", self.animationDock)
        self.area.addDock(self.propertyDock, "bottom", self.regimeDock)
        self.area.addDock(self.dataDock, "bottom", self.propertyDock)
        self.area.addDock(self.plotDockPlaceholder, "bottom", self.animationDock)
        self.area.addDock(self.logDock, "bottom", self.dataDock)
        self.non_plotting_docks = list(self.area.findAll()[1].keys())

        # add widgets to the docks
        self.propertyDock.addWidget(self.targetView)

        if not vtk_available:
            self._logger.error("loading vtk failed with:{}".format(vtk_error_msg))

        # check if there is a registered visualizer
        available_vis = get_registered_visualizers()
        self._logger.info("found visualizers: {}".format(
            [name for cls, name in available_vis]))
        if available_vis:
            # instantiate the first visualizer
            self._logger.info("loading visualizer '{}'".format(available_vis[0][1]))
            self.animationLayout = QVBoxLayout()

            if issubclass(available_vis[0][0], MplVisualizer):
                self.animationWidget = QWidget()
                self.visualizer = available_vis[0][0](self.animationWidget,
                                                      self.animationLayout)
                self.animationDock.addWidget(self.animationWidget)
            elif issubclass(available_vis[0][0], VtkVisualizer):
                if vtk_available:
                    # vtk window
                    self.animationFrame = QFrame()
                    self.vtkWidget = QVTKRenderWindowInteractor(
                        self.animationFrame)
                    self.animationLayout.addWidget(self.vtkWidget)
                    self.animationFrame.setLayout(self.animationLayout)
                    self.animationDock.addWidget(self.animationFrame)
                    self.vtk_renderer = vtkRenderer()
                    self.vtkWidget.GetRenderWindow().AddRenderer(
                        self.vtk_renderer)
                    self.visualizer = available_vis[0][0](self.vtk_renderer)
                    self.vtkWidget.Initialize()
                else:
                    self._logger.warning("visualizer depends on vtk which is "
                                         "not available on this system!")
            elif available_vis:
                raise NotImplementedError
        else:
            self.visualizer = None

        # regime window
        self.regime_list = QListWidget(self)
        self.regime_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.regimeDock.addWidget(self.regime_list)
        self.regime_list.itemDoubleClicked.connect(self.regime_dclicked)
        self._regimes = []
        self.regime_file_name = ""

        self.actDeleteRegimes = QAction(self.regime_list)
        self.actDeleteRegimes.setText("&Delete Selected Regimes")
        # TODO shortcut works always, not only with focus on the regime list
        # self.actDeleteRegimes.setShortcutContext(Qt.WindowShortcut)
        self.actDeleteRegimes.setShortcut(QKeySequence(Qt.Key_Delete))
        self.actDeleteRegimes.triggered.connect(self.remove_regime_items)

        self.actSave = QAction(self)
        self.actSave.setText('Save Results As')
        self.actSave.setIcon(QIcon(get_resource("save.png")))
        self.actSave.setDisabled(True)
        self.actSave.setShortcut(QKeySequence.Save)
        self.actSave.triggered.connect(self.export_simulation_data)

        self.actLoadRegimes = QAction(self)
        self.actLoadRegimes.setText("Load Regimes from File")
        self.actLoadRegimes.setIcon(QIcon(get_resource("load.png")))
        self.actLoadRegimes.setDisabled(False)
        self.actLoadRegimes.setShortcut(QKeySequence.Open)
        self.actLoadRegimes.triggered.connect(self.load_regime_dialog)

        self.actExitOnBatchCompletion = QAction(self)
        self.actExitOnBatchCompletion.setText("&Exit On Batch Completion")
        self.actExitOnBatchCompletion.setCheckable(True)
        self.actExitOnBatchCompletion.setChecked(
            self._settings.value("control/exit_on_batch_completion") == "True"
        )
        self.actExitOnBatchCompletion.changed.connect(
            self.update_exit_on_batch_completion_setting)

        # regime management
        self.runningBatch = False
        self._current_regime_index = None
        self._current_regime_name = None
        self._regimes = []

        self.regimeFinished.connect(self.run_next_regime)
        self.finishedRegimeBatch.connect(self.regime_batch_finished)

        # data window
        self.dataList = QListWidget(self)
        self.dataDock.addWidget(self.dataList)
        self.dataList.itemDoubleClicked.connect(self.create_plot)

        # actions for simulation control
        self.actSimulateCurrent = QAction(self)
        self.actSimulateCurrent.setText("&Simulate Current Regime")
        self.actSimulateCurrent.setIcon(QIcon(get_resource("simulate.png")))
        self.actSimulateCurrent.setShortcut(QKeySequence("F5"))
        self.actSimulateCurrent.triggered.connect(self.start_simulation)

        self.actSimulateAll = QAction(self)
        self.actSimulateAll.setText("Simulate &All Regimes")
        self.actSimulateAll.setIcon(QIcon(get_resource("execute_regimes.png")))
        self.actSimulateAll.setShortcut(QKeySequence("F6"))
        self.actSimulateAll.setDisabled(True)
        self.actSimulateAll.triggered.connect(self.start_regime_execution)

        # actions for animation control
        self.actAutoPlay = QAction(self)
        self.actAutoPlay.setText("&Autoplay Simulation")
        self.actAutoPlay.setCheckable(True)
        self.actAutoPlay.setChecked(
            self._settings.value("control/autoplay_animation") == "True"
        )
        self.actAutoPlay.changed.connect(self.update_autoplay_setting)

        self.actPlayPause = QAction(self)
        self.actPlayPause.setText("Play Animation")
        self.actPlayPause.setIcon(QIcon(get_resource("play.png")))
        self.actPlayPause.setDisabled(True)
        self.actPlayPause.setShortcut(QKeySequence(Qt.Key_Space))
        self.actPlayPause.triggered.connect(self.play_animation)

        self.actStop = QAction(self)
        self.actStop.setText("Stop")
        self.actStop.setIcon(QIcon(get_resource("stop.png")))
        self.actStop.setDisabled(True)
        self.actStop.triggered.connect(self.stop_animation)

        self.actSlow = QAction(self)
        self.actSlow.setText("Slowest")
        self.actSlow.setIcon(QIcon(get_resource("slow.png")))
        self.actSlow.setDisabled(False)
        self.actSlow.triggered.connect(self.set_slowest_playback_speed)

        self.actFast = QAction(self)
        self.actFast.setText("Fastest")
        self.actFast.setIcon(QIcon(get_resource("fast.png")))
        self.actFast.setDisabled(False)
        self.actFast.triggered.connect(self.set_fastest_playback_speed)

        self.speedControl = QSlider(Qt.Horizontal, self)
        self.speedControl.setMaximumSize(200, 25)
        self.speedControl.setTickPosition(QSlider.TicksBothSides)
        self.speedControl.setDisabled(False)
        self.speedControl.setMinimum(0)
        self.speedControl.setMaximum(12)
        self.speedControl.setValue(6)
        self.speedControl.setTickInterval(6)
        self.speedControl.setSingleStep(2)
        self.speedControl.setPageStep(3)
        self.speedControl.valueChanged.connect(self.update_playback_speed)

        self.timeSlider = QSlider(Qt.Horizontal, self)
        self.timeSlider.setMinimum(0)
        self.timeSliderRange = 1000
        self.timeSlider.setMaximum(self.timeSliderRange)
        self.timeSlider.setTickInterval(1)
        self.timeSlider.setTracking(True)
        self.timeSlider.setDisabled(True)
        self.timeSlider.valueChanged.connect(self.update_playback_time)

        self.playbackTime = .0
        self.playbackGain = 1
        self.currentStepSize = .0
        self.currentEndTime = .0
        self.playbackTimer = QTimer()
        self.playbackTimer.timeout.connect(self.increment_playback_time)
        self.playbackTimeChanged.connect(self.update_gui)
        self.playbackTimeout = 33  # in [ms] -> 30 fps

        self.actResetCamera = QAction(self)
        self.actResetCamera.setText("Reset Camera")
        self.actResetCamera.setIcon(QIcon(get_resource("reset_camera.png")))
        self.actResetCamera.setDisabled(True)
        if available_vis:
            self.actResetCamera.setEnabled(self.visualizer.can_reset_view)
        self.actResetCamera.triggered.connect(self.reset_camera_clicked)

        # postprocessing
        self.actPostprocessing = QAction(self)
        self.actPostprocessing.setText("Launch Postprocessor")
        self.actPostprocessing.setIcon(QIcon(get_resource("processing.png")))
        self.actPostprocessing.setDisabled(False)
        self.actPostprocessing.triggered.connect(self.postprocessing_clicked)
        self.actPostprocessing.setShortcut(QKeySequence("F7"))

        self.postprocessor = None

        # toolbar
        self.toolbarSim = QToolBar("Simulation")
        self.toolbarSim.setContextMenuPolicy(Qt.PreventContextMenu)
        self.toolbarSim.setMovable(False)
        self.toolbarSim.setIconSize(icon_size)
        self.addToolBar(self.toolbarSim)
        self.toolbarSim.addAction(self.actLoadRegimes)
        self.toolbarSim.addAction(self.actSave)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actSimulateCurrent)
        self.toolbarSim.addAction(self.actSimulateAll)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actPlayPause)
        self.toolbarSim.addAction(self.actStop)
        self.toolbarSim.addWidget(self.timeSlider)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actSlow)
        self.toolbarSim.addWidget(self.speedControl)
        self.toolbarSim.addAction(self.actFast)
        self.toolbarSim.addSeparator()
        self.toolbarSim.addAction(self.actPostprocessing)
        self.toolbarSim.addAction(self.actResetCamera)
        self.postprocessor = None

        # log dock
        self.logBox = QPlainTextEdit(self)
        self.logBox.setReadOnly(True)
        self.logDock.addWidget(self.logBox)

        # init logger for logging box
        self.textLogger = PlainTextLogger(logging.INFO)
        self.textLogger.set_target_cb(self.logBox.appendPlainText)
        logging.getLogger().addHandler(self.textLogger)

        # menu bar
        fileMenu = self.menuBar().addMenu("&File")
        fileMenu.addAction(self.actLoadRegimes)
        fileMenu.addAction(self.actSave)
        fileMenu.addAction("&Quit", self.close)

        editMenu = self.menuBar().addMenu("&Edit")
        editMenu.addAction(self.actDeleteRegimes)

        simMenu = self.menuBar().addMenu("&Simulation")
        simMenu.addAction(self.actSimulateCurrent)
        simMenu.addAction(self.actSimulateAll)
        simMenu.addAction(self.actExitOnBatchCompletion)
        simMenu.addAction(self.actPostprocessing)

        animMenu = self.menuBar().addMenu("&Animation")
        animMenu.addAction(self.actPlayPause)
        animMenu.addAction("&Increase Playback Speed",
                           self.increment_playback_speed,
                           QKeySequence(Qt.CTRL + Qt.Key_Plus))
        animMenu.addAction("&Decrease Playback Speed",
                           self.decrement_playback_speed,
                           QKeySequence(Qt.CTRL + Qt.Key_Minus))
        animMenu.addAction("&Reset Playback Speed",
                           self.reset_playback_speed,
                           QKeySequence(Qt.CTRL + Qt.Key_0))
        animMenu.addAction(self.actAutoPlay)
        animMenu.addAction(self.actResetCamera)

        helpMenu = self.menuBar().addMenu("&Help")
        helpMenu.addAction("&Online Documentation", self.show_online_docs)
        helpMenu.addAction("&About", self.show_info)

        # status bar
        self.status = QStatusBar(self)
        self.setStatusBar(self.status)
        self.statusLabel = QLabel("Ready.")
        self.statusBar().addPermanentWidget(self.statusLabel)
        self.timeLabel = QLabel("current time: 0.0")
        self.statusBar().addPermanentWidget(self.timeLabel)

        self._logger.info("Simulation GUI is up and running.")

    def _read_settings(self):

        # add default settings if none are present
        if not self._settings.contains("path/simulation_results"):
            self._settings.setValue("path/simulation_results",
                                    os.path.join(os.path.curdir,
                                                 "results",
                                                 "simulation"))
        if not self._settings.contains("path/postprocessing_results"):
            self._settings.setValue("path/postprocessing_results",
                                    os.path.join(os.path.curdir,
                                                 "results",
                                                 "postprocessing"))
        if not self._settings.contains("path/metaprocessing_results"):
            self._settings.setValue("path/metaprocessing_results",
                                    os.path.join(os.path.curdir,
                                                 "results",
                                                 "metaprocessing"))

        if not self._settings.contains("control/autoplay_animation"):
            self._settings.setValue("control/autoplay_animation", "False")

        if not self._settings.contains("control/exit_on_batch_completion"):
            self._settings.setValue("control/exit_on_batch_completion", "False")

    def _write_settings(self):
        """ Store the application state. """
        pass

    @pyqtSlot()
    def update_autoplay_setting(self):
        self._settings.setValue("control/autoplay_animation",
                                str(self.actAutoPlay.isChecked()))

    @pyqtSlot()
    def update_exit_on_batch_completion_setting(self, state=None):
        if state is None:
            state = self.actExitOnBatchCompletion.isChecked()
        self._settings.setValue("control/exit_on_batch_completion", str(state))

    def set_visualizer(self, vis):
        self.visualizer = vis
        self.vtkWidget.Initialize()

    @pyqtSlot()
    def play_animation(self):
        """
        play the animation
        """
        self._logger.debug("Starting Playback")

        # if we are at the end, start from the beginning
        if self.playbackTime == self.currentEndTime:
            self.timeSlider.setValue(0)

        self.actPlayPause.setText("Pause Animation")
        self.actPlayPause.setIcon(QIcon(get_resource("pause.png")))
        self.actPlayPause.triggered.disconnect(self.play_animation)
        self.actPlayPause.triggered.connect(self.pause_animation)
        self.playbackTimer.start(self.playbackTimeout)

    @pyqtSlot()
    def pause_animation(self):
        """
        pause the animation
        """
        self._logger.debug("Pausing Playback")
        self.playbackTimer.stop()
        self.actPlayPause.setText("Play Animation")
        self.actPlayPause.setIcon(QIcon(get_resource("play.png")))
        self.actPlayPause.triggered.disconnect(self.pause_animation)
        self.actPlayPause.triggered.connect(self.play_animation)

    def stop_animation(self):
        """
        Stop the animation if it is running and reset the playback time.
        """
        self._logger.debug("Stopping Playback")
        if self.actPlayPause.text() == "Pause Animation":
            # animation is playing -> stop it
            self.playbackTimer.stop()
            self.actPlayPause.setText("Play Animation")
            self.actPlayPause.setIcon(QIcon(get_resource("play.png")))
            self.actPlayPause.triggered.disconnect(self.pause_animation)
            self.actPlayPause.triggered.connect(self.play_animation)

        self.timeSlider.setValue(0)

    @pyqtSlot()
    def start_simulation(self):
        """
        start the simulation and disable start button
        """
        if self._current_regime_index is None:
            regime_name = ""
        else:
            regime_name = str(self.regime_list.item(
                self._current_regime_index).text())

        self.statusLabel.setText("simulating {}".format(regime_name))
        self._logger.info("Simulating: {}".format(regime_name))

        self.actSimulateCurrent.setIcon(QIcon(
            get_resource("stop_simulation.png")))
        self.actSimulateCurrent.setText("Abort &Simulation")
        self.actSimulateCurrent.triggered.disconnect(self.start_simulation)
        self.actSimulateCurrent.triggered.connect(self.stop_simulation)

        if not self.runningBatch:
            self.actSimulateAll.setDisabled(True)

        self.guiProgress = QProgressBar(self)
        self.sim.simulationProgressChanged.connect(self.guiProgress.setValue)
        self.statusBar().addWidget(self.guiProgress)
        self.runSimulation.emit()

    @pyqtSlot()
    def stop_simulation(self):
        self.stopSimulation.emit()

    def export_simulation_data(self, ok):
        """
        Query the user for a custom name and export the current simulation
        results.

        :param ok: unused parameter from QAction.triggered() Signal
        """
        self._save_data()

    def _save_data(self, file_path=None):
        """
        Save the current simulation results.

        If *fie_name* is given, the result will be saved to the specified
        location, making automated exporting easier.

        Args:
            file_path(str): Absolute path of the target file. If `None` the
                use will be asked for a storage location.
        """
        regime_name = self._regimes[self._current_regime_index]["Name"]

        if file_path is None:
            # get default path
            path = self._settings.value("path/simulation_results")

            # create canonic file name
            suggestion = self._simfile_name(regime_name)
        else:
            path = os.path.dirname(file_path)
            suggestion = os.path.basename(file_path)

        # check if path exists otherwise create it
        if not os.path.isdir(path):
            box = QMessageBox()
            box.setText("Export Folder does not exist yet.")
            box.setInformativeText("Do you want to create it? \n"
                                   "{}".format(os.path.abspath(path)))
            box.setStandardButtons(QMessageBox.Ok | QMessageBox.No)
            box.setDefaultButton(QMessageBox.Ok)
            ret = box.exec_()
            if ret == QMessageBox.Ok:
                os.makedirs(path)
            else:
                path = os.path.abspath(os.path.curdir)
                file_path = None

        # If no path was given, present the default and let the user choose
        if file_path is None:
            dialog = QFileDialog(self)
            dialog.setAcceptMode(QFileDialog.AcceptSave)
            dialog.setFileMode(QFileDialog.AnyFile)
            dialog.setDirectory(path)
            dialog.setNameFilter("PyMoskito Results (*.pmr)")
            dialog.selectFile(suggestion)

            if dialog.exec_():
                file_path = dialog.selectedFiles()[0]
            else:
                self._logger.warning("Export Aborted")
                return -1

        # ask whether this should act as new default
        path = os.path.abspath(os.path.dirname(file_path))
        if path != self._settings.value("path/simulation_results"):
            box = QMessageBox()
            box.setText("Use this path as new default?")
            box.setInformativeText("{}".format(path))
            box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            box.setDefaultButton(QMessageBox.Yes)
            ret = box.exec_()
            if ret == QMessageBox.Yes:
                self._settings.setValue("path/simulation_results", path)

        self.currentDataset.update({"regime name": regime_name})
        with open(file_path, "wb") as f:
            pickle.dump(self.currentDataset, f, protocol=4)

        self.statusLabel.setText("results saved to {}".format(file_path))
        self._logger.info("results saved to {}".format(file_path))

    def _simfile_name(self, regime_name):
        """ Create a canonical name for a simulation result file
        """
        suggestion = (time.strftime("%Y%m%d-%H%M%S")
                      + "_" + regime_name + ".pmr")
        return suggestion

    def load_regime_dialog(self):
        regime_path = os.path.join(os.curdir)

        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setDirectory(regime_path)
        dialog.setNameFilter("Simulation Regime files (*.sreg)")

        if dialog.exec_():
            file = dialog.selectedFiles()[0]
            self.load_regimes_from_file(file)

    def load_regimes_from_file(self, file_name):
        """
        load simulation regime from file
        :param file_name:
        """
        self.regime_file_name = os.path.split(file_name)[-1][:-5]
        self._logger.info("loading regime file: {0}".format(self.regime_file_name))
        with open(file_name.encode(), "r") as f:
            self._regimes += yaml.load(f)

        self._update_regime_list()

        if self._regimes:
            self.actSimulateAll.setDisabled(False)

        self._logger.info("loaded {} regimes".format(len(self._regimes)))
        self.statusBar().showMessage("loaded {} regimes.".format(len(self._regimes)), 1000)
        return

    def _update_regime_list(self):
        self.regime_list.clear()
        for reg in self._regimes:
            self._logger.debug("adding '{}' to regime list".format(reg["Name"]))
            self.regime_list.addItem(reg["Name"])

    def remove_regime_items(self):
        if self.regime_list.currentRow() >= 0:
            # flag all selected files as invalid
            items = self.regime_list.selectedItems()
            for item in items:
                del self._regimes[self.regime_list.row(item)]
                self.regime_list.takeItem(self.regime_list.row(item))

    @pyqtSlot(QListWidgetItem)
    def regime_dclicked(self, item):
        """
        Apply the selected regime to the current target.
        """
        self.apply_regime_by_name(str(item.text()))

    def apply_regime_by_name(self, regime_name):
        """
        Apply the regime given by `regime_name` und update the regime index.

        Returns:
            bool: `True` if successful, `False` if errors occurred.
        """
        # get regime idx
        try:
            idx = list(map(itemgetter("Name"), self._regimes)).index(regime_name)
        except ValueError as e:
            self._logger.error("apply_regime_by_name(): Error no regime called "
                               "'{0}'".format(regime_name))
            return False

        # apply
        return self._apply_regime_by_idx(idx)

    def _apply_regime_by_idx(self, index=0):
        """
        Apply the given regime.

        Args:
            index(int): Index of the regime in the `RegimeList` .

        Returns:
            bool: `True` if successful, `False` if errors occurred.
        """
        if index >= len(self._regimes):
            self._logger.error("applyRegime: index error! ({})".format(index))
            return False

        reg_name = self._regimes[index]["Name"]
        self.statusBar().showMessage("regime {} applied.".format(reg_name),
                                     1000)
        self._logger.info("applying regime '{}'".format(reg_name))

        self._current_regime_index = index
        self._current_regime_name = reg_name

        return self.sim.set_regime(self._regimes[index])

    @pyqtSlot()
    def start_regime_execution(self):
        """
        Simulate all regimes in the regime list.
        """
        self.actSimulateAll.setText("Stop Simulating &All Regimes")
        self.actSimulateAll.setIcon(QIcon(get_resource("stop_batch.png")))
        self.actSimulateAll.triggered.disconnect(self.start_regime_execution)
        self.actSimulateAll.triggered.connect(self.stop_regime_excecution)

        self.runningBatch = True
        self._current_regime_index = -1
        self.regimeFinished.emit()

    def run_next_regime(self):
        """
        Execute the next regime in the regime batch.
        """
        # are we finished?
        if self._current_regime_index == len(self._regimes) - 1:
            self.finishedRegimeBatch.emit(True)
            return

        suc = self._apply_regime_by_idx(self._current_regime_index + 1)
        if not suc:
            self.finishedRegimeBatch.emit(False)
            return

        self.start_simulation()

    @pyqtSlot()
    def stop_regime_excecution(self):
        """ Stop the batch process.
        """
        self.stopSimulation.emit()
        self.finishedRegimeBatch.emit(False)

    def regime_batch_finished(self, status):
        self.runningBatch = False
        self.actSimulateAll.setDisabled(False)
        self.actSave.setDisabled(True)

        self.actSimulateAll.setText("Simulate &All Regimes")
        self.actSimulateAll.setIcon(QIcon(get_resource("execute_regimes.png")))
        self.actSimulateAll.triggered.disconnect(self.stop_regime_excecution)
        self.actSimulateAll.triggered.connect(self.start_regime_execution)

        if status:
            self.statusLabel.setText("All regimes have been simulated")
            self._logger.info("All Regimes have been simulated")
        else:
            self._logger.error("Batch simulation has been aborted")

        if self._settings.value("control/exit_on_batch_completion") == "True":
            self._logger.info("Shutting down SimulationGUI")
            self.close()

    @pyqtSlot(str, dict, name="new_simulation_data")
    def new_simulation_data(self, status, data):
        """
        Slot to be called when the simulation interface has completed the
        current job and new data is available.

        Args:
            status (str): Status of the simulation, either
                - `finished` : Simulation has been finished successfully or
                - `failed` : Simulation has failed.
            data (dict): Dictionary, holding the simulation data.
        """
        self._logger.info("Simulation {}".format(status))
        self.statusLabel.setText("Simulation {}".format(status))

        self.actSimulateCurrent.setText("&Simulate Current Regime")
        self.actSimulateCurrent.setIcon(QIcon(get_resource("simulate.png")))
        self.actSimulateCurrent.triggered.disconnect(self.stop_simulation)
        self.actSimulateCurrent.triggered.connect(self.start_simulation)

        self.actPlayPause.setDisabled(False)
        self.actStop.setDisabled(False)
        self.actSave.setDisabled(False)
        self.speedControl.setDisabled(False)
        self.timeSlider.setDisabled(False)

        self.sim.simulationProgressChanged.disconnect(self.guiProgress.setValue)
        self.statusBar().removeWidget(self.guiProgress)

        self.stop_animation()

        self.currentDataset = data
        if data:
            self._read_results()
            self._update_data_list()
            self._update_plots()

        if self._settings.value("control/autoplay_animation") == "True":
            self.actPlayPause.trigger()

        if self.runningBatch:
            regime_name = self._regimes[self._current_regime_index]["Name"]
            file_name = self._simfile_name(regime_name)
            self._save_data(os.path.join(
                self._settings.value("path/simulation_results"),
                file_name))
            self.regimeFinished.emit()
        else:
            self.actSimulateAll.setDisabled(False)

    def _read_results(self):
        state = self.currentDataset["results"]["Solver"]
        self.interpolator = interp1d(self.currentDataset["results"]["time"],
                                     state,
                                     axis=0,
                                     bounds_error=False,
                                     fill_value=(state[0], state[-1]))
        self.currentStepSize = 1.0/self.currentDataset["simulation"][
            "measure rate"]
        self.currentEndTime = self.currentDataset["simulation"]["end time"]
        self.validData = True

    def increment_playback_speed(self):
        self.speedControl.setValue(self.speedControl.value()
                                   + self.speedControl.singleStep())

    def decrement_playback_speed(self):
        self.speedControl.setValue(self.speedControl.value()
                                   - self.speedControl.singleStep())

    def reset_playback_speed(self):
        self.speedControl.setValue((self.speedControl.maximum()
                                    - self.speedControl.minimum())/2)

    def set_slowest_playback_speed(self):
        self.speedControl.setValue(self.speedControl.minimum())

    def set_fastest_playback_speed(self):
        self.speedControl.setValue(self.speedControl.maximum())

    def update_playback_speed(self, val):
        """
        adjust playback time to slider value

        :param val:
        """
        maximum = self.speedControl.maximum()
        self.playbackGain = 10**(3.0 * (val - maximum / 2) / maximum)

    @pyqtSlot()
    def increment_playback_time(self):
        """
        go one time step forward in playback
        """
        if self.playbackTime == self.currentEndTime:
            self.pause_animation()
            return

        increment = self.playbackGain * self.playbackTimeout / 1000
        self.playbackTime = min(self.currentEndTime,
                                self.playbackTime + increment)
        pos = int(self.playbackTime / self.currentEndTime
                  * self.timeSliderRange)
        self.timeSlider.blockSignals(True)
        self.timeSlider.setValue(pos)
        self.timeSlider.blockSignals(False)
        self.playbackTimeChanged.emit()

    def update_playback_time(self):
        """
        adjust playback time to slider value
        """
        self.playbackTime = self.timeSlider.value()/self.timeSliderRange*self.currentEndTime
        self.playbackTimeChanged.emit()
        return

    def update_gui(self):
        """
        updates the graphical user interface, including:
            - timestamp
            - visualisation
            - time cursor in diagrams
        """
        if not self.validData:
            return

        self.timeLabel.setText("current time: %4f" % self.playbackTime)

        # update time cursor in plots
        self._update_time_cursors()

        # update state of rendering
        if self.visualizer:
            state = self.interpolator(self.playbackTime)
            self.visualizer.update_scene(state)
            if isinstance(self.visualizer, MplVisualizer):
                pass
            elif isinstance(self.visualizer, VtkVisualizer):
                self.vtkWidget.GetRenderWindow().Render()

    def _update_data_list(self):
        self.dataList.clear()
        for module_name, results in self.currentDataset["results"].items():
            if not isinstance(results, np.ndarray):
                continue
            if len(results.shape) == 1:
                self.dataList.insertItem(0, module_name)
            elif len(results.shape) == 2:
                for col in range(results.shape[1]):
                    self.dataList.insertItem(
                        0,
                        self._build_entry_name(module_name, (col, ))
                    )
            elif len(results.shape) == 3:
                for col in range(results.shape[1]):
                    for der in range(results.shape[2]):
                        self.dataList.insertItem(
                            0,
                            self._build_entry_name(module_name, (col, der))
                        )

    def _build_entry_name(self, module_name, idx):
        """
        Construct an identifier for a given entry of a module.
        Args:
            module_name (str): name of the module the entry belongs to.
            idx (tuple): Index of the entry.

        Returns:
            str: Identifier to use for display.
        """
        # save the user from defining 1d entries via tuples
        if len(idx) == 1:
            m_idx = idx[0]
        else:
            m_idx = idx

        mod_settings = self.currentDataset["modules"]
        info = mod_settings.get(module_name, {}).get("output_info", None)
        if info:
            if m_idx in info:
                return ".".join([module_name, info[m_idx]["Name"]])

        return ".".join([module_name] + [str(i) for i in idx])

    def _get_index_from_suffix(self, module_name, suffix):
        info = self.currentDataset["modules"].get(module_name, {}).get(
            "output_info", None)
        idx = next((i for i in info if info[i]["Name"] == suffix), None)
        return idx

    def _get_units(self, entry):
        """
        Return the unit that corresponds to a given entry.

        If no information is available, None is returned.

        Args:
            entry (str): Name of the entry. This can either be "Model.a.b" where
                a and b are numbers or if information is available "Model.Signal"
                where signal is the name of that part.

        Returns:

        """
        args = entry.split(".")
        module_name = args.pop(0)
        info = self.currentDataset["modules"].get(module_name, {}).get(
            "output_info", None)
        if info is None:
            return None

        if len(args) == 1:
            try:
                idx = int(args[0])
            except ValueError:
                idx = next((i for i in info if info[i]["Name"] == args[0]),
                           None)
        else:
            idx = (int(a) for a in args)

        return info[idx]["Unit"]

    def create_plot(self, item):
        """
        Creates a plot widget based on the given item.

        If a plot for this item is already open no new plot is created but the
        existing one is raised up again.

        Args:
            item(Qt.ListItem): Item to plot.
        """
        title = str(item.text())
        if title in self.non_plotting_docks:
            self._logger.error("Title '{}' not allowed for a plot window since"
                               "it would shadow on of the reserved "
                               "names".format(title))

        # check if plot has already been opened
        if title in self.area.findAll()[1]:
            self.area.docks[title].raiseDock()
            return

        # collect data
        data = self._get_data_by_name(title)
        t = self.currentDataset["results"]["time"]
        unit = self._get_units(title)
        if "." in title:
            name = title.split(".")[1]
        else:
            name = title

        # create plot widget
        widget = pg.PlotWidget(title=title)
        widget.showGrid(True, True)
        widget.plot(x=t, y=data)
        widget.getPlotItem().getAxis("bottom").setLabel(text="Time", units="s")
        widget.getPlotItem().getAxis("left").setLabel(text=name, units=unit)

        # add a time line
        time_line = pg.InfiniteLine(self.playbackTime,
                                    angle=90,
                                    movable=False,
                                    pen=pg.mkPen("#FF0000", width=2.0))
        widget.getPlotItem().addItem(time_line)

        # create dock container and add it to dock area
        dock = pg.dockarea.Dock(title, closable=True)
        dock.addWidget(widget)
        self.area.addDock(dock, "above", self.plotDockPlaceholder)

    def _get_data_by_name(self, name):
        tmp = name.split(".")
        module_name = tmp[0]
        if len(tmp) == 1:
            data = np.array(self.currentDataset["results"][module_name])
        elif len(tmp) == 2:
            try:
                idx = int(tmp[1])
            except ValueError:
                idx = self._get_index_from_suffix(module_name, tmp[1])
            finally:
                data = self.currentDataset["results"][module_name][..., idx]
        elif len(tmp) == 3:
            idx = int(tmp[1])
            der = int(tmp[2])
            data = self.currentDataset["results"][module_name][..., idx, der]
        else:
            raise ValueError("Format not supported")

        return data

    def _update_time_cursors(self):
        """
        Update the time lines of all plot windows
        """
        for title, dock in self.area.findAll()[1].items():
            if title in self.non_plotting_docks:
                continue
            for widget in dock.widgets:
                for item in widget.getPlotItem().items:
                    if isinstance(item, pg.InfiniteLine):
                        item.setValue(self.playbackTime)

    def _update_plots(self):
        """
        Update the data in all plot windows
        """
        for title, dock in self.area.findAll()[1].items():
            if title in self.non_plotting_docks:
                continue

            if not self.dataList.findItems(dock.name(), Qt.MatchExactly):
                # no data for this plot -> remove it
                dock.close()
                continue

            for widget in dock.widgets:
                for item in widget.getPlotItem().items:
                    if isinstance(item, pg.PlotDataItem):
                        x_data = self.currentDataset["results"]["time"]
                        y_data = self._get_data_by_name(dock.name())
                        item.setData(x=x_data, y=y_data)

    @pyqtSlot(QModelIndex)
    def target_view_changed(self, index):
        self.targetView.resizeColumnToContents(0)

    def postprocessing_clicked(self):
        """
        starts the post- and metaprocessing application
        """
        self._logger.info("launching postprocessor")
        self.statusBar().showMessage("launching postprocessor", 1000)
        if self.postprocessor is None:
            self.postprocessor = PostProcessor()

        self.postprocessor.show()

    def reset_camera_clicked(self):
        """
        reset camera in vtk window
        """
        self.visualizer.reset_camera()
        self.vtkWidget.GetRenderWindow().Render()

    def show_info(self):
        icon_lic = open(get_resource("license.txt"), "r").read()
        text = "This application was build using PyMoskito ver. {} .<br />" \
               "PyMoskito is free software distributed under GPLv3. <br />" \
               "It is developed by members of the " \
               "<a href=\'https://tu-dresden.de/ing/elektrotechnik/rst'>" \
               "Institute of Control Theory</a>" \
               " at the <a href=\'https://tu-dresden.de'>" \
               "Dresden University of Technology</a>. <br />" \
               "".format(pkg_resources.require("PyMoskito")[0].version) \
               + "<br />" + icon_lic
        box = QMessageBox.about(self, "PyMoskito", text)

    def show_online_docs(self):
        webbrowser.open("https://pymoskito.readthedocs.org")

    def closeEvent(self, QCloseEvent):
        self._logger.info("Close Event received, shutting down.")
        logging.getLogger().removeHandler(self.textLogger)
        super().closeEvent(QCloseEvent)
示例#24
0
class SettingsDialog(QDialog):
    def __init__(self, parent=None):
        super(SettingsDialog, self).__init__(parent)

        # Set layout.
        _layout = QVBoxLayout(self)
        _layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(_layout)

        # Set window title.
        self.setWindowTitle(tr("Settings"))

        # Tab widget
        self.tabs = QTabWidget(self)
        self.layout().addWidget(self.tabs)

        self.tabs.addTab(GeneralSettingsPanel(self), tr("&General"))
        self.tabs.addTab(ContentSettingsPanel(self), tr("Con&tent"))
        self.tabs.addTab(AdremoverSettingsPanel(self), tr("Ad &Remover"))
        self.tabs.addTab(DataSettingsPanel(self), tr("&Data && Privacy"))
        self.tabs.addTab(NetworkSettingsPanel(self), tr("N&etwork"))
        self.tabs.addTab(ExtensionsSettingsPanel(self), tr("E&xtensions"))

        # Toolbar
        self.toolBar = QToolBar(self)
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.toolBar.setStyleSheet(common.blank_toolbar)
        self.layout().addWidget(self.toolBar)

        # Apply button
        applyButton = QPushButton(tr("&Apply"), self)
        applyButton.clicked.connect(self.saveSettings)
        self.toolBar.addWidget(applyButton)

        # Reload settings button
        closeButton = QPushButton(tr("&Close"), self)
        closeButton.clicked.connect(self.hide)
        self.toolBar.addWidget(closeButton)

        # Load settings
        self.loadSettings()

    def show(self):
        super(SettingsDialog, self).show()
        self.loadSettings()

    def url(self):
        return QUrl("")

    def icon(self):
        return common.complete_icon("preferences-system")

    # Method to load all settings.
    def loadSettings(self):
        for index in range(0, self.tabs.count()):
            self.tabs.widget(index).loadSettings()

    # Method to save all settings.
    def saveSettings(self):
        for index in range(0, self.tabs.count()):
            self.tabs.widget(index).saveSettings()
        settings.reset_extensions()
        settings.reload_userscripts()
        for window in browser.windows:
            try:
                window.reloadExtensions()
            except:
                pass
            try:
                window.applySettings()
            except:
                pass
示例#25
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__()
        self.setWindowTitle("RainbowBB")
        self.setParent(parent)
        self.initUI()

    def initUI(self):
        self.setStyleSheet("QCheckBox { background: palette(window); border-radius: 4px; padding: 2px; margin-right: 2px; }")

        self.toolBar = QToolBar(self)
        self.toolBar.setStyleSheet(stylesheet % (create_gradient("pastel"),))
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.addToolBar(self.toolBar)

        self.reverseBox = QCheckBox("&Reverse", self)
        self.reverseBox.clicked.connect(lambda: self.updateGradient())
        self.toolBar.addWidget(self.reverseBox)

        self.byWordBox = QCheckBox("By &word", self)
        self.toolBar.addWidget(self.byWordBox)

        self.bounceBox = QCheckBox("&Bounce", self)
        self.bounceBox.clicked.connect(lambda: self.updateGradient())
        self.toolBar.addWidget(self.bounceBox)
        
        self.sizeList = QComboBox(self)
        self.sizeList.addItem("None")
        for num in range(1, 8):
            self.sizeList.addItem(str(num))
        self.toolBar.addWidget(self.sizeList)
        
        self.cycleList = QComboBox(self)
        self.toolBar.addWidget(self.cycleList)
        self.cycleList.currentIndexChanged.connect(self.updateGradient)
        self.loadCycles()
        
        self.convertButton = QPushButton("&Convert", self)
        self.convertButton.clicked.connect(self.convert)
        self.toolBar.addWidget(self.convertButton)

        self.reloadButton = QPushButton("Reload", self)
        self.reloadButton.setShortcut("Alt+Shift+R")
        self.reloadButton.clicked.connect(self.loadCycles)
        self.toolBar.addWidget(self.reloadButton)

        self.inputDock = QDockWidget("Input", self)
        self.inputDock.setFeatures(QDockWidget.NoDockWidgetFeatures)
        self.inputDock.setContextMenuPolicy(Qt.CustomContextMenu)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.inputDock)

        self.inputField = QTextEdit(self)
        self.inputField.setAcceptRichText(False)
        self.inputDock.setWidget(self.inputField)

        self.outputField = QTextEdit(self)
        self.outputField.setReadOnly(True)
        self.setCentralWidget(self.outputField)

    def updateGradient(self, index=None):
        if not index:
            index = self.cycleList.currentIndex()
        self.toolBar.setStyleSheet(stylesheet % (create_gradient(self.cycleList.itemText(index), self.reverseBox.isChecked(), self.bounceBox.isChecked()),))

    def loadCycles(self):
        rainbowbb.load_cycles()
        self.cycleList.clear()
        self.cycleList.addItem("pastel")
        for cycle in sorted(list(rainbowbb.cycles.keys())):
            if cycle != "pastel":
                self.cycleList.addItem(cycle)

    def show(self):
        self.setVisible(True)
        self.inputField.setFocus()

    def convert(self):
        self.outputField.setPlainText(rainbowbb.size(rainbowbb.colorize(self.inputField.toPlainText(), self.cycleList.currentText(), self.reverseBox.isChecked(), not self.byWordBox.isChecked(), self.bounceBox.isChecked()), self.sizeList.currentText() if self.sizeList.currentText() != "None" else None))
示例#26
0
class MainWindow(QMainWindow):
    
    def __init__(self):
        super().__init__()
        
        self.setStyleSheet(
            """
                color: white;
                background-color: #2c2c2c;
                selection-background-color: #3b5784
            """)

        
        path = os.path.abspath(__file__)
        self.HOME = os.path.dirname(path) + '/'
        self.setWindowIcon(QIcon(self.HOME + 'images/crosscobra.png'))

        # change to Home Path
        os.chdir(Path.home())

        self.fileBrowser = None
        
        self.initUI()
        self.centerOnScreen()
        
        helpAction = QAction(self)
        helpAction.setShortcut('F1')
        helpAction.triggered.connect(self.help)
        
        self.addAction(helpAction)
    
    def initUI(self):        
        self.setGeometry(300, 300, 1200, 600)
        self.setWindowTitle('CrossCobra - Python IDE')
        
        # splitters
        splitter1 = QSplitter(Qt.Vertical)
        splitter2 = QSplitter(Qt.Horizontal)
        
        # widgets
        self.notebook = TabWidget(self)
        self.codeView = CodeView(self, self.notebook)

        self.notebook.newTab(codeView=self.codeView)

        self.textPad = self.notebook.textPad

        self.fileBrowser = FileBrowser(self, self.textPad, self.notebook, self.codeView)
        self.textPad.fileBrowser = self.fileBrowser

        # add widgets to splitters
        splitter1.addWidget(self.fileBrowser)
        splitter1.addWidget(self.codeView)
        w = splitter1.width()
        splitter1.setSizes([w//2, w//2])
        
        splitter2.addWidget(splitter1)
        splitter2.addWidget(self.notebook)
        
        hbox = QHBoxLayout()
        hbox.addWidget(splitter2)
        
        splitter1.setStretchFactor(1, 1)
        splitter2.setStretchFactor(1, 10)
        
        self.setCentralWidget(splitter2)
        
        # actions
        newAction = QAction(QIcon(self.HOME + 'images/new.png'), 'New', self)    

        newAction.setShortcut('Ctrl+N')
        newAction.triggered.connect(self.new)
        
        openAction = QAction(QIcon(self.HOME + 'images/open.png'), 'Open', self)
        openAction.setShortcut('Ctrl+O')
        openAction.triggered.connect(self.open)
        
        saveAction = QAction(QIcon(self.HOME + 'images/save.png'), 'Save', self)
        saveAction.setShortcut('Ctrl+S')
        saveAction.triggered.connect(self.save)
        
        saveAsAction = QAction(QIcon(self.HOME + 'images/saveAs.png'), 'Save As', self)
        saveAsAction.setShortcut('Ctrl+Shift+S')
        saveAsAction.triggered.connect(self.saveAs)
        
        printAction = QAction(QIcon(self.HOME + 'images/print.png'), 'Print', self)
        printAction.setShortcut('Ctrl+P')
        printAction.triggered.connect(self.onPrint)
        
        undoAction = QAction(QIcon(self.HOME + 'images/undo.png'), 'Undo', self)
        undoAction.setShortcut('Ctrl+Z')
        undoAction.triggered.connect(self.undo)

        redoAction = QAction(QIcon(self.HOME + 'images/redo.png'), 'Redo', self)
        redoAction.setShortcut('Ctrl+Shift+Z')
        redoAction.triggered.connect(self.redo)
        
        zoomInAction = QAction(QIcon(self.HOME + 'images/zoomIn.png'), 'ZoomIn', self)
        zoomInAction.setShortcut('Ctrl++')
        zoomInAction.triggered.connect(self.zoomIn)

        zoomOutAction = QAction(QIcon(self.HOME + 'images/zoomOut.png'), 'ZoomOut', self)
        zoomOutAction.setShortcut('Ctrl+-')
        zoomOutAction.triggered.connect(self.zoomOut)
        
        settingsAction = QAction(QIcon(self.HOME + 'images/settings.png'), 'Settings', self)
        settingsAction.setShortcut('F9')
        settingsAction.triggered.connect(self.showSettings)
              
        interpreterAction = QAction(QIcon(self.HOME + 'images/interpreter.png'), 'Start Python Interpreter', self)
        interpreterAction.setShortcut('F10')
        interpreterAction.triggered.connect(self.interpreter)
        
        terminalAction = QAction(QIcon(self.HOME + 'images/terminal.png'), 'Start Terminal', self)
        terminalAction.setShortcut('F11')
        terminalAction.triggered.connect(self.terminal)

        runAction = QAction(QIcon(self.HOME + 'images/run.png'), 'Run File', self)
        runAction.setShortcut('F12')
        runAction.triggered.connect(self.run)
        
        searchShortcut = QShortcut(self)
        searchShortcut.setKey('Ctrl+F')
        searchShortcut.activated.connect(self.onSearch)

        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        # make toolbar
        self.toolbar = QToolBar()
        self.toolbar.setStyleSheet('''
            QToolButton::hover { background-color: darkgreen;}
        ''')

        self.toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        self.addToolBar(Qt.RightToolBarArea, self.toolbar)
        
        self.toolbar.addSeparator()        
        self.toolbar.addAction(newAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(openAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(saveAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(saveAsAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(printAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(undoAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(redoAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(zoomInAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(zoomOutAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(settingsAction)
        self.toolbar.addSeparator()
        self.toolbar.addWidget(spacer)
        self.toolbar.addAction(interpreterAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(terminalAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(runAction)

      
        # make statusbar
        self.statusBar = QStatusBar()
        self.searchEdit = QLineEdit()
        spacer2 = QWidget()

        self.searchEdit.setStyleSheet(
            '''
                background-color: white;
                color: black;
            ''')
        self.searchEdit.returnPressed.connect(self.onSearch)
        self.searchButton = QPushButton(QIcon(self.HOME + 'images/search.png'), 'Search', self)
        self.searchButton.setStyleSheet(
        '''
            QPushButton::hover { background-color: darkgreen;}
        ''')
        self.searchButton.clicked.connect(self.onSearch)
        self.statusBar.addPermanentWidget(spacer2)
        self.statusBar.addPermanentWidget(self.searchEdit)
        self.statusBar.addPermanentWidget(self.searchButton)
        self.setStatusBar(self.statusBar)
        # show all
        self.textPad.setFocus()
        self.show()
        
    def new(self):
        editor = CodeEditor(parent=self)
        editor.filename = None
        
        self.notebook.newTab(editor)
        
        x = self.notebook.count()
        index = x - 1
        
        self.notebook.setCurrentIndex(index)
        self.textPad = editor
        self.notebook.textPad = editor
        self.mainWindow = self.textPad.mainWindow

    def open(self):
        dialog = QFileDialog(self)
        dialog.setViewMode(QFileDialog.List)
        dialog.setDirectory(os.getcwd())

        filename = dialog.getOpenFileName(self, "Save")
        
        if filename[0]:
            filePath = filename[0]
            
            try:
                with open(filePath, 'r') as f:
                    text = f.read()
                
                editor = CodeEditor(self)
                editor.setText(text) 
                editor.filename = filePath
                
                self.notebook.newTab(editor)
                x = self.notebook.count()   # number of tabs
                index = x - 1
                self.notebook.setCurrentIndex(index)
                
                tabName = os.path.basename(editor.filename)    
                self.notebook.setTabText(x, tabName)
                self.textPad = editor    
            
            except Exception as e:
                self.statusBar.showMessage(str(e), 3000)
            

    def save(self):
        filename = self.textPad.filename
        index = self.notebook.currentIndex()
        tabText = self.notebook.tabText(index)
        
        if not filename:
            self.saveAs()
        
        else:
            text = self.textPad.text()
            try:
                with open(filename, 'w') as file:
                    file.write(text)
                    self.statusBar.showMessage(filename + " saved", 3000)
                    
                    # remove '*' in tabText
                    fname = os.path.basename(filename)
                    self.notebook.setTabText(index, fname)
                    
            except Exception as e:
                self.statusBar.showMessage(str(e), 3000)
                self.saveAs()
    
    
    def saveAs(self):
        ## to do ....
        dialog = QFileDialog(self)
        dialog.setViewMode(QFileDialog.List)
        dialog.setDirectory(os.getcwd())

        filename = dialog.getSaveFileName(self, "Save")
        
        if filename[0]:
            fullpath = filename[0]
            text = self.textPad.text()
            try:
                with open(fullpath, 'w') as file:
                    file.write(text)
                    self.statusBar.showMessage(fullpath + " saved", 3000)
                                    
                    # update all widgets
                    
                    self.textPad.filename = fullpath
                    self.refresh(self.textPad)
                    self.fileBrowser.refresh()
                    fname = os.path.basename(fullpath)
                    index = self.notebook.currentIndex()
                    self.notebook.setTabText(index, fname)

            except Exception as e:
                self.statusBar.showMessage(str(e), 3000)
        
        else:
            self.statusBar.showMessage('File not saved !', 3000)
    
    
    def onPrint(self):
        doc = QsciPrinter()
        dialog = QPrintDialog(doc, self)
        dialog.setWindowTitle('Print')

        if (dialog.exec_() == QDialog.Accepted):
            self.textPad.setPythonPrintStyle()
            try:
                doc.printRange(self.textPad)
            except Exception as e:
                print(str(e))
                
        else:
            return
        
        self.textPad.setPythonStyle()

    def undo(self):
        self.textPad.undo()

    def redo(self):
        self.textPad.redo()
    
    def zoomIn(self):
        self.textPad.zoomIn()
    
    def zoomOut(self):
        self.textPad.zoomOut()

    def showSettings(self):
        dialog = SettingsDialog(self, self.textPad)
        dialog.setModal(False)
        dialog.exec_()
    
    def interpreter(self):
        c = Configuration()
        system = c.getSystem()
        command = c.getInterpreter(system)
        
        thread = RunThread(command)
        thread.start()
    
    def terminal(self):
        c = Configuration()
        system = c.getSystem()
        command = c.getTerminal(system)
        
        thread = RunThread(command)
        thread.start()
    
    def run(self):
        self.save()
        c = Configuration()
        system = c.getSystem()
        command = c.getRun(system).format(self.textPad.filename)
        
        if not self.textPad.filename:
            self.statusBar.showMessage("can't run without filename !", 3000)
            return 
            
        thread = RunThread(command)
        thread.start()
    
    def onSearch(self):
        text = self.searchEdit.text()
        if text == '':
            self.statusBar.showMessage("can't start search without word", 3000) 
            return
        else:
            x = self.textPad.findFirst(text, False, True, False, True, True) # case sensitive
    
            if x == False:
                l = len(self.searchEdit.text())
                self.searchEdit.setSelection(0, l)
                self.searchEdit.setFocus()
                self.statusBar.showMessage('<' + text + '> not found', 3000)

    def refresh(self, textPad=None):
        if not textPad:
            return
                 
        self.textPad = textPad

        if not self.textPad.filename:
            self.setWindowTitle('CrossCobra - Python IDE')
            return
        
        dir = os.path.dirname(self.textPad.filename)
        
        try:
            os.chdir(dir)
            self.setWindowTitle(self.textPad.filename)
        
        except Exception as e:
            self.statusBar.showMessage(str(e), 3000)
            
        self.fileBrowser.refresh(dir)
        self.codeView.refresh()
    
    def centerOnScreen(self):
        res = QDesktopWidget().screenGeometry()
        self.move((res.width() // 2) - (self.frameSize().width() // 2),
                  (res.height() // 2) - (self.frameSize().height() // 2))

    def help(self):
        helpdialog = HelpDialog(self)
        helpdialog.exec_()
示例#27
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(QMainWindow, self).__init__(parent)

        # Initialize UI
        self.setWindowTitle('Durumari')
        self.resize(800, 600)
        self.status_bar = self.statusBar()
        self.setStatusBar(self.status_bar)

        self.central_widget = QWidget(self)
        self.setCentralWidget(self.central_widget)

        self.layout = QHBoxLayout(self.central_widget)

        # Editor
        self.edit = ScriptEdit()
        self.layout.addWidget(self.edit)
        '''
        self.central_tab = QTabWidget()
        self.central_tab.addTab(ScriptEdit(), 'File 1')
        self.layout.addWidget(self.central_tab)
        '''

        # Scene Tree
        self.scn_tree = SceneTree(self)
        self.scn_tree.setMaximumSize(10000, 10000)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.scn_tree)

        # Tool Bar
        self.tool_bar = QToolBar()
        self.tool_bar.setContextMenuPolicy(Qt.PreventContextMenu)
        self.addToolBar(Qt.LeftToolBarArea, self.tool_bar)

        self.act_toggle_tree = set_action('Toggle Tree',
                                          QIcon('toggle_tree.png'), 'Ctrl+T')
        self.tool_bar.addAction(self.act_toggle_tree)
        self.tool_bar.setIconSize(QSize(24, 24))
        self.addToolBarBreak()

        # Menu Bar
        self.main_menu = self.menuBar()

        # <-*- File Menu
        self.file_menu = self.main_menu.addMenu('&File')

        self.act_new = set_action('&New ..', shortcut='Ctrl+N')
        self.act_open = set_action('&Open', shortcut='Ctrl+O')
        self.act_save = set_action('&Save', shortcut='Ctrl+S')

        self.file_menu.addAction(self.act_new)
        self.file_menu.addAction(self.act_open)
        self.file_menu.addAction(self.act_save)
        self.file_menu.addSeparator()
        # File Menu -*->

        # <-*- Text Menu
        self.text_menu = self.main_menu.addMenu('&Text')

        self.act_font = set_action('Font', shortcut='Ctrl+Alt+F')

        self.text_menu.addAction(self.act_font)
        self.text_menu.addSeparator()