Beispiel #1
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)
Beispiel #2
0
    def setup(self):
        # icons
        self.homeIcon = Icon('home.svg', '#0A0').getIcon()
        self.csvIcon = Icon('file-csv.svg', '#D50').getIcon()
        self.dbIcon = Icon('database.svg', '#666').getIcon()

        # Setup ToolBar
        toolBar = QToolBar('Left Menu', self)
        toolBar.setFloatable(False)
        toolBar.setMovable(False)
        toolBar.setIconSize(QSize(64, 64))
        toolBar.setStyleSheet('background-color: #004; color: #FFF;')

        # Tabs Properties
        self.TabContainer.setTabsClosable(True)
        self.TabContainer.tabCloseRequested.connect(self.closeTab)

        # Home
        home = QAction(self.homeIcon, 'Home', self)
        home.triggered.connect(self.onHome)
        self.TabContainer.addTab(self.home, self.homeIcon, 'Home')

        # CSV
        loadCSV = QAction(self.csvIcon, 'Load CSV', self)
        loadCSV.triggered.connect(self.onLoadCSV)

        # DB
        loadDB = QAction(self.dbIcon, 'Load From DataBase', self)
        loadDB.triggered.connect(self.onLoadDB)

        # Add to ToolBar
        toolBar.addAction(home)
        toolBar.addAction(loadCSV)
        toolBar.addAction(loadDB)
        self.addToolBar(Qt.LeftToolBarArea, toolBar)
Beispiel #3
0
    def __init__(self, parentWidget, settings):
        QWidget.__init__(self, parentWidget)
        self.settings = settings

        toolbar = QToolBar(self)
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        addAction = QAction("+", toolbar)
        addAction.triggered.connect(self.addNotepad)
        toolbar.addAction(addAction)

        removeAction = QAction("-", toolbar)
        removeAction.triggered.connect(self.removeNotepad)
        toolbar.addAction(removeAction)

        self.browserView = TreeWidget(self)

        hLayout = QVBoxLayout(self)
        hLayout.setContentsMargins(0, 0, 0, 1)
        hLayout.addWidget(toolbar)
        hLayout.addWidget(self.browserView)

        self.currentItem = None
        self.browserView.itemSelectionChanged.connect(self.handleItemSelected)
Beispiel #4
0
    def __init__(self, parentWidget, settings):
        QWidget.__init__(self, parentWidget)
        self.settings = settings

        toolbar = QToolBar(self)
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        addAction = QAction("+", toolbar)
        addAction.triggered.connect(self.addNotepad)
        toolbar.addAction(addAction)

        removeAction = QAction("-", toolbar)
        removeAction.triggered.connect(self.removeNotepad)
        toolbar.addAction(removeAction)

        self.browserView = TreeWidget(self)

        hLayout = QVBoxLayout(self)
        hLayout.setContentsMargins(0, 0, 0, 1)
        hLayout.addWidget(toolbar)
        hLayout.addWidget(self.browserView)

        self.currentItem = None
        self.browserView.itemSelectionChanged.connect(self.handleItemSelected)
Beispiel #5
0
    def init_menu(self):
        load_rom = self.create_action('載入Rom', self.load_rom)
        save_rom = self.create_action('保存Rom', self.save_rom)
        save_rom.setEnabled(False)
        save_as = self.create_action('另存為', self.save_as)
        save_as.setEnabled(False)
        close_child = self.create_action('關閉窗口', self.close_child)
        exit_editor = self.create_action('退出', self.close)
        file_menu = self.create_menu(
            '文件(&F)', None,
            [load_rom, save_rom, save_as, close_child, exit_editor])

        value_editors = [
            self.create_action(editor_name, self.open_editor_frame)
            for editor_name in CHILD_MAPPING
        ]

        edit_menu = self.create_menu('編輯(&E)', None, value_editors)
        edit_menu.setEnabled(False)

        self.menuBar().addMenu(file_menu)
        self.menuBar().addMenu(edit_menu)

        tool_bar = QToolBar('顯示標籤')
        tool_bar.setObjectName('工具')
        tool_bar.addActions(value_editors)
        tool_bar.setEnabled(False)
        tool_bar.setMovable(False)
        tool_bar.setVisible(False)
        self.addToolBar(tool_bar)

        action_group = QActionGroup(self)
        [(action_group.addAction(i), i.setCheckable(True))
         for i in value_editors]
        action_group.setExclusive(True)
    def _create_tool_bar(self):
        tools_toolbar = QToolBar('Tools')
        tools_toolbar.addAction(self.file_open)
        tools_toolbar.setFloatable(False)
        tools_toolbar.setMovable(False)

        self.addToolBar(tools_toolbar)
Beispiel #7
0
    def invoke(self):
        """
        the real setup function to show someting.
        """
        self.setupUi(self)

        # make sure the first col show full
        self.yeahdoclisttree.header().setResizeMode(0, QHeaderView.ResizeToContents)

        self.__initAction()

        # toolbar .
        classToolbar = QToolBar()
        classToolbar.setIconSize(QSize(16, 16))
        classToolbar.setMovable(False)
        self.rightsplitter.insertWidget(0, classToolbar)

        classToolbar.addAction(self.__actions["__yeahdoc_c_new__"])
        classToolbar.addAction(self.__actions["__yeahdoc_c_edit__"])
        classToolbar.addAction(self.__actions["__yeahdoc_c_rename__"])
        classToolbar.addAction(self.__actions["__yeahdoc_c_delete__"])
        classToolbar.addWidget(self.__evt_category_view())

        # More useful gadgets
        self.togglebtn.setIcon(QIcon(getPath("iconDir", "yeahdoc/right.png")))

        # read datas from db .
        self.__setupYeahdocCategoryDatas()
        self.__setupyeahdoclisttreeDatas()
Beispiel #8
0
    def Menu_init(self):
        menubar = self.menuBar()
        # 菜单栏
        mfile = menubar.addMenu("文件")
        themefile = menubar.addMenu("主题")
        # 重置
        reset_canvas_act = QAction(QIcon("./icon/file.png"), "重置画布", self)

        reset_canvas_act.triggered.connect(
            self.reset_canvas_action)  # To be done

        # 保存
        save_canvas_act = QAction(QIcon("./icon/save.png"), "保存画布", self)
        save_canvas_act.triggered.connect(self.save_canvas_action)

        #默认主题:
        theme1_act = QAction("Blue theme", self)
        theme1_act.triggered.connect(self.theme1_action)
        theme2_act = QAction("Coffee theme", self)
        theme2_act.triggered.connect(self.theme2_action)
        # 将action添加到file上面
        mfile.addAction(reset_canvas_act)
        mfile.addAction(save_canvas_act)
        #将action添加到theme上面
        themefile.addAction(theme1_act)
        themefile.addAction(theme2_act)
        # 工具栏
        toolbar = QToolBar()
        toolbar.setMovable(False)
        self.addToolBar(toolbar)
        toolbar.addAction(reset_canvas_act)
        toolbar.addAction(save_canvas_act)
Beispiel #9
0
    def __init__(self, wallet_api: WalletAPI, parent: QWidget) -> None:
        super().__init__(parent)

        self._context = ListContext(wallet_api, self)

        cards = Cards(self._context, self)

        sort_action = QAction(self)
        sort_action.setIcon(
            read_QIcon("icons8-alphabetical-sorting-2-80-blueui.png"))
        sort_action.setToolTip(_("Sort"))
        sort_action.triggered.connect(self._on_sort_action)
        sort_action.setEnabled(self._context.sortable_list)

        toolbar = QToolBar(self)
        toolbar.setMovable(False)
        toolbar.setOrientation(Qt.Vertical)
        toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        toolbar.addAction(sort_action)

        self._layout = QHBoxLayout()
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)
        self._layout.addWidget(cards)
        self._layout.addWidget(toolbar)
        self.setLayout(self._layout)

        self._cards = cards
        self._sort_action = sort_action
        self._sort_type = 1
Beispiel #10
0
    def __init__(self, wallet_api: WalletAPI, parent: Optional['ElectrumWindow']=None):
        super().__init__(parent)

        self._context = ListContext(wallet_api, self)

        cards = ContactCards(self._context, self)
        self.setStyleSheet(contactcard_stylesheet)

        add_contact_action = QAction(self)
        add_contact_action.setIcon(read_QIcon("icons8-plus-blueui.svg"))
        add_contact_action.setToolTip(_("Add new contact"))
        add_contact_action.triggered.connect(self._on_add_contact_action)

        sort_action = QAction(self)
        sort_action.setIcon(read_QIcon("icons8-alphabetical-sorting-2-80-blueui.png"))
        sort_action.setToolTip(_("Sort"))
        sort_action.triggered.connect(self._on_sort_action)

        toolbar = QToolBar(self)
        toolbar.setMovable(False)
        toolbar.setOrientation(Qt.Vertical)
        toolbar.setToolButtonStyle(Qt.ToolButtonIconOnly)
        toolbar.addAction(add_contact_action)
        toolbar.addAction(sort_action)

        self._layout = QHBoxLayout()
        self._layout.setContentsMargins(0, 0, 0, 0)
        self._layout.setSpacing(0)
        self._layout.addWidget(cards)
        self._layout.addWidget(toolbar)
        self.setLayout(self._layout)

        self._cards = cards
        self._sort_action = sort_action
        self._sort_type = 1
Beispiel #11
0
    def __init__(self, parent):
        TitledToolbar.__init__(self, parent, 'Actions')

        toolbar = QToolBar(self)
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        self.saveAction = QAction(QIcon(":/icons/file-save.png"),
                                  "Save (Ctrl-S)", toolbar)
        self.saveAction.setShortcut(Qt.CTRL + Qt.Key_S)
        self.saveAction.triggered.connect(parent.save)
        toolbar.addAction(self.saveAction)

        self.nonprintableAction = QAction(
            QIcon(":/icons/view-nonprintable.png"), "View nonprintable chars",
            toolbar)
        self.nonprintableAction.setCheckable(True)
        self.nonprintableAction.triggered.connect(parent.toggleNonprintable)
        toolbar.addAction(self.nonprintableAction)

        self.undoAction = QAction(QIcon(":/icons/edit-undo.png"),
                                  "Undo (Ctrl-Z)", toolbar)
        # saveAction.setShortcut(Qt.CTRL + Qt.Key_Z);
        self.undoAction.triggered.connect(parent.undo)
        toolbar.addAction(self.undoAction)

        self.redoAction = QAction(QIcon(":/icons/edit-redo.png"),
                                  "Redo (Ctrl-Y)", toolbar)
        # saveAction.setShortcut(Qt.CTRL + Qt.Key_Y);
        self.redoAction.triggered.connect(parent.redo)
        toolbar.addAction(self.redoAction)

        self.backAction = QAction(QIcon(":/icons/view-back.png"), "Back",
                                  toolbar)
        self.backAction.setEnabled(False)
        self.backAction.triggered.connect(parent.navigateBack)
        toolbar.addAction(self.backAction)

        self.forwardAction = QAction(QIcon(":/icons/view-forward.png"),
                                     "Forward", toolbar)
        self.forwardAction.setEnabled(False)
        self.forwardAction.triggered.connect(parent.navigateForward)
        toolbar.addAction(self.forwardAction)

        insertImageAction = QAction(QIcon(":/icons/edit-insert-image.png"),
                                    "Insert Image", toolbar)
        insertImageAction.triggered.connect(parent.insertImage)
        toolbar.addAction(insertImageAction)

        insertFormulaAction = QAction("f(x)", toolbar)
        insertFormulaAction.triggered.connect(parent.insertFormula)
        toolbar.addAction(insertFormulaAction)

        findInPageAction = QAction(QIcon(":/icons/edit-find.png"),
                                   "Find in page (CTRL-F)", toolbar)
        findInPageAction.setShortcut(Qt.CTRL + Qt.Key_F)
        findInPageAction.triggered.connect(parent.findInPage)
        toolbar.addAction(findInPageAction)

        self.addWidget(toolbar)
Beispiel #12
0
    def initUI(self):
        toolbar = QToolBar()
        toolbar.setMovable(False)
        self.addToolBar(Qt.LeftToolBarArea,toolbar) # Switched toolbar to left cause it looked cool
        
        # Saved Notes
        # ------------------------------------------------------------------------------------- #
        self.notes_heading = QtWidgets.QLabel('Saved Notes',self)
        toolbar.addWidget(self.notes_heading)
        toolbar.addSeparator()

        all_saved = ["title", "test", "example"]
        self.saved_note_buttons = []

        for i in all_saved:
            self.saved_note_buttons.append(savedNote(i, self))
            self.saved_note_buttons[::-1][0].display.triggered.connect(self.saved_note_buttons[::-1][0].clicked)
            toolbar.addAction(self.saved_note_buttons[::-1][0].display)


        # Pages heading
        # ------------------------------------------------------------------------------------- #
        self.pages_head = QtWidgets.QLabel('Pages',self)
        toolbar.addWidget(self.pages_head)
        toolbar.addSeparator()

        self.nextPageButton = QAction(QIcon('resources/NewPageIcon.PNG'),'Next/New page',self)
        self.nextPageButton.triggered.connect(self.NextPage)
        toolbar.addAction(self.nextPageButton)

        self.lastPageButton = QAction(QIcon('resources/InvalidLastPageIcon.PNG'),'Previous page',self)
        self.lastPageButton.triggered.connect(self.LastPage)
        toolbar.addAction(self.lastPageButton)

        self.pageDisplay = QtWidgets.QLabel('1 / 1', self)#.setAlignment(Qt.AlignCenter) Trying to center it (horizontally), not working rn.
        toolbar.addWidget(self.pageDisplay)


        # Special controls heading
        # ------------------------------------------------------------------------------------- #
        self.controls_head = QtWidgets.QLabel('Controls',self)
        toolbar.addWidget(self.controls_head)
        toolbar.addSeparator()

        self.interpretButton = QAction(QIcon('resources/InterpretIcon.PNG'),'Interpret',self)
        self.interpretButton.triggered.connect(self.ReadText)
        toolbar.addAction(self.interpretButton)

        self.boardSwitchButton = QAction('Swap Input', self)
        self.boardSwitchButton.triggered.connect(self.BoardSwitch)
        toolbar.addAction(self.boardSwitchButton)

        self.newLineButton = QAction('New line', self)
        self.newLineButton.triggered.connect(self.NewLine)
        toolbar.addAction(self.newLineButton)
                                       
        self.setGeometry(200,200,750,600)
        self.setWindowTitle('PiPad')
        self.show()
Beispiel #13
0
    def initToolBar(self):
        enlargeAction = QAction(QIcon('icon/enlarge.png'), 'Enlarge', self)
        enlargeAction.setShortcut('Ctrl+E')
        enlargeAction.setStatusTip('Enlarge')
        enlargeAction.triggered.connect(self.enlarge)

        narrowAction = QAction(QIcon('icon/narrow.png'), 'Narrow', self)
        narrowAction.setShortcut('Ctrl+N')
        narrowAction.setStatusTip('Narrow')
        narrowAction.triggered.connect(self.narrow)

        restartAction = QAction(QIcon('icon/redo.png'), 'Restart', self)
        restartAction.setShortcut('Ctrl+R')
        restartAction.setStatusTip('Restart')
        restartAction.triggered.connect(self.restart)

        addLabelAction = QAction(QIcon('icon/add-label.png'), 'Label', self)
        addLabelAction.setShortcut('Ctrl+Q')
        addLabelAction.setStatusTip('Label')
        addLabelAction.triggered.connect(self.label)

        undoAction = QAction(QIcon('icon/undo.png'), 'Undo', self)
        undoAction.setShortcut('Ctrl+Z')
        undoAction.setStatusTip('Undo')
        undoAction.triggered.connect(self.undo)

        lastImageAction = QAction(QIcon('icon/top.png'), 'Last', self)
        lastImageAction.setStatusTip('Last')
        lastImageAction.triggered.connect(self.last)

        nextImageAction = QAction(QIcon('icon/down.png'), 'Next', self)
        nextImageAction.setStatusTip('Next')
        nextImageAction.triggered.connect(self.next)

        saveAction = QAction(QIcon('icon/save.png'), 'Save', self)
        saveAction.setShortcut('Ctrl+S')
        saveAction.setStatusTip('Save')
        saveAction.triggered.connect(self.save)

        toolbar = QToolBar('Label')
        toolbar.addAction(enlargeAction)
        toolbar.addSeparator()
        toolbar.addAction(narrowAction)
        toolbar.addSeparator()
        toolbar.addAction(restartAction)
        toolbar.addSeparator()
        toolbar.addAction(addLabelAction)
        toolbar.addSeparator()
        toolbar.addAction(undoAction)
        toolbar.addSeparator()
        toolbar.addAction(lastImageAction)
        toolbar.addSeparator()
        toolbar.addAction(nextImageAction)
        toolbar.addSeparator()
        toolbar.addAction(saveAction)
        toolbar.setMovable(False)
        toolbar.setStyleSheet("QWidget { background-color: %s }" % '#FEFEFE')
        self.addToolBar(Qt.RightToolBarArea, toolbar)
    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)
Beispiel #15
0
    def initToolBar(self):
        toolbarBox = QToolBar(self)
        self.addToolBar(Qt.LeftToolBarArea, toolbarBox)
        toolbarBox.setMovable(False)
        toolbarBox.setStyleSheet("background-color:#444444;color:#000000;")

        resize = QAction(QIcon('Resize.png'), "Resize", self)
        toolbarBox.addAction(resize)
        toolbarBox.actionTriggered[QAction].connect(self.toolBtnPressed)
Beispiel #16
0
    def __init__(self, toolbar):
        TitledToolbar.__init__(self, toolbar, 'Text style')
        self.currentStyle = None

        toolbar = QToolBar(self)
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        self.styleToAction = {}

        textKeywordAction = QAction(QIcon(':/icons/format-keyword.png'),
                                    'Notepad link', toolbar)
        textKeywordAction.setCheckable(True)
        selector = ('olink', None, None)
        textKeywordAction.setProperty('style', selector)
        self.styleToAction[selector] = textKeywordAction
        textKeywordAction.triggered.connect(self.styleSelected)
        toolbar.addAction(textKeywordAction)

        textLinkAction = QAction(QIcon(':/icons/format-link.png'),
                                 'Internet link', toolbar)
        textLinkAction.setCheckable(True)
        selector = ('link', None, None)
        textLinkAction.setProperty('style', selector)
        self.styleToAction[selector] = textLinkAction
        textLinkAction.triggered.connect(self.styleSelected)
        toolbar.addAction(textLinkAction)

        textBoldAction = QAction(QIcon(':/icons/format-text-emphasized.png'),
                                 'Emphasize', toolbar)
        textBoldAction.setCheckable(True)
        selector = ('emphasis', None, None)
        textBoldAction.setProperty('style', selector)
        self.styleToAction[selector] = textBoldAction
        textBoldAction.triggered.connect(self.styleSelected)
        toolbar.addAction(textBoldAction)

        textHighlightAction = QAction(
            QIcon(':/icons/format-text-highlight.png'), 'Highlight', toolbar)
        textHighlightAction.setCheckable(True)
        selector = ('emphasis', 'role', 'highlight')
        textHighlightAction.setProperty('style', selector)
        self.styleToAction[selector] = textHighlightAction
        textHighlightAction.triggered.connect(self.styleSelected)
        toolbar.addAction(textHighlightAction)

        textCodeAction = QAction(QIcon(':/icons/format-text-code.png'), 'Code',
                                 toolbar)
        textCodeAction.setCheckable(True)
        selector = ('code', None, None)
        textCodeAction.setProperty('style', selector)
        self.styleToAction[selector] = textCodeAction
        textCodeAction.triggered.connect(self.styleSelected)
        toolbar.addAction(textCodeAction)

        self.addWidget(toolbar)
Beispiel #17
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()
Beispiel #18
0
    def _create_toolbar(self, color_maps):
        toolbar = QToolBar()
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        self._layout_combo = LayoutCombo()
        self._layout_combo_action = QWidgetAction(self._layout_combo)
        self._layout_combo_action.setDefaultWidget(self._layout_combo)
        toolbar.addAction(self._layout_combo_action)
        self._layout_combo.layout_changed.connect(
            self._slice_view_widget.set_plot_layout)

        # self._colormap_combo = ColormapCombo(['seismic', 'spectral', 'RdGy', 'hot', 'jet', 'gray'])
        self._colormap_combo = ColormapCombo(color_maps)
        self._colormap_combo.currentIndexChanged[int].connect(
            self._colormap_changed)
        toolbar.addWidget(self._colormap_combo)

        self._save_button = QToolButton()
        self._save_button.setToolTip("Save as image")
        self._save_button.setIcon(resource_icon("table_export.png"))
        self._save_button.clicked.connect(self._save_figure)
        toolbar.addWidget(self._save_button)

        self._settings_button = QToolButton()
        self._settings_button.setToolTip("Toggle settings visibility")
        self._settings_button.setIcon(resource_icon("cog.png"))
        self._settings_button.setCheckable(True)
        self._settings_button.toggled.connect(self._show_settings)
        toolbar.addWidget(self._settings_button)

        self._help_button = QToolButton()
        self._help_button.setToolTip("View help")
        self._help_button.setIcon(resource_icon("help.png"))
        self._help_button.setCheckable(True)
        self._help_button.toggled.connect(self._show_help)
        toolbar.addWidget(self._help_button)

        def toggle_on_close(event):
            self._settings_button.setChecked(False)
            event.accept()

        def toggle_on_close_help(event):
            self._help_button.setChecked(False)
            event.accept()

        self._settings_window.closeEvent = toggle_on_close
        self._help_window.closeEvent = toggle_on_close_help

        self._colormap_combo.setCurrentIndex(45)
        self.set_default_layout()

        return toolbar
Beispiel #19
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.mOpacityLabel = QLabel()
        self.mOpacitySlider = QSlider(Qt.Horizontal)
        self.mLayerView = LayerView()
        self.mMapDocument = None
        self.mUpdatingSlider = False
        self.mChangingLayerOpacity = False
        self.mUpdatingSlider = False

        self.setObjectName("layerDock")
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)
        opacityLayout = QHBoxLayout()
        self.mOpacitySlider.setRange(0, 100)
        self.mOpacitySlider.setEnabled(False)
        opacityLayout.addWidget(self.mOpacityLabel)
        opacityLayout.addWidget(self.mOpacitySlider)
        self.mOpacityLabel.setBuddy(self.mOpacitySlider)
        handler = MapDocumentActionHandler.instance()
        newLayerMenu = QMenu(self)
        newLayerMenu.addAction(handler.actionAddTileLayer())
        newLayerMenu.addAction(handler.actionAddObjectGroup())
        newLayerMenu.addAction(handler.actionAddImageLayer())
        newIcon = QIcon(":/images/16x16/document-new.png")
        newLayerButton = QToolButton()
        newLayerButton.setPopupMode(QToolButton.InstantPopup)
        newLayerButton.setMenu(newLayerMenu)
        newLayerButton.setIcon(newIcon)
        Utils.setThemeIcon(newLayerButton, "document-new")
        buttonContainer = QToolBar()
        buttonContainer.setFloatable(False)
        buttonContainer.setMovable(False)
        buttonContainer.setIconSize(QSize(16, 16))
        buttonContainer.addWidget(newLayerButton)
        buttonContainer.addAction(handler.actionMoveLayerUp())
        buttonContainer.addAction(handler.actionMoveLayerDown())
        buttonContainer.addAction(handler.actionDuplicateLayer())
        buttonContainer.addAction(handler.actionRemoveLayer())
        buttonContainer.addSeparator()
        buttonContainer.addAction(handler.actionToggleOtherLayers())
        listAndToolBar = QVBoxLayout()
        listAndToolBar.setSpacing(0)
        listAndToolBar.addWidget(self.mLayerView)
        listAndToolBar.addWidget(buttonContainer)
        layout.addLayout(opacityLayout)
        layout.addLayout(listAndToolBar)
        self.setWidget(widget)
        self.retranslateUi()
        self.mOpacitySlider.valueChanged.connect(self.sliderValueChanged)
        self.updateOpacitySlider()
Beispiel #20
0
    def __init__(self, parent = None):
        super().__init__(parent)
        self.mOpacityLabel = QLabel()
        self.mOpacitySlider = QSlider(Qt.Horizontal)
        self.mLayerView = LayerView()
        self.mMapDocument = None
        self.mUpdatingSlider = False
        self.mChangingLayerOpacity = False
        self.mUpdatingSlider = False

        self.setObjectName("layerDock")
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)
        opacityLayout = QHBoxLayout()
        self.mOpacitySlider.setRange(0, 100)
        self.mOpacitySlider.setEnabled(False)
        opacityLayout.addWidget(self.mOpacityLabel)
        opacityLayout.addWidget(self.mOpacitySlider)
        self.mOpacityLabel.setBuddy(self.mOpacitySlider)
        handler = MapDocumentActionHandler.instance()
        newLayerMenu = QMenu(self)
        newLayerMenu.addAction(handler.actionAddTileLayer())
        newLayerMenu.addAction(handler.actionAddObjectGroup())
        newLayerMenu.addAction(handler.actionAddImageLayer())
        newIcon = QIcon(":/images/16x16/document-new.png")
        newLayerButton = QToolButton()
        newLayerButton.setPopupMode(QToolButton.InstantPopup)
        newLayerButton.setMenu(newLayerMenu)
        newLayerButton.setIcon(newIcon)
        Utils.setThemeIcon(newLayerButton, "document-new")
        buttonContainer = QToolBar()
        buttonContainer.setFloatable(False)
        buttonContainer.setMovable(False)
        buttonContainer.setIconSize(QSize(16, 16))
        buttonContainer.addWidget(newLayerButton)
        buttonContainer.addAction(handler.actionMoveLayerUp())
        buttonContainer.addAction(handler.actionMoveLayerDown())
        buttonContainer.addAction(handler.actionDuplicateLayer())
        buttonContainer.addAction(handler.actionRemoveLayer())
        buttonContainer.addSeparator()
        buttonContainer.addAction(handler.actionToggleOtherLayers())
        listAndToolBar = QVBoxLayout()
        listAndToolBar.setSpacing(0)
        listAndToolBar.addWidget(self.mLayerView)
        listAndToolBar.addWidget(buttonContainer)
        layout.addLayout(opacityLayout)
        layout.addLayout(listAndToolBar)
        self.setWidget(widget)
        self.retranslateUi()
        self.mOpacitySlider.valueChanged.connect(self.sliderValueChanged)
        self.updateOpacitySlider()
Beispiel #21
0
    def _defineToolBar(self) -> None:
        toolBar = QToolBar(self)
        toolBar.setMovable(False)

        # add actions
        toolBar.addAction(self.actionAdd)
        toolBar.addAction(self.actionRemove)
        toolBar.addSeparator()
        toolBar.addAction(self.actionRemoveAll)
        toolBar.addSeparator()
        toolBar.addAction(self.actionSave)

        self.addToolBar(toolBar)
Beispiel #22
0
    def __init__(self, parent):
        TitledToolbar.__init__(self, parent, 'Actions')
 
        toolbar = QToolBar(self)
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        self.saveAction = QAction(QIcon(":/icons/file-save.png"), "Save (Ctrl-S)", toolbar)
        self.saveAction.setShortcut(Qt.CTRL + Qt.Key_S);
        self.saveAction.triggered.connect(parent.save)
        toolbar.addAction(self.saveAction)

        self.nonprintableAction = QAction(QIcon(":/icons/view-nonprintable.png"), "View nonprintable chars", toolbar)
        self.nonprintableAction.setCheckable(True);
        self.nonprintableAction.triggered.connect(parent.toggleNonprintable)
        toolbar.addAction(self.nonprintableAction)

        self.undoAction = QAction(QIcon(":/icons/edit-undo.png"), "Undo (Ctrl-Z)", toolbar)
        # saveAction.setShortcut(Qt.CTRL + Qt.Key_Z);
        self.undoAction.triggered.connect(parent.undo)
        toolbar.addAction(self.undoAction)

        self.redoAction = QAction(QIcon(":/icons/edit-redo.png"), "Redo (Ctrl-Y)", toolbar)
        # saveAction.setShortcut(Qt.CTRL + Qt.Key_Y);
        self.redoAction.triggered.connect(parent.redo)
        toolbar.addAction(self.redoAction)

        self.backAction = QAction(QIcon(":/icons/view-back.png"), "Back", toolbar)
        self.backAction.setEnabled(False)
        self.backAction.triggered.connect(parent.navigateBack)
        toolbar.addAction(self.backAction)

        self.forwardAction = QAction(QIcon(":/icons/view-forward.png"), "Forward", toolbar)
        self.forwardAction.setEnabled(False)
        self.forwardAction.triggered.connect(parent.navigateForward)
        toolbar.addAction(self.forwardAction)

        insertImageAction = QAction(QIcon(":/icons/edit-insert-image.png"), "Insert Image", toolbar)
        insertImageAction.triggered.connect(parent.insertImage)
        toolbar.addAction(insertImageAction)

        insertFormulaAction = QAction("f(x)", toolbar)
        insertFormulaAction.triggered.connect(parent.insertFormula)
        toolbar.addAction(insertFormulaAction)

        findInPageAction = QAction(QIcon(":/icons/edit-find.png"), "Find in page (CTRL-F)", toolbar)
        findInPageAction.setShortcut(Qt.CTRL + Qt.Key_F);
        findInPageAction.triggered.connect(parent.findInPage)
        toolbar.addAction(findInPageAction)

        self.addWidget(toolbar)
Beispiel #23
0
    def __init__(self, toolbar):
        TitledToolbar.__init__(self, toolbar, 'Text style')
        self.currentStyle = None

        toolbar = QToolBar(self)
        toolbar.setFloatable(False)
        toolbar.setMovable(False)

        self.styleToAction = {}

        textKeywordAction = QAction(QIcon(':/icons/format-keyword.png'), 'Notepad link', toolbar)
        textKeywordAction.setCheckable(True);
        selector = ('olink', None, None)
        textKeywordAction.setProperty('style', selector)
        self.styleToAction[selector] = textKeywordAction
        textKeywordAction.triggered.connect(self.styleSelected)
        toolbar.addAction(textKeywordAction)

        textLinkAction = QAction(QIcon(':/icons/format-link.png'), 'Internet link', toolbar)
        textLinkAction.setCheckable(True);
        selector = ('link', None, None)
        textLinkAction.setProperty('style', selector)
        self.styleToAction[selector] = textLinkAction 
        textLinkAction.triggered.connect(self.styleSelected)
        toolbar.addAction(textLinkAction)

        textBoldAction = QAction(QIcon(':/icons/format-text-emphasized.png'), 'Emphasize', toolbar)
        textBoldAction.setCheckable(True);
        selector = ('emphasis', None, None)
        textBoldAction.setProperty('style', selector)
        self.styleToAction[selector] = textBoldAction
        textBoldAction.triggered.connect(self.styleSelected)
        toolbar.addAction(textBoldAction)

        textHighlightAction = QAction(QIcon(':/icons/format-text-highlight.png'), 'Highlight', toolbar)
        textHighlightAction.setCheckable(True);
        selector = ('emphasis', 'role', 'highlight')
        textHighlightAction.setProperty('style', selector)
        self.styleToAction[selector] = textHighlightAction
        textHighlightAction.triggered.connect(self.styleSelected)
        toolbar.addAction(textHighlightAction)
 
        textCodeAction = QAction(QIcon(':/icons/format-text-code.png'), 'Code', toolbar)
        textCodeAction.setCheckable(True);
        selector = ('code', None, None)
        textCodeAction.setProperty('style', selector)
        self.styleToAction[selector] = textCodeAction
        textCodeAction.triggered.connect(self.styleSelected)
        toolbar.addAction(textCodeAction)

        self.addWidget(toolbar)
Beispiel #24
0
 def init_topmenu(self):
     topmenu = QToolBar()
     Sync_Button = QPushButton("Sync")
     Sync_Button.clicked.connect(self.do_sync)
     Last_Updated = QLabel("Last Updated:")
     settings = QPushButton("Settings")
     settings.clicked.connect(self.popup_settings)
     topmenu.addWidget(Sync_Button)
     topmenu.addSeparator()
     topmenu.addWidget(Last_Updated)
     topmenu.addWidget(settings)
     # Do not let the user drag the toolbar around
     topmenu.setMovable(False)
     return topmenu
Beispiel #25
0
    def _createContractionToolbar(self):
        toolbar = QToolBar(parent=self)
        toolbar.setFloatable(True)
        toolbar.setMovable(True)
        toolbar.hide()

        action = toolbar.addAction('next')
        action.triggered.connect(self.next_hg)
        action = toolbar.addAction('previous')
        action.triggered.connect(self.previous_hg)
        action = toolbar.addAction('stop')
        action.triggered.connect(self.stopContractionPlayerSlot)

        self.contraction_toolbar = toolbar
    def setupToolbar(self):
        """Create the toolbar for navigating web pages."""
        toolbar = QToolBar()
        toolbar.setIconSize(QSize(24, 24))
        toolbar.setMovable(False)
        self.addToolBar(toolbar)

        # Create actions
        back_act = QAction(QIcon("icons/back.png"), "Back Button", toolbar)
        back_act.triggered.connect(self.web_view.back)

        forward_act = QAction(QIcon("icons/forward.png"), "Forward Button", toolbar)
        forward_act.triggered.connect(self.web_view.forward)

        # Add actions to the toolbar
        toolbar.addAction(back_act)
        toolbar.addAction(forward_act)
Beispiel #27
0
    def __init__(self):
        super().__init__()

        Util.Style.applyStyle(self)
        Util.Style.applyWindowTitle(self)
        Util.Style.applyWindowIcon(self)

        self.stack = QStackedWidget()
        self.stackList = {}
        self.jsonView = None
        self.requestView = None

        mainToolbar = QToolBar()
        mainToolbar.setMovable(False)
        topWidget = QWidget()
        topWidget.setFixedHeight(8)
        mainToolbar.addWidget(topWidget)
        self.requestAction = mainToolbar.addAction(
            PResource.invertIcon(Parapluie.Icon_Link_Svg), "Request",
            self.showRequest)
        self.requestAction.setCheckable(True)
        self.jsonAction = mainToolbar.addAction(
            PResource.invertIcon(Parapluie.Icon_Web_Development_Svg), "Viewer",
            self.showJSONViewer)
        self.jsonAction.setCheckable(True)

        stretchWidget = QWidget()
        stretchWidget.setSizePolicy(QSizePolicy.Expanding,
                                    QSizePolicy.Expanding)
        mainToolbar.addWidget(stretchWidget)
        mainToolbar.addAction(
            PResource.invertIcon(Parapluie.Icon_Information_Svg),
            "Information", self.openAbout)

        self.addToolBar(Qt.LeftToolBarArea, mainToolbar)

        bottomWidget = QWidget()
        bottomWidget.setFixedHeight(8)
        mainToolbar.addWidget(bottomWidget)

        self.stack.currentChanged.connect(self.stackChange)

        self.setCentralWidget(self.stack)
        self.setContentsMargins(0, 0, 0, 0)

        self.showRequest()
    def add_toolbar(self, title=None, toolbar=None):
        """Creates, adds and returns a QToolBar
        """
        if 1 != bool(toolbar) + bool(title):
            raise ValueError('Just one of toolbar or title should be given')
        if not toolbar:
            toolbar = QToolBar(title)
        toolbar.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
        self.addTab(toolbar, toolbar.windowTitle())

        # This style applies to QToolButtons that are immediate children
        # of the toolbar - it does not apply to QToolButtons that are
        # contained within QWidgets added to toolbar.
        toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        toolbar.setMovable(False)
        toolbar.setFloatable(False)
        return toolbar
Beispiel #29
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()
Beispiel #30
0
    def add_toolbar(self,
                    name: str,
                    toolbar: QToolBar,
                    text: str = 'untitled toolbar'):

        b = self.top_toolbar_tab.add_button(text)
        toolbar.tab_button = b
        b.clicked.connect(lambda: self.switch_toolbar(name))

        self.addToolBarBreak(Qt.TopToolBarArea)
        self.addToolBar(toolbar)
        toolbar.setObjectName(name)
        self.toolbars[name] = toolbar
        toolbar.setMovable(False)
        toolbar.setFloatable(False)

        if self._current_toolbar_name != '':
            self.refresh_toolbar_appearance()
Beispiel #31
0
    def __init__(self):
        super(MainWindow, self).__init__()

        self.ports = serial.listports()
        self.port = None

        # remove close & maximize window buttons
        #self.setWindowFlags(Qt.CustomizeWindowHint|Qt.WindowMinimizeButtonHint)
        self.setMinimumSize(850, 450)

        self.mdiArea = QMdiArea()
        self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setCentralWidget(self.mdiArea)

        self.mdiArea.subWindowActivated.connect(self.updateMenus)
        self.mdiArea.setViewMode(QMdiArea.TabbedView)

        self.windowMapper = QSignalMapper(self)
        self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow)

        self.child = None

        self.createActions()
        self.createMenus()
        self.createStatusBar()
        self.updateMenus()
        self.readSettings()
        self.setWindowTitle("VISCAM")

        mytoolbar = QToolBar()
        ports_menu = QComboBox()
        ports_menu.addItem('Output Port')
        ports_menu.insertSeparator(1)
        for port in self.ports:
            ports_menu.addItem(port)
        self.ports_menu = ports_menu
        ports_menu.currentTextChanged.connect(self.setActivePort)
        mytoolbar.addWidget(ports_menu)
        mytoolbar.addSeparator()
        mytoolbar.setMovable(False)
        mytoolbar.setFixedHeight(60)
        self.addToolBar(Qt.TopToolBarArea, mytoolbar)
Beispiel #32
0
    def __init__(self, parent = None):
        super().__init__(parent)
        self.mExpandedGroups = QMapList()
        self.mObjectsView = ObjectsView()
        self.mMapDocument = None

        self.setObjectName("ObjectsDock")
        self.mActionObjectProperties = QAction(self)
        self.mActionObjectProperties.setIcon(QIcon(":/images/16x16/document-properties.png"))
        Utils.setThemeIcon(self.mActionObjectProperties, "document-properties")
        self.mActionObjectProperties.triggered.connect(self.objectProperties)
        handler = MapDocumentActionHandler.instance()
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.setSpacing(0)
        layout.addWidget(self.mObjectsView)
        self.mActionNewLayer = QAction(self)
        self.mActionNewLayer.setIcon(QIcon(":/images/16x16/document-new.png"))
        self.mActionNewLayer.triggered.connect(handler.actionAddObjectGroup().triggered)
        self.mActionMoveToGroup = QAction(self)
        self.mActionMoveToGroup.setIcon(QIcon(":/images/16x16/layer-object.png"))
        toolBar = QToolBar()
        toolBar.setFloatable(False)
        toolBar.setMovable(False)
        toolBar.setIconSize(QSize(16, 16))
        toolBar.addAction(self.mActionNewLayer)
        toolBar.addAction(handler.actionDuplicateObjects())
        toolBar.addAction(handler.actionRemoveObjects())
        toolBar.addAction(self.mActionMoveToGroup)
        button = toolBar.widgetForAction(self.mActionMoveToGroup)
        self.mMoveToMenu = QMenu(self)
        button.setPopupMode(QToolButton.InstantPopup)
        button.setMenu(self.mMoveToMenu)
        self.mMoveToMenu.aboutToShow.connect(self.aboutToShowMoveToMenu)
        self.mMoveToMenu.triggered.connect(self.triggeredMoveToMenu)
        toolBar.addAction(self.mActionObjectProperties)
        layout.addWidget(toolBar)
        self.setWidget(widget)
        self.retranslateUi()
        DocumentManager.instance().documentAboutToClose.connect(self.documentAboutToClose)
Beispiel #33
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.mMapDocument = None
        self.mPropertyBrowser = PropertyBrowser()

        self.setObjectName("propertiesDock")
        self.mActionAddProperty = QAction(self)
        self.mActionAddProperty.setEnabled(False)
        self.mActionAddProperty.setIcon(QIcon(":/images/16x16/add.png"))
        self.mActionAddProperty.triggered.connect(self.addProperty)
        self.mActionRemoveProperty = QAction(self)
        self.mActionRemoveProperty.setEnabled(False)
        self.mActionRemoveProperty.setIcon(QIcon(":/images/16x16/remove.png"))
        self.mActionRemoveProperty.triggered.connect(self.removeProperty)
        self.mActionRenameProperty = QAction(self)
        self.mActionRenameProperty.setEnabled(False)
        self.mActionRenameProperty.setIcon(QIcon(":/images/16x16/rename.png"))
        self.mActionRenameProperty.triggered.connect(self.renameProperty)
        Utils.setThemeIcon(self.mActionAddProperty, "add")
        Utils.setThemeIcon(self.mActionRemoveProperty, "remove")
        Utils.setThemeIcon(self.mActionRenameProperty, "rename")
        toolBar = QToolBar()
        toolBar.setFloatable(False)
        toolBar.setMovable(False)
        toolBar.setIconSize(QSize(16, 16))
        toolBar.addAction(self.mActionAddProperty)
        toolBar.addAction(self.mActionRemoveProperty)
        toolBar.addAction(self.mActionRenameProperty)
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.setSpacing(0)
        layout.addWidget(self.mPropertyBrowser)
        layout.addWidget(toolBar)
        widget.setLayout(layout)
        self.setWidget(widget)
        manager = DocumentManager.instance()
        manager.currentDocumentChanged.connect(self.mapDocumentChanged)
        self.mPropertyBrowser.currentItemChangedSignal.connect(
            self.currentItemChanged)
        self.retranslateUi()
Beispiel #34
0
    def __init__(self, parent = None):
        super().__init__(parent)
        self.mMapDocument = None
        self.mPropertyBrowser = PropertyBrowser()

        self.setObjectName("propertiesDock")
        self.mActionAddProperty = QAction(self)
        self.mActionAddProperty.setEnabled(False)
        self.mActionAddProperty.setIcon(QIcon(":/images/16x16/add.png"))
        self.mActionAddProperty.triggered.connect(self.addProperty)
        self.mActionRemoveProperty = QAction(self)
        self.mActionRemoveProperty.setEnabled(False)
        self.mActionRemoveProperty.setIcon(QIcon(":/images/16x16/remove.png"))
        self.mActionRemoveProperty.triggered.connect(self.removeProperty)
        self.mActionRenameProperty = QAction(self)
        self.mActionRenameProperty.setEnabled(False)
        self.mActionRenameProperty.setIcon(QIcon(":/images/16x16/rename.png"))
        self.mActionRenameProperty.triggered.connect(self.renameProperty)
        Utils.setThemeIcon(self.mActionAddProperty, "add")
        Utils.setThemeIcon(self.mActionRemoveProperty, "remove")
        Utils.setThemeIcon(self.mActionRenameProperty, "rename")
        toolBar = QToolBar()
        toolBar.setFloatable(False)
        toolBar.setMovable(False)
        toolBar.setIconSize(QSize(16, 16))
        toolBar.addAction(self.mActionAddProperty)
        toolBar.addAction(self.mActionRemoveProperty)
        toolBar.addAction(self.mActionRenameProperty)
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.setSpacing(0)
        layout.addWidget(self.mPropertyBrowser)
        layout.addWidget(toolBar)
        widget.setLayout(layout)
        self.setWidget(widget)
        manager = DocumentManager.instance()
        manager.currentDocumentChanged.connect(self.mapDocumentChanged)
        self.mPropertyBrowser.currentItemChangedSignal.connect(self.currentItemChanged)
        self.retranslateUi()
Beispiel #35
0
class Record(object):
	def __init__(self):
		r = Record()
		r.foo = 'oof'
		setattr(r, 'bar', 'rab')
		r.foo
		'oof'
		r.bar
		'rab'
		names = 'id description price'.split()
		values = [666, 'duct tape', 3.45]
		s = Record()
		for name, value in zip(names, values):
			setattr(s, name, value)
		s.__dict__ # If you are suffering from dict withdrawal symptoms
		{'price': 3.45, 'id': 666, 'description': 'duct tape'}
		return self
	def appToolBar(self, QToolBar, cfg):
		'Create a Toolbar from configurations file'
		pxcfg = here+'z-data_/desktop.yaml'
		self.config = config.instruct(pxcfg).select(
								'docAddToolBar').override(cfg)#	||
		self.createToolBar()
		for button, cfg in self.config['buttons'].items():
			self.createButton(button, cfg)
	def createToolBar(self):
		self.toolbar = QToolBar()
		self.toolbar.setMovable(True)
		self.toolbar.setFloatable(True)
		self.toolbar.setOrientation(Qt.Vertical)
		return self
	def createButton(self, button, cfg):
		''
		toolbutton = QToolButton()
		toolbutton.setText(cfg['DisplayName'])
		toolbutton.setCheckable(cfg['checkable'])
		toolbutton.setAutoExclusive(cfg['setAutoExclusive'])
		self.toolbar.addWidget(toolbutton)
		return self
Beispiel #36
0
    def __init__(self):
        super(MainWindow, self).__init__()
        # remove close & maximize window buttons
        #self.setWindowFlags(Qt.CustomizeWindowHint|Qt.WindowMinimizeButtonHint)
        self.setMinimumSize(500, 666)
        #self.setMaximumSize(1000,666)
        self.mdiArea = QMdiArea()
        self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setCentralWidget(self.mdiArea)

        self.mdiArea.subWindowActivated.connect(self.updateMenus)
        self.mdiArea.setViewMode(QMdiArea.TabbedView)

        self.windowMapper = QSignalMapper(self)
        self.windowMapper.mapped[QWidget].connect(self.setActiveSubWindow)

        self.child = None

        self.createActions()
        self.createMenus()
        self.createStatusBar()
        self.updateMenus()
        self.readSettings()
        self.setWindowTitle("LEKTURE")

        mytoolbar = QToolBar()
        #self.toolbar = self.addToolBar()
        mytoolbar.addAction(self.newAct)
        mytoolbar.addAction(self.openAct)
        mytoolbar.addAction(self.saveAct)
        mytoolbar.addAction(self.saveAsAct)
        mytoolbar.addSeparator()
        mytoolbar.addAction(self.outputsAct)
        mytoolbar.addAction(self.scenarioAct)
        self.scenarioAct.setVisible(False)
        mytoolbar.setMovable(False)
        mytoolbar.setFixedWidth(60)
        self.addToolBar(Qt.LeftToolBarArea, mytoolbar)
Beispiel #37
0
    def __init__(self, style='default'):
        super(QRibbonWindow, self).__init__()
        self.style = style
        self.setObjectName('QRibbonWindow')

        self.tabs = []
        self.groups = []

        # 设置样式
        self.default = default
        if self.style == 'default':
            _default = default.replace("{{margin}}", str(self.margin))
            self.setStyleSheet(_default + '\n' + self.styleSheet())
        # 去除右键菜单
        self.setContextMenuPolicy(Qt.NoContextMenu)
        # 添加工具栏
        toolBar = QToolBar(self)
        toolBar.setMouseTracking(True)
        self.ribbonWidget = QRibbonWidget(toolBar)
        toolBar.addWidget(self.ribbonWidget)
        toolBar.setAllowedAreas(Qt.NoToolBarArea)
        toolBar.setMovable(False)
        toolBar.setFloatable(False)
        self.addToolBar(toolBar)
        # 添加中心控件
        self.centralWidget = QWidget(self)
        self.centralWidget.setMouseTracking(True)
        self.centralWidget.setObjectName("centralWidget")
        self.setCentralWidget(self.centralWidget)
        # 安装时间过滤器
        self.installEventFilter(self)
        self.ribbonWidget.tabPanel.installEventFilter(self)
        self.minButton.installEventFilter(self)
        self.maxButton.installEventFilter(self)
        self.closeButton.installEventFilter(self)
        # 最小化、最大化、关闭按钮事件
        self.minButton.clicked.connect(self.showMinimized)
        self.maxButton.clicked.connect(self.toggle_max)
        self.closeButton.clicked.connect(self.close)
Beispiel #38
0
    def add_toolbar(self, name: str, toolbar: QToolBar,
                    text: str = 'untitled toolbar'):
        """
        添加一个工具栏。
        """
        b = self.top_toolbar_tab.add_button(text)
        toolbar.tab_button = b
        b.clicked.connect(lambda: self.on_toolbar_switch_button_clicked(name))

        if hasattr(self, 'toolbar_path'):
            self.insertToolBar(self.toolbar_path, toolbar)
            self.insertToolBarBreak(self.toolbar_path)
        else:
            self.addToolBarBreak(Qt.TopToolBarArea)
            self.addToolBar(toolbar)
        toolbar.setObjectName(name)
        self.toolbars[name] = toolbar
        toolbar.setMovable(False)
        toolbar.setFloatable(False)

        if self._current_toolbar_name != '':
            self.refresh_toolbar_appearance()
Beispiel #39
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()
Beispiel #40
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
Beispiel #42
0
class MainGlyphWindow(QMainWindow):

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

        menuBar = self.menuBar()
        fileMenu = QMenu("&File", self)
        fileMenu.addAction("E&xit", self.close, QKeySequence.Quit)
        menuBar.addMenu(fileMenu)
        editMenu = QMenu("&Edit", self)
        self._undoAction = editMenu.addAction(
            "&Undo", self.undo, QKeySequence.Undo)
        self._redoAction = editMenu.addAction(
            "&Redo", self.redo, QKeySequence.Redo)
        editMenu.addSeparator()
        # XXX
        action = editMenu.addAction("C&ut", self.cutOutlines, QKeySequence.Cut)
        action.setEnabled(False)
        self._copyAction = editMenu.addAction(
            "&Copy", self.copyOutlines, QKeySequence.Copy)
        editMenu.addAction("&Paste", self.pasteOutlines, QKeySequence.Paste)
        editMenu.addAction(
            "Select &All", self.selectAll, QKeySequence.SelectAll)
        editMenu.addAction("&Deselect", self.deselect, "Ctrl+D")
        menuBar.addMenu(editMenu)
        glyphMenu = QMenu("&Glyph", self)
        glyphMenu.addAction("&Next Glyph", lambda: self.glyphOffset(1), "End")
        glyphMenu.addAction(
            "&Previous Glyph", lambda: self.glyphOffset(-1), "Home")
        glyphMenu.addAction("&Go To…", self.changeGlyph, "G")
        glyphMenu.addSeparator()
        self._layerAction = glyphMenu.addAction(
            "&Layer Actions…", self.layerActions, "L")
        menuBar.addMenu(glyphMenu)

        # create tools and buttons toolBars
        self._tools = []
        self._toolsToolBar = QToolBar("Tools", self)
        self._toolsToolBar.setMovable(False)
        self._buttons = []
        self._buttonsToolBar = QToolBar("Buttons", self)
        self._buttonsToolBar.setMovable(False)
        self.addToolBar(self._toolsToolBar)
        self.addToolBar(self._buttonsToolBar)

        # http://www.setnode.com/blog/right-aligning-a-button-in-a-qtoolbar/
        self._layersToolBar = QToolBar("Layers", self)
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._currentLayerBox = QComboBox(self)
        self._currentLayerBox.currentIndexChanged.connect(
            self._layerChanged)
        self._layersToolBar.addWidget(spacer)
        self._layersToolBar.addWidget(self._currentLayerBox)
        self._layersToolBar.setContentsMargins(0, 0, 2, 0)
        self._layersToolBar.setMovable(False)
        self.addToolBar(self._layersToolBar)

        viewMenu = self.createPopupMenu()
        viewMenu.setTitle("View")
        viewMenu.addSeparator()
        action = viewMenu.addAction("Lock Toolbars", self.lockToolBars)
        action.setCheckable(True)
        action.setChecked(True)
        menuBar.addMenu(viewMenu)

        self.view = GlyphView(self)
        self.setGlyph(glyph)
        selectionTool = self.installTool(SelectionTool)
        selectionTool.trigger()
        self.installTool(PenTool)
        self.installTool(RulerTool)
        self.installTool(KnifeTool)
        self.installButton(RemoveOverlapButton)

        self.setCentralWidget(self.view.scrollArea())
        self.resize(900, 700)
        self.view.setFocus(True)

    # ----------
    # Menu items
    # ----------

    def glyphOffset(self, offset):
        currentGlyph = self.view.glyph()
        font = currentGlyph.font
        glyphOrder = font.glyphOrder
        # should be enforced in fontView already
        if not (glyphOrder and len(glyphOrder)):
            return
        index = glyphOrder.index(currentGlyph.name)
        newIndex = (index + offset) % len(glyphOrder)
        glyph = font[glyphOrder[newIndex]]
        self.setGlyph(glyph)

    def changeGlyph(self):
        glyph = self.view.glyph()
        newGlyph, ok = GotoDialog.getNewGlyph(self, glyph)
        if ok and newGlyph is not None:
            self.setGlyph(newGlyph)

    def layerActions(self):
        glyph = self.view.glyph()
        newLayer, action, ok = LayerActionsDialog.getLayerAndAction(
            self, glyph)
        if ok and newLayer is not None:
            # TODO: whole glyph for now, but consider selection too
            if not glyph.name in newLayer:
                newLayer.newGlyph(glyph.name)
            otherGlyph = newLayer[glyph.name]
            otherGlyph.disableNotifications()
            if action == "Swap":
                tempGlyph = TGlyph()
                otherGlyph.drawPoints(tempGlyph.getPointPen())
                tempGlyph.width = otherGlyph.width
                otherGlyph.clearContours()
            glyph.drawPoints(otherGlyph.getPointPen())
            otherGlyph.width = glyph.width
            if action != "Copy":
                glyph.disableNotifications()
                glyph.clearContours()
                if action == "Swap":
                    tempGlyph.drawPoints(glyph.getPointPen())
                    glyph.width = tempGlyph.width
                glyph.enableNotifications()
            otherGlyph.enableNotifications()

    def undo(self):
        glyph = self.view.glyph()
        glyph.undo()

    def redo(self):
        glyph = self.view.glyph()
        glyph.redo()

    def cutOutlines(self):
        pass

    def copyOutlines(self):
        glyph = self.view.glyph()
        clipboard = QApplication.clipboard()
        mimeData = QMimeData()
        copyGlyph = glyph.getRepresentation("defconQt.FilterSelection")
        mimeData.setData("application/x-defconQt-glyph-data",
                         pickle.dumps([copyGlyph.serialize(
                             blacklist=("name", "unicode")
                         )]))
        clipboard.setMimeData(mimeData)

    def pasteOutlines(self):
        glyph = self.view.glyph()
        clipboard = QApplication.clipboard()
        mimeData = clipboard.mimeData()
        if mimeData.hasFormat("application/x-defconQt-glyph-data"):
            data = pickle.loads(mimeData.data(
                "application/x-defconQt-glyph-data"))
            if len(data) == 1:
                pen = glyph.getPointPen()
                pasteGlyph = TGlyph()
                pasteGlyph.deserialize(data[0])
                # TODO: if we serialize selected state, we don't need to do
                # this
                pasteGlyph.selected = True
                if len(pasteGlyph) or len(pasteGlyph.components) or \
                        len(pasteGlyph.anchors):
                    glyph.prepareUndo()
                    pasteGlyph.drawPoints(pen)

    def selectAll(self):
        glyph = self.view.glyph()
        glyph.selected = True
        if not len(glyph):
            for component in glyph.components:
                component.selected = True

    def deselect(self):
        glyph = self.view.glyph()
        for anchor in glyph.anchors:
            anchor.selected = False
        for component in glyph.components:
            component.selected = False
        glyph.selected = False

    def lockToolBars(self):
        action = self.sender()
        movable = not action.isChecked()
        for toolBar in (
                self._toolsToolBar, self._buttonsToolBar, self._layersToolBar):
            toolBar.setMovable(movable)

    # --------------------------
    # Tools & buttons management
    # --------------------------

    def installTool(self, tool):
        action = self._toolsToolBar.addAction(
            QIcon(tool.iconPath), tool.name, self._setViewTool)
        action.setCheckable(True)
        num = len(self._tools)
        action.setData(num)
        action.setShortcut(QKeySequence(str(num + 1)))
        self._tools.append(tool(parent=self.view))
        return action

    def uninstallTool(self, tool):
        pass  # XXX

    def _setViewTool(self):
        action = self.sender()
        index = action.data()
        newTool = self._tools[index]
        if newTool == self.view.currentTool():
            action.setChecked(True)
            return
        ok = self.view.setCurrentTool(newTool)
        # if view did change tool, disable them all and enable the one we want
        # otherwise, just disable the tool that was clicked.
        # previously we used QActionGroup to have exclusive buttons, but doing
        # it manually allows us to NAK a button change.
        if ok:
            for act in self._toolsToolBar.actions():
                act.setChecked(False)
        action.setChecked(ok)

    def installButton(self, button):
        action = self._buttonsToolBar.addAction(
            QIcon(button.iconPath), button.name, self._buttonAction)
        action.setData(len(self._buttons))
        self._buttons.append(button(parent=self.view))
        return action

    def uninstallButton(self, button):
        pass  # XXX

    def _buttonAction(self):
        action = self.sender()
        index = action.data()
        button = self._buttons[index]
        button.clicked()

    # --------------------
    # Notification support
    # --------------------

    # glyph

    def _subscribeToGlyph(self, glyph):
        if glyph is not None:
            glyph.addObserver(self, "_glyphChanged", "Glyph.Changed")
            glyph.addObserver(self, "_glyphNameChanged", "Glyph.NameChanged")
            glyph.addObserver(
                self, "_glyphSelectionChanged", "Glyph.SelectionChanged")
            undoManager = glyph.undoManager
            undoManager.canUndoChanged.connect(self._undoAction.setEnabled)
            undoManager.canRedoChanged.connect(self._redoAction.setEnabled)
            self._subscribeToFontAndLayerSet(glyph.font)

    def _unsubscribeFromGlyph(self, glyph):
        if glyph is not None:
            glyph.removeObserver(self, "Glyph.Changed")
            glyph.removeObserver(self, "Glyph.NameChanged")
            glyph.removeObserver(self, "Glyph.SelectionChanged")
            undoManager = glyph.undoManager
            undoManager.canUndoChanged.disconnect(self._undoAction.setEnabled)
            undoManager.canRedoChanged.disconnect(self._redoAction.setEnabled)
            self._unsubscribeFromFontAndLayerSet(glyph.font)

    def _glyphChanged(self, notification):
        self.view.glyphChanged()

    def _glyphNameChanged(self, notification):
        glyph = self.view.glyph()
        self.setWindowTitle(glyph.name, glyph.font)

    def _glyphSelectionChanged(self, notification):
        self._updateSelection()
        self.view.glyphChanged()

    def _fontInfoChanged(self, notification):
        self.view.fontInfoChanged()
        glyph = self.view.glyph()
        self.setWindowTitle(glyph.name, glyph.font)

    # layers & font

    def _subscribeToFontAndLayerSet(self, font):
        """Note: called by _subscribeToGlyph."""
        if font is None:
            return
        font.info.addObserver(self, "_fontInfoChanged", "Info.Changed")
        layerSet = font.layers
        if layerSet is None:
            return
        layerSet.addObserver(self, '_layerSetLayerDeleted',
                             'LayerSet.LayerDeleted')
        for event in ('LayerSet.LayerAdded', 'LayerSet.LayerChanged',
                      'LayerSet.LayerOrderChanged'):
            layerSet.addObserver(self, '_layerSetEvents', event)

    def _unsubscribeFromFontAndLayerSet(self, font):
        """Note: called by _unsubscribeFromGlyph."""
        if font is None:
            return
        font.info.removeObserver(self, "Info.Changed")
        layerSet = font.layers
        if layerSet is None:
            return
        for event in ('LayerSet.LayerAdded', 'LayerSet.LayerChanged',
                      'LayerSet.LayerOrderChanged', 'LayerSet.LayerDeleted'):
            layerSet.removeObserver(self, event)

    def _layerSetEvents(self, notification):
        self._updateLayerControls()

    def _layerSetLayerDeleted(self, notification):
        self._layerSetEvents(notification)
        self._currentLayerBox.setCurrentIndex(0)

    # other updaters

    def _updateUndoRedo(self):
        glyph = self.view.glyph()
        self._undoAction.setEnabled(glyph.canUndo())
        self._redoAction.setEnabled(glyph.canRedo())

    def _updateSelection(self):
        def hasSelection():
            glyph = self.view.glyph()
            for contour in glyph:
                if len(contour.selection):
                    return True
            for anchor in glyph.anchors:
                if anchor.selected:
                    return True
            for component in glyph.components:
                if component.selected:
                    return True
            return False
        self._copyAction.setEnabled(hasSelection())

    # --------------
    # Public Methods
    # --------------

    def setGlyph(self, glyph):
        currentGlyph = self.view.glyph()
        self._unsubscribeFromGlyph(currentGlyph)
        self._subscribeToGlyph(glyph)
        self.view.setGlyph(glyph)
        self._updateLayerControls()
        self._updateUndoRedo()
        self._updateSelection()
        self.setWindowTitle(glyph.name, glyph.font)

    def setDrawingAttribute(self, attr, value, layerName=None):
        self.view.setDrawingAttribute(attr, value, layerName)

    def drawingAttribute(self, attr, layerName=None):
        return self.view.drawingAttribute(attr, layerName)

    # -----------------
    # Layers management
    # -----------------

    def _layerChanged(self, newLayerIndex):
        glyph = self.view.glyph()
        layer = self._currentLayerBox.itemData(newLayerIndex)
        if layer is None:
            layer = self._makeLayer()
            if layer is None:
                # restore comboBox to active index
                layerSet = glyph.layerSet
                index = layerSet.layerOrder.index(glyph.layer.name)
                self._setLayerBoxIndex(index)
                return

        if glyph.name in layer:
            newGlyph = layer[glyph.name]
        else:
            # TODO: make sure we mimic defcon ufo3 APIs for that
            newGlyph = self._makeLayerGlyph(layer, glyph)
        self.setGlyph(newGlyph)

        # setting the layer-glyph here
        app = QApplication.instance()
        app.setCurrentGlyph(newGlyph)

    def _makeLayer(self):
        # TODO: what with duplicate names?
        glyph = self.view.glyph()
        newLayerName, ok = AddLayerDialog.getNewLayerName(self)
        if ok:
            layerSet = glyph.layerSet
            # TODO: this should return the layer
            layerSet.newLayer(newLayerName)
            return layerSet[newLayerName]
        else:
            return None

    def _makeLayerGlyph(self, layer, currentGlyph):
        glyph = layer.newGlyph(currentGlyph.name)
        glyph.width = currentGlyph.width
        glyph.template = True
        return glyph

    def _updateLayerControls(self):
        comboBox = self._currentLayerBox
        glyph = self.view.glyph()
        comboBox.blockSignals(True)
        comboBox.clear()
        for layer in glyph.layerSet:
            comboBox.addItem(layer.name, layer)
        comboBox.setCurrentText(glyph.layer.name)
        comboBox.addItem("New layer…", None)
        comboBox.blockSignals(False)
        self._layerAction.setEnabled(len(glyph.layerSet) > 1)

    def _setLayerBoxIndex(self, index):
        comboBox = self._currentLayerBox
        comboBox.blockSignals(True)
        comboBox.setCurrentIndex(index)
        comboBox.blockSignals(False)

    # ---------------------
    # QMainWindow functions
    # ---------------------

    def event(self, event):
        if event.type() == QEvent.WindowActivate:
            app = QApplication.instance()
            app.setCurrentGlyph(self.view.glyph())
        return super().event(event)

    def closeEvent(self, event):
        glyph = self.view.glyph()
        self._unsubscribeFromGlyph(glyph)
        event.accept()

    def setWindowTitle(self, title, font=None):
        if font is not None:
            title = "%s – %s %s" % (
                title, font.info.familyName, font.info.styleName)
        super().setWindowTitle(title)
Beispiel #43
0
class GlyphWindow(BaseMainWindow):

    def __init__(self, glyph, parent=None):
        super().__init__(parent)
        self.setAttribute(Qt.WA_DeleteOnClose, False)
        self.setUnifiedTitleAndToolBarOnMac(True)

        self.view = GlyphCanvasView(self)
        # create tools and buttons toolBars
        self._tools = []
        self._toolsToolBar = QToolBar(self.tr("Tools"), self)
        self._toolsToolBar.setMovable(False)
        self._buttons = []
        self._buttonsToolBar = QToolBar(self.tr("Buttons"), self)
        self._buttonsToolBar.setMovable(False)
        self.addToolBar(self._toolsToolBar)
        self.addToolBar(self._buttonsToolBar)

        # http://www.setnode.com/blog/right-aligning-a-button-in-a-qtoolbar/
        self._layersToolBar = QToolBar(self.tr("Layers"), self)
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._currentLayerBox = QComboBox(self)
        self._currentLayerBox.currentIndexChanged.connect(
            self._layerChanged)
        self._layersToolBar.addWidget(spacer)
        self._layersToolBar.addWidget(self._currentLayerBox)
        self._layersToolBar.setContentsMargins(0, 0, 2, 0)
        self._layersToolBar.setMovable(False)
        self.addToolBar(self._layersToolBar)

        self.setGlyph(glyph)
        app = QApplication.instance()
        tools = app.drawingTools()
        for index, tool in enumerate(tools):
            action = self.installTool(tool)
            if not index:
                action.trigger()
        app.dispatcher.addObserver(
            self, "_drawingToolRegistered", "drawingToolRegistered")
        # TODO: drawingToolUnregistered
        self.installButton(RemoveOverlapButton)

        self.setCentralWidget(self.view)
        self.view.setFocus(True)

        self.readSettings()

    def readSettings(self):
        geometry = settings.glyphWindowGeometry()
        if geometry:
            self.restoreGeometry(geometry)

    def writeSettings(self):
        # TODO: save current tool?
        settings.setGlyphWindowGeometry(self.saveGeometry())

    def setupMenu(self, menuBar):
        fileMenu = menuBar.fetchMenu(Entries.File)
        fontWindow = self.parent()
        if fontWindow is not None:
            fileMenu.fetchAction(Entries.File_Save, fontWindow.saveFile)
            fileMenu.fetchAction(Entries.File_Save_As, fontWindow.saveFileAs)
        fileMenu.fetchAction(Entries.File_Close, self.close)
        if fontWindow is not None:
            fileMenu.fetchAction(Entries.File_Reload, fontWindow.reloadFile)

        editMenu = menuBar.fetchMenu(Entries.Edit)
        self._undoAction = editMenu.fetchAction(Entries.Edit_Undo, self.undo)
        self._redoAction = editMenu.fetchAction(Entries.Edit_Redo, self.redo)
        editMenu.addSeparator()
        cutAction = editMenu.fetchAction(Entries.Edit_Cut, self.cutOutlines)
        copyAction = editMenu.fetchAction(Entries.Edit_Copy, self.copyOutlines)
        self._selectActions = (cutAction, copyAction)
        editMenu.fetchAction(Entries.Edit_Paste, self.pasteOutlines)
        editMenu.fetchAction(Entries.Edit_Select_All, self.selectAll)
        editMenu.fetchAction(Entries.Edit_Find, self.changeGlyph)
        # TODO: sort this out
        # editMenu.fetchAction(self.tr("&Deselect"), self.deselect, "Ctrl+D")

        # glyphMenu = menuBar.fetchMenu(self.tr("&Glyph"))
        # self._layerAction = glyphMenu.fetchAction(
        #     self.tr("&Layer Actions…"), self.layerActions, "L")

        viewMenu = menuBar.fetchMenu(Entries.View)
        viewMenu.fetchAction(Entries.View_Zoom_In, lambda: self.view.zoom(1))
        viewMenu.fetchAction(Entries.View_Zoom_Out, lambda: self.view.zoom(-1))
        viewMenu.fetchAction(Entries.View_Reset_Zoom, self.view.fitScaleBBox)
        viewMenu.addSeparator()
        viewMenu.fetchAction(
            Entries.View_Next_Glyph, lambda: self.glyphOffset(1))
        viewMenu.fetchAction(
            Entries.View_Previous_Glyph, lambda: self.glyphOffset(-1))

        self._updateUndoRedo()

    # ----------
    # Menu items
    # ----------

    def saveFile(self):
        glyph = self.view.glyph()
        font = glyph.font
        if None not in (font, font.path):
            font.save()

    def glyphOffset(self, offset):
        currentGlyph = self.view.glyph()
        font = currentGlyph.font
        glyphOrder = font.glyphOrder
        # should be enforced in fontView already
        if not (glyphOrder and len(glyphOrder)):
            return
        index = glyphOrder.index(currentGlyph.name)
        newIndex = (index + offset) % len(glyphOrder)
        glyph = font[glyphOrder[newIndex]]
        self.setGlyph(glyph)

    def changeGlyph(self):
        glyph = self.view.glyph()
        newGlyph, ok = FindDialog.getNewGlyph(self, glyph)
        if ok and newGlyph is not None:
            self.setGlyph(newGlyph)

    def layerActions(self):
        glyph = self.view.glyph()
        newLayer, action, ok = LayerActionsDialog.getLayerAndAction(
            self, glyph)
        if ok and newLayer is not None:
            # TODO: whole glyph for now, but consider selection too
            if glyph.name not in newLayer:
                newLayer.newGlyph(glyph.name)
            otherGlyph = newLayer[glyph.name]
            otherGlyph.holdNotifications()
            if action == "Swap":
                tempGlyph = glyph.__class__()
                otherGlyph.drawPoints(tempGlyph.getPointPen())
                tempGlyph.width = otherGlyph.width
                otherGlyph.clearContours()
            glyph.drawPoints(otherGlyph.getPointPen())
            otherGlyph.width = glyph.width
            if action != "Copy":
                glyph.holdNotifications()
                glyph.clearContours()
                if action == "Swap":
                    tempGlyph.drawPoints(glyph.getPointPen())
                    glyph.width = tempGlyph.width
                glyph.releaseHeldNotifications()
            otherGlyph.releaseHeldNotifications()

    def undo(self):
        glyph = self.view.glyph()
        glyph.undo()

    def redo(self):
        glyph = self.view.glyph()
        glyph.redo()

    def cutOutlines(self):
        glyph = self.view.glyph()
        self.copyOutlines()
        deleteUISelection(glyph)

    def copyOutlines(self):
        glyph = self.view.glyph()
        clipboard = QApplication.clipboard()
        mimeData = QMimeData()
        copyGlyph = glyph.getRepresentation("TruFont.FilterSelection")
        mimeData.setData("application/x-trufont-glyph-data",
                         pickle.dumps([copyGlyph.serialize(
                             blacklist=("name", "unicode")
                         )]))
        clipboard.setMimeData(mimeData)

    def pasteOutlines(self):
        glyph = self.view.glyph()
        clipboard = QApplication.clipboard()
        mimeData = clipboard.mimeData()
        if mimeData.hasFormat("application/x-trufont-glyph-data"):
            data = pickle.loads(mimeData.data(
                "application/x-trufont-glyph-data"))
            if len(data) == 1:
                pen = glyph.getPointPen()
                pasteGlyph = glyph.__class__()
                pasteGlyph.deserialize(data[0])
                # TODO: if we serialize selected state, we don't need to do
                # this
                pasteGlyph.selected = True
                if len(pasteGlyph) or len(pasteGlyph.components) or \
                        len(pasteGlyph.anchors):
                    glyph.prepareUndo()
                    pasteGlyph.drawPoints(pen)

    def selectAll(self):
        glyph = self.view.glyph()
        if glyph.selected:
            for anchor in glyph.anchors:
                anchor.selected = True
            for component in glyph.components:
                component.selected = True
        else:
            glyph.selected = True

    def deselect(self):
        glyph = self.view.glyph()
        for anchor in glyph.anchors:
            anchor.selected = False
        for component in glyph.components:
            component.selected = False
        glyph.selected = False

    def lockToolBars(self):
        action = self.sender()
        movable = not action.isChecked()
        for toolBar in (
                self._toolsToolBar, self._buttonsToolBar, self._layersToolBar):
            toolBar.setMovable(movable)

    # --------------------------
    # Tools & buttons management
    # --------------------------

    def installTool(self, tool):
        action = self._toolsToolBar.addAction(
            QIcon(tool.iconPath), tool.name, self._setViewTool)
        action.setCheckable(True)
        num = len(self._tools)
        action.setData(num)
        action.setShortcut(QKeySequence(str(num + 1)))
        self._tools.append(tool(parent=self.view.widget()))
        return action

    def uninstallTool(self, tool):
        pass  # XXX

    def _setViewTool(self):
        action = self.sender()
        index = action.data()
        newTool = self._tools[index]
        if newTool == self.view.currentTool():
            action.setChecked(True)
            return
        ok = self.view.setCurrentTool(newTool)
        # if view did change tool, disable them all and enable the one we want
        # otherwise, just disable the tool that was clicked.
        # previously we used QActionGroup to have exclusive buttons, but doing
        # it manually allows us to NAK a button change.
        if ok:
            for act in self._toolsToolBar.actions():
                act.setChecked(False)
        action.setChecked(ok)

    def installButton(self, button):
        action = self._buttonsToolBar.addAction(
            QIcon(button.iconPath), button.name, self._buttonAction)
        action.setData(len(self._buttons))
        self._buttons.append(button(parent=self.view))
        return action

    def uninstallButton(self, button):
        pass  # XXX

    def _buttonAction(self):
        action = self.sender()
        index = action.data()
        button = self._buttons[index]
        button.clicked()

    # -------------
    # Notifications
    # -------------

    # app

    def _drawingToolRegistered(self, notification):
        tool = notification.data["tool"]
        self.installTool(tool)

    # glyph

    def _subscribeToGlyph(self, glyph):
        if glyph is not None:
            glyph.addObserver(self, "_glyphNameChanged", "Glyph.NameChanged")
            glyph.addObserver(
                self, "_glyphSelectionChanged", "Glyph.SelectionChanged")
            undoManager = glyph.undoManager
            undoManager.canUndoChanged.connect(self._setUndoEnabled)
            undoManager.canRedoChanged.connect(self._setRedoEnabled)
            self._subscribeToFontAndLayerSet(glyph.font)

    def _unsubscribeFromGlyph(self, glyph):
        if glyph is not None:
            glyph.removeObserver(self, "Glyph.NameChanged")
            glyph.removeObserver(self, "Glyph.SelectionChanged")
            undoManager = glyph.undoManager
            undoManager.canUndoChanged.disconnect(self._setUndoEnabled)
            undoManager.canRedoChanged.disconnect(self._setRedoEnabled)
            self._unsubscribeFromFontAndLayerSet(glyph.font)

    def _glyphNameChanged(self, notification):
        glyph = self.view.glyph()
        self.setWindowTitle(glyph.name, glyph.font)

    def _glyphSelectionChanged(self, notification):
        self._updateSelection()

    # layers & font

    def _subscribeToFontAndLayerSet(self, font):
        """Note: called by _subscribeToGlyph."""
        if font is None:
            return
        font.info.addObserver(self, "_fontInfoChanged", "Info.Changed")
        layerSet = font.layers
        if layerSet is None:
            return
        layerSet.addObserver(
            self, '_layerSetLayerDeleted', 'LayerSet.LayerDeleted')
        for event in ('LayerSet.LayerAdded', 'LayerSet.LayerChanged',
                      'LayerSet.LayerOrderChanged'):
            layerSet.addObserver(self, '_layerSetEvents', event)

    def _unsubscribeFromFontAndLayerSet(self, font):
        """Note: called by _unsubscribeFromGlyph."""
        if font is None:
            return
        font.info.removeObserver(self, "Info.Changed")
        layerSet = font.layers
        if layerSet is None:
            return
        for event in ('LayerSet.LayerAdded', 'LayerSet.LayerChanged',
                      'LayerSet.LayerOrderChanged', 'LayerSet.LayerDeleted'):
            layerSet.removeObserver(self, event)

    def _fontInfoChanged(self, notification):
        glyph = self.view.glyph()
        self.setWindowTitle(glyph.name, glyph.font)

    def _layerSetEvents(self, notification):
        self._updateLayerControls()

    def _layerSetLayerDeleted(self, notification):
        self._layerSetEvents(notification)
        self._currentLayerBox.setCurrentIndex(0)

    # other updaters

    def _updateSelection(self):
        def hasSelection():
            glyph = self.view.glyph()
            for contour in glyph:
                if len(contour.selection):
                    return True
            for anchor in glyph.anchors:
                if anchor.selected:
                    return True
            for component in glyph.components:
                if component.selected:
                    return True
            return False

        if not hasattr(self, "_selectActions"):
            return
        hasSelection = hasSelection()
        for action in self._selectActions:
            action.setEnabled(hasSelection)

    def _updateUndoRedo(self):
        glyph = self.view.glyph()
        self._setUndoEnabled(glyph.canUndo())
        self._setRedoEnabled(glyph.canRedo())

    def _setUndoEnabled(self, value):
        if not hasattr(self, "_undoAction"):
            return
        self._undoAction.setEnabled(value)

    def _setRedoEnabled(self, value):
        if not hasattr(self, "_redoAction"):
            return
        self._redoAction.setEnabled(value)

    # --------------
    # Public Methods
    # --------------

    def setGlyph(self, glyph):
        currentGlyph = self.view.glyph()
        self._unsubscribeFromGlyph(currentGlyph)
        self.view.setGlyph(glyph)
        self._subscribeToGlyph(glyph)
        self._updateLayerControls()
        self._updateUndoRedo()
        self._updateSelection()
        self.setWindowTitle(glyph.name, glyph.font)
        # setting the layer-glyph here
        app = QApplication.instance()
        app.setCurrentGlyph(glyph)

    # -----------------
    # Layers management
    # -----------------

    def _layerChanged(self, newLayerIndex):
        glyph = self.view.glyph()
        layer = self._currentLayerBox.itemData(newLayerIndex)
        if layer is None:
            layer = self._makeLayer()
            if layer is None:
                # restore comboBox to active index
                layerSet = glyph.layerSet
                index = layerSet.layerOrder.index(glyph.layer.name)
                self._setLayerBoxIndex(index)
                return

        if glyph.name in layer:
            newGlyph = layer[glyph.name]
        else:
            # TODO: make sure we mimic defcon ufo3 APIs for that
            newGlyph = self._makeLayerGlyph(layer, glyph)
        self.setGlyph(newGlyph)

    def _makeLayer(self):
        # TODO: what with duplicate names?
        glyph = self.view.glyph()
        newLayerName, color, ok = AddLayerDialog.getNewLayerNameAndColor(self)
        if ok:
            layerSet = glyph.layerSet
            layer = layerSet.newLayer(newLayerName)
            layer.color = color
            return layer
        return None

    def _makeLayerGlyph(self, layer, currentGlyph):
        glyph = layer.newGlyph(currentGlyph.name)
        glyph.width = currentGlyph.width
        glyph.template = True
        return glyph

    def _updateLayerControls(self):
        comboBox = self._currentLayerBox
        glyph = self.view.glyph()
        comboBox.blockSignals(True)
        comboBox.clear()
        for layer in glyph.layerSet:
            comboBox.addItem(layer.name, layer)
        comboBox.setCurrentText(glyph.layer.name)
        comboBox.addItem(self.tr("New layer…"), None)
        comboBox.blockSignals(False)
        if not hasattr(self, "_layerAction"):
            return
        self._layerAction.setEnabled(len(glyph.layerSet) > 1)

    def _setLayerBoxIndex(self, index):
        comboBox = self._currentLayerBox
        comboBox.blockSignals(True)
        comboBox.setCurrentIndex(index)
        comboBox.blockSignals(False)

    # ---------------------
    # QMainWindow functions
    # ---------------------

    def sizeHint(self):
        return QSize(1100, 750)

    def moveEvent(self, event):
        self.writeSettings()

    resizeEvent = moveEvent

    def event(self, event):
        if event.type() == QEvent.WindowActivate:
            app = QApplication.instance()
            app.setCurrentGlyph(self.view.glyph())
        return super().event(event)

    def showEvent(self, event):
        app = QApplication.instance()
        data = dict(window=self)
        app.postNotification("glyphWindowWillOpen", data)
        super().showEvent(event)
        app.postNotification("glyphWindowOpened", data)

    def closeEvent(self, event):
        super().closeEvent(event)
        if event.isAccepted():
            app = QApplication.instance()
            app.dispatcher.removeObserver(self, "drawingToolRegistered")
            data = dict(window=self)
            app.postNotification("glyphWindowWillClose", data)
            glyph = self.view.glyph()
            self._unsubscribeFromGlyph(glyph)
            self.view.closeEvent(event)

    def setWindowTitle(self, title, font=None):
        if font is not None:
            title = "%s – %s %s" % (
                title, font.info.familyName, font.info.styleName)
        super().setWindowTitle(title)
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)
Beispiel #45
0
class MainWindow(QMainWindow):

    """This is the main application window class

    it defines the GUI window for the browser
    """

    def parse_config(self, file_config, options):
        self.config = {}
        options = vars(options)
        for key, metadata in CONFIG_OPTIONS.items():
            options_val = options.get(key)
            file_val = file_config.get(key)
            env_val = os.environ.get(metadata.get("env", ''))
            default_val = metadata.get("default")
            vals = metadata.get("values")
            debug("key: {}, default: {}, file: {}, options: {}".format(
                key, default_val, file_val, options_val
            ))
            if vals:
                options_val = (options_val in vals and options_val) or None
                file_val = (file_val in vals and file_val) or None
                env_val = (env_val in vals and env_val) or None
            if metadata.get("is_file"):
                filename = options_val or env_val
                if not filename:
                    self.config[key] = default_val
                else:
                    try:
                        with open(filename, 'r') as fh:
                            self.config[key] = fh.read()
                    except IOError:
                        debug("Could not open file {} for reading.".format(
                            filename)
                        )
                        self.config[key] = default_val
            else:
                set_values = [
                    val for val in (options_val, env_val, file_val)
                    if val is not None
                ]
                if len(set_values) > 0:
                    self.config[key] = set_values[0]
                else:
                    self.config[key] = default_val
            if metadata.get("type") and self.config[key]:
                debug("{} cast to {}".format(key, metadata.get("type")))
                self.config[key] = metadata.get("type")(self.config[key])
        debug(repr(self.config))

    def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None,
                     checkable=False, signal="triggered"):
        """Return a QAction given a number of common QAction attributes

        Just a shortcut function Originally borrowed from
        'Rapid GUI Development with PyQT' by Mark Summerset
        """
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon.fromTheme(
                icon, QIcon(":/{}.png".format(icon))
            ))
        if shortcut is not None and not shortcut.isEmpty():
            action.setShortcut(shortcut)
            tip += " ({})".format(shortcut.toString())
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            action.__getattr__(signal).connect(slot)
        if checkable:
            action.setCheckable()
        return action

    def __init__(self, options, parent=None):
        """Construct a MainWindow Object."""
        super(MainWindow, self).__init__(parent)
        # Load config file
        self.setWindowTitle("Browser")
        debug("loading configuration from '{}'".format(options.config_file))
        configfile = {}
        if options.config_file:
            configfile = yaml.safe_load(open(options.config_file, 'r'))
        self.parse_config(configfile, options)
        # self.popup will hold a reference to the popup window
        # if it gets opened
        self.popup = None

        # Stylesheet support
        if self.config.get("stylesheet"):
            try:
                with open(self.config.get("stylesheet")) as ss:
                    self.setStyleSheet(ss.read())
            except:
                debug(
                    """Problem loading stylesheet file "{}", """
                    """using default style."""
                    .format(self.config.get("stylesheet"))
                )
        self.setObjectName("global")

        # If the whitelist is activated, add the bookmarks and start_url
        if self.config.get("whitelist"):
            # we can just specify whitelist = True,
            # which should whitelist just the start_url and bookmark urls.
            whitelist = self.config.get("whitelist")
            if type(whitelist) is not list:
                whitelist = []
            whitelist.append(str(QUrl(
                self.config.get("start_url")
            ).host()))
            bookmarks = self.config.get("bookmarks")
            if bookmarks:
                whitelist += [
                    str(QUrl(b.get("url")).host())
                    for k, b in bookmarks.items()
                ]
                self.config["whitelist"] = set(whitelist)  # uniquify and optimize
            debug("Generated whitelist: " + str(whitelist))

        # If diagnostic is enabled, connect CTRL+ALT+? to show some diagnistic info
        if (self.config.get("enable_diagnostic")):
            self.diagnostic_action = self.createAction(
                "Show Diagnostic",
                self.show_diagnostic,
                QKeySequence("Ctrl+Alt+/"),
                tip=''
            )
            self.addAction(self.diagnostic_action)

        self.build_ui()

    # ## END OF CONSTRUCTOR ## #

    def build_ui(self):
        """Set up the user interface for the main window.

        Unlike the constructor, this method is re-run
        whenever the browser is "reset" by the user.
        """

        debug("build_ui")
        inactivity_timeout = self.config.get("timeout")
        quit_button_tooltip = (
            self.config.get("quit_button_mode") == 'close'
            and "Click here to quit the browser."
            or """Click here when you are done.
            It will clear your browsing history"""
            """ and return you to the start page.""")
        qb_mode_callbacks = {'close': self.close, 'reset': self.reset_browser}
        to_mode_callbacks = {'close': self.close,
                             'reset': self.reset_browser,
                             'screensaver': self.screensaver}
        self.screensaver_active = False

        # ##Start GUI configuration## #
        self.browser_window = WcgWebView(self.config)
        self.browser_window.setObjectName("web_content")

        if (
            self.config.get("icon_theme") is not None
            and QT_VERSION_STR > '4.6'
        ):
            QIcon.setThemeName(self.config.get("icon_theme"))
        self.setCentralWidget(self.browser_window)
        debug("loading {}".format(self.config.get("start_url")))
        self.browser_window.setUrl(QUrl(self.config.get("start_url")))
        if self.config.get("fullscreen"):
            self.showFullScreen()
        elif (
            self.config.get("window_size") and
            self.config.get("window_size").lower() == 'max'
        ):
            self.showMaximized()
        elif self.config.get("window_size"):
            size = re.match(r"(\d+)x(\d+)", self.config.get("window_size"))
            if size:
                width, height = size.groups()
                self.setFixedSize(int(width), int(height))
            else:
                debug('Ignoring invalid window size "{}"'.format(
                    self.config.get("window_size")
                ))

        # Set up the top navigation bar if it's configured to exist
        if self.config.get("navigation"):
            self.navigation_bar = QToolBar("Navigation")
            self.navigation_bar.setObjectName("navigation")
            self.addToolBar(Qt.TopToolBarArea, self.navigation_bar)
            self.navigation_bar.setMovable(False)
            self.navigation_bar.setFloatable(False)

            #  Standard navigation tools
            self.nav_items = {}
            self.nav_items["back"] = self.browser_window.pageAction(QWebPage.Back)
            self.nav_items["forward"] = self.browser_window.pageAction(QWebPage.Forward)
            self.nav_items["refresh"] = self.browser_window.pageAction(QWebPage.Reload)
            self.nav_items["stop"] = self.browser_window.pageAction(QWebPage.Stop)
            # The "I'm finished" button.
            self.nav_items["quit"] = self.createAction(
                self.config.get("quit_button_text"),
                qb_mode_callbacks.get(self.config.get("quit_button_mode"), self.reset_browser),
                QKeySequence("Alt+F"),
                None,
                quit_button_tooltip)
            # Zoom buttons
            self.nav_items["zoom_in"] = self.createAction(
                "Zoom In",
                self.zoom_in,
                QKeySequence("Alt++"),
                "zoom-in",
                "Increase the size of the text and images on the page")
            self.nav_items["zoom_out"] = self.createAction(
                "Zoom Out",
                self.zoom_out,
                QKeySequence("Alt+-"),
                "zoom-out",
                "Decrease the size of text and images on the page")
            if self.config.get("allow_printing"):
                self.nav_items["print"] = self.createAction(
                    "Print",
                    self.browser_window.print_webpage,
                    QKeySequence("Ctrl+p"),
                    "document-print",
                    "Print this page")

            # Add all the actions to the navigation bar.
            for item in self.config.get("navigation_layout"):
                if item == "separator":
                    self.navigation_bar.addSeparator()
                elif item == "spacer":
                    # an expanding spacer.
                    spacer = QWidget()
                    spacer.setSizePolicy(
                        QSizePolicy.Expanding, QSizePolicy.Preferred)
                    self.navigation_bar.addWidget(spacer)
                elif item == "bookmarks":
                    # Insert bookmarks buttons here.
                    self.bookmark_buttons = []
                    for bookmark in self.config.get("bookmarks", {}).items():
                        debug("Bookmark:\n" + bookmark.__str__())
                        # bookmark name will use the "name" attribute, if present
                        # or else just the key:
                        bookmark_name = bookmark[1].get("name") or bookmark[0]
                        # Create a button for the bookmark as a QAction,
                        # which we'll add to the toolbar
                        button = self.createAction(
                            bookmark_name,
                            lambda url=bookmark[1].get("url"): self.browser_window.load(QUrl(url)),
                            QKeySequence.mnemonic(bookmark_name),
                            None,
                            bookmark[1].get("description")
                            )
                        self.navigation_bar.addAction(button)
                        self.navigation_bar.widgetForAction(button).setObjectName("navigation_button")
                else:
                    action = self.nav_items.get(item, None)
                    if action:
                        self.navigation_bar.addAction(action)
                        self.navigation_bar.widgetForAction(action).setObjectName("navigation_button")

            # This removes the ability to toggle off the navigation bar:
            self.nav_toggle = self.navigation_bar.toggleViewAction()
            self.nav_toggle.setVisible(False)
            # End "if show_navigation is True" block

        # set hidden quit action
        # For reasons I haven't adequately ascertained,
        # this shortcut fails now and then claiming
        # "Ambiguous shortcut overload".
        # No idea why, as it isn't consistent.
        self.really_quit = self.createAction(
            "", self.close, QKeySequence("Ctrl+Alt+Q"), None, ""
        )
        self.addAction(self.really_quit)

        # Call a reset function after timeout
        if inactivity_timeout != 0:
            self.event_filter = InactivityFilter(inactivity_timeout)
            QCoreApplication.instance().installEventFilter(self.event_filter)
            self.browser_window.page().installEventFilter(self.event_filter)
            self.event_filter.timeout.connect(
                to_mode_callbacks.get(self.config.get("timeout_mode"),
                                      self.reset_browser))
        else:
            self.event_filter = None

        # ##END OF UI SETUP## #

    def screensaver(self):
        """Enter "screensaver" mode

        This method puts the browser in screensaver mode, where a URL
        is displayed while the browser is idle.  Activity causes the browser to
        return to the home screen.
        """
        debug("screensaver started")
        self.screensaver_active = True
        if self.popup:
            self.popup.close()
        if self.config.get("navigation"):
            self.navigation_bar.hide()
        self.browser_window.setZoomFactor(self.config.get("zoom_factor"))
        self.browser_window.load(QUrl(self.config.get("screensaver_url")))
        self.event_filter.timeout.disconnect()
        self.event_filter.activity.connect(self.reset_browser)

    def reset_browser(self):
        """Clear the history and reset the UI.

        Called whenever the inactivity filter times out,
        or when the user clicks the "finished" button in
        'reset' mode.
        """
        # Clear out the memory cache
        QWebSettings.clearMemoryCaches()
        self.browser_window.history().clear()
        # self.navigation_bar.clear() doesn't do its job,
        # so remove the toolbar first, then rebuild the UI.
        debug("RESET BROWSER")
        if self.event_filter:
            self.event_filter.blockSignals(True)
        if self.screensaver_active is True:
            self.screensaver_active = False
            self.event_filter.activity.disconnect()
        if self.event_filter:
            self.event_filter.blockSignals(False)
        if hasattr(self, "navigation_bar"):
            self.removeToolBar(self.navigation_bar)
        self.build_ui()

    def zoom_in(self):
        """Zoom in action callback.

        Note that we cap zooming in at a factor of 3x.
        """
        if self.browser_window.zoomFactor() < 3.0:
            self.browser_window.setZoomFactor(
                self.browser_window.zoomFactor() + 0.1
            )
            self.nav_items["zoom_out"].setEnabled(True)
        else:
            self.nav_items["zoom_in"].setEnabled(False)

    def zoom_out(self):
        """Zoom out action callback.

        Note that we cap zooming out at 0.1x.
        """
        if self.browser_window.zoomFactor() > 0.1:
            self.browser_window.setZoomFactor(
                self.browser_window.zoomFactor() - 0.1
            )
            self.nav_items["zoom_in"].setEnabled(True)
        else:
            self.nav_items["zoom_out"].setEnabled(False)

    def show_diagnostic(self):
        "Display a dialog box with some diagnostic info"
        data = {
            "OS": os.uname(),
            "USER": (os.environ.get("USER")
                     or os.environ.get("USERNAME")),
            "Python": sys.version,
            "Qt": QT_VERSION_STR,
            "Script Date": (
                datetime.datetime.fromtimestamp(
                    os.stat(__file__).st_mtime).isoformat()
            )
        }
        html = "\n".join([
            "<h1>System Information</h1>",
            "<h2>Please click &quot;",
            self.config.get("quit_button_text").replace("&", ''),
            "&quot; when you are finished.</h2>",
            "<ul>",
            "\n".join([
                "<li><b>{}</b>: {}</li>".format(k, v)
                for k, v in data.items()
            ]),
            "</ul>"
        ])
        self.browser_window.setHtml(html)
Beispiel #46
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
Beispiel #47
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()
Beispiel #48
0
class MainWindow(QMainWindow, ui_window.Ui_Window):
    emulator_found = QtCore.pyqtSignal(dict)
    emulators_loaded = QtCore.pyqtSignal()

    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)

        self.emulators = { }

        self.settings = QSettings('SanderTheDragon', 'Qtendo')

        self.ui_create()
        self.ui_connect()
        self.settings_load()



    def showEvent(self, ev):
        QMainWindow.showEvent(self, ev)

        self.statusBar.showMsg('Searching for emulators', 1000)
        Thread(target=self.find_emulators, daemon=True).start()


    def closeEvent(self, ev):
        QMainWindow.closeEvent(self, ev)

        self.settings_save()



    def ui_create(self):
        #Add toolbar
        self.toolBar = QToolBar()
        self.toolBar.addAction(self.actionPageEmulation)
        self.toolBar.setFloatable(False)
        self.toolBar.setMovable(False)
        self.toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.gridLayout.addWidget(self.toolBar, 1, 0)

        #Add a second toolbar on emulation page
        self.toolBarEmulation = QToolBar()
        self.toolBarEmulation.setFloatable(False)
        self.toolBarEmulation.setMovable(False)
        self.toolBarEmulation.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.pageEmulationLayout.addWidget(self.toolBarEmulation, 0, 0)

        #Add progress bar to status bar
        self.taskProgress = QProgressBar()
        self.taskProgress.setVal = lambda x: ( self.taskProgress.setVisible(True), self.taskProgress.setValue(x) )
        self.taskProgress.setVal(0)
        self.taskProgress.setTextVisible(False)
        self.statusBar.addPermanentWidget(self.taskProgress)

        #Also print messages to terminal
        self.statusBar.showMsg = lambda msg, timeout: ( logging.info(msg), self.statusBar.showMessage(msg, timeout) )

        #Styling
        self.setStyleSheet('QToolButton { padding-right: -3px; }')


    def ui_connect(self):
        #Menu actions
        self.actionQuit.triggered.connect(QCoreApplication.quit)
        self.actionSettings.triggered.connect(lambda: settings.SettingsDialog(parent=self).exec_())
        self.actionAbout.triggered.connect(lambda: about.AboutDialog(parent=self).exec_())

        #Toolbar actions
        self.actionPageEmulation.triggered.connect(lambda: self.stackedWidget.setCurrentIndex(0))

        #Other signals
        self.emulator_found.connect(self.add_emulator)
        self.emulators_loaded.connect(self.reset_status)


    def settings_load(self):
        if self.settings.value('qtendo/window/restore', True, type=bool):
            self.restoreGeometry(self.settings.value('qtendo/window/geometry', type=QByteArray))


    def settings_save(self):
        if self.settings.value('qtendo/window/restore', True, type=bool):
            self.settings.setValue('qtendo/window/geometry', self.saveGeometry())



    def change_emulator(self, index):
        current = self.stackedWidgetEmulation.currentIndex()

        if current != index:
            emulator = self.emulators[list(self.emulators.keys())[current]]
            emulator['action'].setIcon(QIcon(emulator['action'].icon().pixmap(QSize(24, 24), QIcon.Disabled)))

            self.stackedWidgetEmulation.setCurrentIndex(index)
            emulator = self.emulators[list(self.emulators.keys())[index]]
            emulator['action'].setIcon(QIcon(':' + emulator['icon']))


    def add_emulator(self, emulator):
        if len(emulator['path']) > 0:
            self.statusBar.showMsg('Found ' + emulator['name'], 1000)
        else:
            self.statusBar.showMsg('Failed to find ' + emulator['name'], 1000)

        self.emulators[emulator['name']] = emulator

        i = self.stackedWidgetEmulation.count()
        emulator['action'] = QAction()

        emulator['action'].setIcon(QIcon(':' + emulator['icon']))
        if i > 0:
            self.toolBarEmulation.addSeparator()
            emulator['action'].setIcon(QIcon(emulator['action'].icon().pixmap(QSize(24, 24), QIcon.Disabled)))

        emulator['action'].setIconText(emulator['name'])
        emulator['action'].triggered.connect(lambda checked, index=i: self.change_emulator(index))

        self.toolBarEmulation.addAction(emulator['action'])
        self.stackedWidgetEmulation.insertWidget(i, emulator['widget'](emulator))

        if len(self.settings.value('emulation/emulator/' + emulator['name'].lower().replace(' ', '_') + '/path', emulator['path'], type=str)) == 0:
            self.toolBarEmulation.widgetForAction(emulator['action']).setStyleSheet('color: ' + QApplication.palette().color(QPalette.Disabled, QPalette.WindowText).name() + ';')

        emulator['reload_settings'] = self.reload_settings

        self.taskProgress.setVal(int((100.0 / float(emulator_count)) * float(i + 1)))


    def reset_status(self):
        self.statusBar.clearMessage()
        self.taskProgress.setValue(0)
        self.taskProgress.setVisible(False)


    def reload_settings(self):
        emulator = self.emulators[list(self.emulators.keys())[self.stackedWidgetEmulation.currentIndex()]]

        if len(self.settings.value('emulation/emulator/' + emulator['name'].lower().replace(' ', '_') + '/path', emulator['path'], type=str)) == 0:
            self.toolBarEmulation.widgetForAction(emulator['action']).setStyleSheet('color: ' + QApplication.palette().color(QPalette.Disabled, QPalette.WindowText).name() + ';')
        else:
            self.toolBarEmulation.widgetForAction(emulator['action']).setStyleSheet('')



    def find_emulators(self):
        #Search for FCEUX
        self.emulator_found.emit(fceux.find(None if not self.settings.contains('emulation/emulator/fceux/path') else self.settings.value('emulation/emulator/fceux/path', type=str)))
        #Search for ZSNES
        self.emulator_found.emit(zsnes.find(None if not self.settings.contains('emulation/emulator/zsnes/path') else self.settings.value('emulation/emulator/zsnes/path', type=str)))
        #Search for Mupen64Plus
        self.emulator_found.emit(mupen64plus.find(None if not self.settings.contains('emulation/emulator/mupen64plus/path') else self.settings.value('emulation/emulator/mupen64plus/path', type=str)))
        #Search for Dolphin Emulator
        self.emulator_found.emit(dolphin.find(None if not self.settings.contains('emulation/emulator/dolphin/path') else self.settings.value('emulation/emulator/dolphin/path', type=str)))
        #Search for Citra
        self.emulator_found.emit(citra.find(None if not self.settings.contains('emulation/emulator/citra/path') else self.settings.value('emulation/emulator/citra/path', type=str)))

        self.emulators_loaded.emit()
Beispiel #49
0
class AppWindow(QMainWindow):
    "The application's main window"

    def __init__(self):
        super().__init__()
        self.initUI()
        self.start_up()
        QTimer.singleShot(3000, self._check_update)

    def init_watchers(self):
        def remove_gallery(g):
            index = self.manga_list_view.find_index(g.id)
            if index:
                self.manga_list_view.remove_gallery([index])

        def create_gallery(path):
            g_dia = gallerydialog.GalleryDialog(self, path)
            g_dia.SERIES.connect(self.manga_list_view.gallery_model.addRows)
            g_dia.show()

        def update_gallery(g):
            index = self.manga_list_view.find_index(g.id)
            if index:
                self.manga_list_view.replace_edit_gallery([g], index.row())
            else:
                log_e("Could not find gallery to update from Watcher")

        def created(path):
            c_popup = file_misc.CreatedPopup(path, self)
            c_popup.ADD_SIGNAL.connect(create_gallery)

        def modified(path, gallery):
            mod_popup = file_misc.ModifiedPopup(path, gallery, self)

        def deleted(path, gallery):
            d_popup = file_misc.DeletedPopup(path, gallery, self)
            d_popup.UPDATE_SIGNAL.connect(update_gallery)
            d_popup.REMOVE_SIGNAL.connect(remove_gallery)

        def moved(new_path, gallery):
            mov_popup = file_misc.MovedPopup(new_path, gallery, self)
            mov_popup.UPDATE_SIGNAL.connect(update_gallery)

        self.watchers = file_misc.Watchers()
        self.watchers.gallery_handler.CREATE_SIGNAL.connect(created)
        self.watchers.gallery_handler.MODIFIED_SIGNAL.connect(modified)
        self.watchers.gallery_handler.MOVED_SIGNAL.connect(moved)
        self.watchers.gallery_handler.DELETED_SIGNAL.connect(deleted)

        if gui_constants.LOOK_NEW_GALLERY_STARTUP:
            self.notification_bar.add_text("Looking for new galleries...")
            try:

                class ScanDir(QObject):
                    final_paths_and_galleries = pyqtSignal(list, list)

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

                    def scan_dirs(self):
                        db_data = self.model_data
                        paths = []
                        for g in range(len(db_data)):
                            paths.append(os.path.normcase(db_data[g].path))

                        contents = []
                        case_path = []  # needed for tile and artist parsing... e.g to avoid lowercase
                        for m_path in gui_constants.MONITOR_PATHS:
                            for p in os.listdir(m_path):
                                abs_p = os.path.join(m_path, p)
                                if os.path.isdir(abs_p) or p.endswith(utils.ARCHIVE_FILES):
                                    case_path.append(abs_p)
                                    contents.append(os.path.normcase(abs_p))

                        paths = sorted(paths)
                        new_galleries = []
                        for c, x in enumerate(contents):
                            y = utils.b_search(paths, x)
                            if not y:
                                # (path, number for case_path)
                                new_galleries.append((x, c))

                        galleries = []
                        final_paths = []
                        if new_galleries:
                            for g in new_galleries:
                                gallery = gallerydb.Gallery()
                                try:
                                    gallery.profile = utils.get_gallery_img(g[0])
                                except:
                                    gallery.profile = gui_constants.NO_IMAGE_PATH
                                parser_dict = utils.title_parser(os.path.split(case_path[g[1]])[1])
                                gallery.title = parser_dict["title"]
                                gallery.artist = parser_dict["artist"]
                                galleries.append(gallery)
                                final_paths.append(case_path[g[1]])
                        self.final_paths_and_galleries.emit(final_paths, galleries)
                        # if gui_constants.LOOK_NEW_GALLERY_AUTOADD:
                        # 	QTimer.singleShot(10000, self.gallery_populate(final_paths))
                        # 	return

                def show_new_galleries(final_paths, galleries):
                    if final_paths and galleries:
                        if gui_constants.LOOK_NEW_GALLERY_AUTOADD:
                            self.gallery_populate(final_paths)
                        else:
                            if len(galleries) == 1:
                                self.notification_bar.add_text(
                                    "{} new gallery was discovered in one of your monitored directories".format(
                                        len(galleries)
                                    )
                                )
                            else:
                                self.notification_bar.add_text(
                                    "{} new galleries were discovered in one of your monitored directories".format(
                                        len(galleries)
                                    )
                                )
                            text = (
                                "These new galleries were discovered! Do you want to add them?"
                                if len(galleries) > 1
                                else "This new gallery was discovered! Do you want to add it?"
                            )
                            g_popup = file_misc.GalleryPopup((text, galleries), self)
                            buttons = g_popup.add_buttons("Add", "Close")

                            def populate_n_close():
                                self.gallery_populate(final_paths)
                                g_popup.close()

                            buttons[0].clicked.connect(populate_n_close)
                            buttons[1].clicked.connect(g_popup.close)

                thread = QThread(self)
                self.scan_inst = ScanDir(self.manga_list_view.gallery_model._data)
                self.scan_inst.moveToThread(thread)
                self.scan_inst.final_paths_and_galleries.connect(show_new_galleries)
                self.scan_inst.final_paths_and_galleries.connect(lambda a: self.scan_inst.deleteLater())
                thread.started.connect(self.scan_inst.scan_dirs)
                thread.finished.connect(thread.deleteLater)
                thread.start()
            except:
                self.notification_bar.add_text(
                    "An error occured while attempting to scan for new galleries. Check happypanda.log."
                )
                log.exception("An error occured while attempting to scan for new galleries.")

    def start_up(self):
        def normalize_first_time():
            settings.set(2, "Application", "first time level")

        def done():
            self.manga_list_view.gallery_model.init_data()
            if gui_constants.ENABLE_MONITOR and gui_constants.MONITOR_PATHS and all(gui_constants.MONITOR_PATHS):
                self.init_watchers()
            if gui_constants.FIRST_TIME_LEVEL != 2:
                normalize_first_time()

        if gui_constants.FIRST_TIME_LEVEL < 2:

            class FirstTime(file_misc.BasePopup):
                def __init__(self, parent=None):
                    super().__init__(parent)
                    main_layout = QVBoxLayout()
                    info_lbl = QLabel(
                        "Hi there! Some big changes are about to occur!\n"
                        + "Please wait.. This will take at most a few minutes.\n"
                        + "If not then try restarting the application."
                    )
                    info_lbl.setAlignment(Qt.AlignCenter)
                    main_layout.addWidget(info_lbl)
                    prog = QProgressBar(self)
                    prog.setMinimum(0)
                    prog.setMaximum(0)
                    prog.setTextVisible(False)
                    main_layout.addWidget(prog)
                    main_layout.addWidget(QLabel("Note: This popup will close itself when everything is ready"))
                    self.main_widget.setLayout(main_layout)

            ft_widget = FirstTime(self)
            log_i("Invoking first time level 2")
            bridge = gallerydb.Bridge()
            thread = QThread(self)
            thread.setObjectName("Startup")
            bridge.moveToThread(thread)
            thread.started.connect(bridge.rebuild_galleries)
            bridge.DONE.connect(ft_widget.close)
            bridge.DONE.connect(self.setEnabled)
            bridge.DONE.connect(done)
            bridge.DONE.connect(bridge.deleteLater)
            thread.finished.connect(thread.deleteLater)
            thread.start()
            ft_widget.adjustSize()
            ft_widget.show()
            self.setEnabled(False)
        else:
            done()

    def initUI(self):
        self.center = QWidget()
        self.display = QStackedLayout()
        self.center.setLayout(self.display)
        # init the manga view variables
        self.manga_display()
        log_d("Create manga display: OK")
        # init the chapter view variables
        # self.chapter_display()
        self.m_l_view_index = self.display.addWidget(self.manga_list_main)
        self.m_t_view_index = self.display.addWidget(self.manga_table_view)
        # init toolbar
        self.init_toolbar()
        log_d("Create toolbar: OK")
        # init status bar
        self.init_stat_bar()
        log_d("Create statusbar: OK")

        self.system_tray = misc.SystemTray(QIcon(gui_constants.APP_ICO_PATH), self)
        gui_constants.SYSTEM_TRAY = self.system_tray
        tray_menu = QMenu(self)
        self.system_tray.setContextMenu(tray_menu)
        self.system_tray.setToolTip("Happypanda {}".format(gui_constants.vs))
        tray_quit = QAction("Quit", tray_menu)
        tray_menu.addAction(tray_quit)
        tray_quit.triggered.connect(self.close)
        self.system_tray.show()
        log_d("Create system tray: OK")

        # self.display.addWidget(self.chapter_main)

        self.setCentralWidget(self.center)
        self.setWindowTitle("Happypanda")
        self.setWindowIcon(QIcon(gui_constants.APP_ICO_PATH))

        props = settings.win_read(self, "AppWindow")
        if props.resize:
            x, y = props.resize
            self.resize(x, y)
        else:
            self.resize(gui_constants.MAIN_W, gui_constants.MAIN_H)
        posx, posy = props.pos
        self.move(posx, posy)
        self.show()
        log_d("Show window: OK")

        self.notification_bar = misc.NotificationOverlay(self)
        p = self.toolbar.pos()
        self.notification_bar.move(p.x(), p.y() + self.toolbar.height())
        self.notification_bar.resize(self.width())
        gui_constants.NOTIF_BAR = self.notification_bar
        log_d("Create notificationbar: OK")

        log_d("Window Create: OK")

    def _check_update(self):
        class upd_chk(QObject):
            UPDATE_CHECK = pyqtSignal(str)

            def __init__(self, **kwargs):
                super().__init__(**kwargs)

            def fetch_vs(self):
                import requests
                import time

                try:
                    log_d("Checking Update")
                    time.sleep(1.5)
                    r = requests.get(
                        "https://raw.githubusercontent.com/Pewpews/happypanda/master/VS.txt", verify="cacert.pem"
                    )
                    a = r.text
                    vs = a.strip()
                    self.UPDATE_CHECK.emit(vs)
                except:
                    log.exception("Checking Update: FAIL")
                    self.UPDATE_CHECK.emit("this is a very long text which is is sure to be over limit")

        def check_update(vs):
            log_i("Received version: {}\nCurrent version: {}".format(vs, gui_constants.vs))
            if vs != gui_constants.vs:
                if len(vs) < 10:
                    self.notification_bar.add_text(
                        "Version {} of Happypanda is".format(vs) + " available. Click here to update!", False
                    )
                    self.notification_bar.clicked.connect(
                        lambda: utils.open_web_link("https://github.com/Pewpews/happypanda/releases")
                    )
                    self.notification_bar.set_clickable(True)
                else:
                    self.notification_bar.add_text("An error occurred while checking for new version")

        self.update_instance = upd_chk()
        thread = QThread(self)
        self.update_instance.moveToThread(thread)
        thread.started.connect(self.update_instance.fetch_vs)
        self.update_instance.UPDATE_CHECK.connect(check_update)
        self.update_instance.UPDATE_CHECK.connect(self.update_instance.deleteLater)
        thread.finished.connect(thread.deleteLater)
        thread.start()

    def _web_metadata_picker(self, gallery, title_url_list, queue, parent=None):
        if not parent:
            parent = self
        text = "Which gallery do you want to extract metadata from?"
        s_gallery_popup = misc.SingleGalleryChoices(gallery, title_url_list, text, parent)
        s_gallery_popup.USER_CHOICE.connect(queue.put)

    def get_metadata(self, gal=None):
        thread = QThread(self)
        thread.setObjectName("App.get_metadata")
        fetch_instance = fetch.Fetch()
        if gal:
            galleries = [gal]
        else:
            if gui_constants.CONTINUE_AUTO_METADATA_FETCHER:
                galleries = [g for g in self.manga_list_view.gallery_model._data if not g.exed]
            else:
                galleries = self.manga_list_view.gallery_model._data
            if not galleries:
                self.notification_bar.add_text("Looks like we've already gone through all galleries!")
                return None
        fetch_instance.galleries = galleries

        self.notification_bar.begin_show()
        fetch_instance.moveToThread(thread)

        def done(status):
            self.notification_bar.end_show()
            fetch_instance.deleteLater()

        fetch_instance.GALLERY_PICKER.connect(self._web_metadata_picker)
        fetch_instance.GALLERY_EMITTER.connect(self.manga_list_view.replace_edit_gallery)
        fetch_instance.AUTO_METADATA_PROGRESS.connect(self.notification_bar.add_text)
        thread.started.connect(fetch_instance.auto_web_metadata)
        fetch_instance.FINISHED.connect(done)
        thread.finished.connect(thread.deleteLater)
        thread.start()

        # def style_tooltip(self):
        # 	palette = QToolTip.palette()
        # 	palette.setColor()

    def init_stat_bar(self):
        self.status_bar = self.statusBar()
        self.status_bar.setMaximumHeight(20)
        self.status_bar.setSizeGripEnabled(False)
        self.stat_info = QLabel()
        self.stat_info.setIndent(5)
        self.sort_main = QAction("Asc", self)
        sort_menu = QMenu()
        self.sort_main.setMenu(sort_menu)
        s_by_title = QAction("Title", sort_menu)
        s_by_artist = QAction("Artist", sort_menu)
        sort_menu.addAction(s_by_title)
        sort_menu.addAction(s_by_artist)
        self.status_bar.addPermanentWidget(self.stat_info)
        # self.status_bar.addAction(self.sort_main)
        self.temp_msg = QLabel()
        self.temp_timer = QTimer()

        self.manga_list_view.gallery_model.ROWCOUNT_CHANGE.connect(self.stat_row_info)
        self.manga_list_view.gallery_model.STATUSBAR_MSG.connect(self.stat_temp_msg)
        self.manga_list_view.STATUS_BAR_MSG.connect(self.stat_temp_msg)
        self.manga_table_view.STATUS_BAR_MSG.connect(self.stat_temp_msg)
        self.stat_row_info()

    def stat_temp_msg(self, msg):
        self.temp_timer.stop()
        self.temp_msg.setText(msg)
        self.status_bar.addWidget(self.temp_msg)
        self.temp_timer.timeout.connect(self.temp_msg.clear)
        self.temp_timer.setSingleShot(True)
        self.temp_timer.start(5000)

    def stat_row_info(self):
        r = self.manga_list_view.model().rowCount()
        t = self.manga_list_view.gallery_model._data_count
        self.stat_info.setText("Loaded {} of {} ".format(r, t))

    def manga_display(self):
        "initiates the manga view"
        # list view
        self.manga_list_main = QWidget()
        # self.manga_list_main.setContentsMargins(-10, -12, -10, -10)
        self.manga_list_main.setContentsMargins(10, -9, -10, -10)  # x, y, inverted_width, inverted_height
        self.manga_list_layout = QHBoxLayout()
        self.manga_list_main.setLayout(self.manga_list_layout)

        self.manga_list_view = gallery.MangaView(self)
        self.manga_list_view.clicked.connect(self.popup)
        self.manga_list_view.manga_delegate.POPUP.connect(self.popup)
        self.popup_window = self.manga_list_view.manga_delegate.popup_window
        self.manga_list_layout.addWidget(self.manga_list_view)

        # table view
        self.manga_table_main = QWidget()
        self.manga_table_layout = QVBoxLayout()
        self.manga_table_main.setLayout(self.manga_table_layout)

        self.manga_table_view = gallery.MangaTableView(self)
        self.manga_table_view.gallery_model = self.manga_list_view.gallery_model
        self.manga_table_view.sort_model = self.manga_list_view.sort_model
        self.manga_table_view.setModel(self.manga_table_view.sort_model)
        self.manga_table_view.sort_model.change_model(self.manga_table_view.gallery_model)
        self.manga_table_view.setColumnWidth(gui_constants.FAV, 20)
        self.manga_table_view.setColumnWidth(gui_constants.ARTIST, 200)
        self.manga_table_view.setColumnWidth(gui_constants.TITLE, 400)
        self.manga_table_view.setColumnWidth(gui_constants.TAGS, 300)
        self.manga_table_view.setColumnWidth(gui_constants.TYPE, 60)
        self.manga_table_view.setColumnWidth(gui_constants.CHAPTERS, 60)
        self.manga_table_view.setColumnWidth(gui_constants.LANGUAGE, 100)
        self.manga_table_view.setColumnWidth(gui_constants.LINK, 400)
        self.manga_table_layout.addWidget(self.manga_table_view)

    def search(self, srch_string):
        case_ins = srch_string.lower()
        if not gui_constants.ALLOW_SEARCH_REGEX:
            remove = "^$*+?{}\\|()[]"
            for x in remove:
                if x == "[" or x == "]":
                    continue
                else:
                    case_ins = case_ins.replace(x, ".")
        else:
            try:
                re.compile(case_ins)
            except re.error:
                return
        self.manga_list_view.sort_model.search(case_ins)

    def popup(self, index):
        if not self.popup_window.isVisible():
            m_x = QCursor.pos().x()
            m_y = QCursor.pos().y()
            d_w = QDesktopWidget().width()
            d_h = QDesktopWidget().height()
            p_w = gui_constants.POPUP_WIDTH
            p_h = gui_constants.POPUP_HEIGHT

            index_rect = self.manga_list_view.visualRect(index)
            index_point = self.manga_list_view.mapToGlobal(index_rect.topRight())
            # adjust so it doesn't go offscreen
            if d_w - m_x < p_w and d_h - m_y < p_h:  # bottom
                self.popup_window.move(m_x - p_w + 5, m_y - p_h)
            elif d_w - m_x > p_w and d_h - m_y < p_h:
                self.popup_window.move(m_x + 5, m_y - p_h)
            elif d_w - m_x < p_w:
                self.popup_window.move(m_x - p_w + 5, m_y + 5)
            else:
                self.popup_window.move(index_point)

            self.popup_window.set_gallery(index.data(Qt.UserRole + 1))
            self.popup_window.show()

    def favourite_display(self):
        "Switches to favourite display"
        if self.display.currentIndex() == self.m_l_view_index:
            self.manga_list_view.sort_model.fav_view()
        else:
            self.manga_table_view.sort_model.fav_view()

    def catalog_display(self):
        "Switches to catalog display"
        if self.display.currentIndex() == self.m_l_view_index:
            self.manga_list_view.sort_model.catalog_view()
        else:
            self.manga_table_view.sort_model.catalog_view()

    def settings(self):
        sett = settingsdialog.SettingsDialog(self)
        sett.scroll_speed_changed.connect(self.manga_list_view.updateGeometries)
        # sett.show()

    def init_toolbar(self):
        self.toolbar = QToolBar()
        self.toolbar.setFixedHeight(25)
        self.toolbar.setWindowTitle("Show")  # text for the contextmenu
        # self.toolbar.setStyleSheet("QToolBar {border:0px}") # make it user defined?
        self.toolbar.setMovable(False)
        self.toolbar.setFloatable(False)
        # self.toolbar.setIconSize(QSize(20,20))
        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

        spacer_start = QWidget()  # aligns the first actions properly
        spacer_start.setFixedSize(QSize(10, 1))
        self.toolbar.addWidget(spacer_start)

        favourite_view_icon = QIcon(gui_constants.STAR_BTN_PATH)
        favourite_view_action = QAction(favourite_view_icon, "Favorites", self)
        favourite_view_action.setToolTip("Show only favourite galleries")
        favourite_view_action.triggered.connect(self.favourite_display)  # need lambda to pass extra args
        self.toolbar.addAction(favourite_view_action)

        catalog_view_icon = QIcon(gui_constants.HOME_BTN_PATH)
        catalog_view_action = QAction(catalog_view_icon, "Library", self)
        catalog_view_action.setToolTip("Show all your galleries")
        # catalog_view_action.setText("Catalog")
        catalog_view_action.triggered.connect(self.catalog_display)  # need lambda to pass extra args
        self.toolbar.addAction(catalog_view_action)
        self.toolbar.addSeparator()

        gallery_menu = QMenu()
        gallery_action = QToolButton()
        gallery_action.setText("Gallery ")
        gallery_action.setPopupMode(QToolButton.InstantPopup)
        gallery_action.setToolTip("Contains various gallery related features")
        gallery_action.setMenu(gallery_menu)
        add_gallery_icon = QIcon(gui_constants.PLUS_PATH)
        gallery_action_add = QAction(add_gallery_icon, "Add gallery", self)
        gallery_action_add.triggered.connect(self.manga_list_view.SERIES_DIALOG.emit)
        gallery_action_add.setToolTip("Add a single gallery thoroughly")
        gallery_menu.addAction(gallery_action_add)
        add_more_action = QAction(add_gallery_icon, "Add galleries...", self)
        add_more_action.setStatusTip("Add galleries from different folders")
        add_more_action.triggered.connect(lambda: self.populate(True))
        gallery_menu.addAction(add_more_action)
        populate_action = QAction(add_gallery_icon, "Populate from folder...", self)
        populate_action.setStatusTip("Populates the DB with galleries from a single folder")
        populate_action.triggered.connect(self.populate)
        gallery_menu.addAction(populate_action)
        gallery_menu.addSeparator()
        metadata_action = QAction("Get metadata for all galleries", self)
        metadata_action.triggered.connect(self.get_metadata)
        gallery_menu.addAction(metadata_action)
        self.toolbar.addWidget(gallery_action)
        self.toolbar.addSeparator()

        misc_action = QToolButton()
        misc_action.setText("Misc ")
        misc_action_menu = QMenu()
        misc_action.setMenu(misc_action_menu)
        misc_action.setPopupMode(QToolButton.InstantPopup)
        misc_action.setToolTip("Contains misc. features")
        misc_action_random = QAction("Open random gallery", misc_action_menu)
        misc_action_random.triggered.connect(self.manga_list_view.open_random_gallery)
        misc_action_menu.addAction(misc_action_random)
        duplicate_check_simple = QAction("Simple duplicate finder", misc_action_menu)
        duplicate_check_simple.triggered.connect(lambda: self.manga_list_view.duplicate_check())
        misc_action_menu.addAction(duplicate_check_simple)
        self.toolbar.addWidget(misc_action)

        spacer_middle = QWidget()  # aligns buttons to the right
        spacer_middle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.toolbar.addWidget(spacer_middle)

        self.grid_toggle_g_icon = QIcon(gui_constants.GRID_PATH)
        self.grid_toggle_l_icon = QIcon(gui_constants.LIST_PATH)
        self.grid_toggle = QToolButton()
        if self.display.currentIndex() == self.m_l_view_index:
            self.grid_toggle.setIcon(self.grid_toggle_l_icon)
        else:
            self.grid_toggle.setIcon(self.grid_toggle_g_icon)
        self.grid_toggle.setObjectName("gridtoggle")
        self.grid_toggle.clicked.connect(self.toggle_view)
        self.toolbar.addWidget(self.grid_toggle)

        self.search_bar = misc.LineEdit()
        if gui_constants.SEARCH_AUTOCOMPLETE:
            completer = QCompleter(self)
            completer.setModel(self.manga_list_view.gallery_model)
            completer.setCaseSensitivity(Qt.CaseInsensitive)
            completer.setCompletionMode(QCompleter.PopupCompletion)
            completer.setCompletionRole(Qt.DisplayRole)
            completer.setCompletionColumn(gui_constants.TITLE)
            completer.setFilterMode(Qt.MatchContains)
            self.search_bar.setCompleter(completer)
        if gui_constants.SEARCH_ON_ENTER:
            self.search_bar.returnPressed.connect(lambda: self.search(self.search_bar.text()))
        else:
            self.search_bar.textChanged[str].connect(self.search)
        self.search_bar.setPlaceholderText("Search title, artist, namespace & tags")
        self.search_bar.setMinimumWidth(150)
        self.search_bar.setMaximumWidth(500)
        self.toolbar.addWidget(self.search_bar)
        self.toolbar.addSeparator()
        settings_icon = QIcon(gui_constants.SETTINGS_PATH)
        settings_action = QAction("Set&tings", self)
        settings_action.triggered.connect(self.settings)
        self.toolbar.addAction(settings_action)

        spacer_end = QWidget()  # aligns About action properly
        spacer_end.setFixedSize(QSize(10, 1))
        self.toolbar.addWidget(spacer_end)
        self.addToolBar(self.toolbar)

    def toggle_view(self):
        """
		Toggles the current display view
		"""
        if self.display.currentIndex() == self.m_l_view_index:
            self.display.setCurrentIndex(self.m_t_view_index)
            self.grid_toggle.setIcon(self.grid_toggle_g_icon)
        else:
            self.display.setCurrentIndex(self.m_l_view_index)
            self.grid_toggle.setIcon(self.grid_toggle_l_icon)

            # TODO: Improve this so that it adds to the gallery dialog,
            # so user can edit data before inserting (make it a choice)

    def populate(self, mixed=None):
        "Populates the database with gallery from local drive'"
        if mixed:
            gallery_view = misc.GalleryListView(self, True)
            gallery_view.SERIES.connect(self.gallery_populate)
            gallery_view.show()
        else:
            path = QFileDialog.getExistingDirectory(None, "Choose a folder containing your galleries")
            self.gallery_populate(path, True)

    def gallery_populate(self, path, validate=False):
        "Scans the given path for gallery to add into the DB"
        if len(path) is not 0:
            data_thread = QThread(self)
            data_thread.setObjectName("General gallery populate")
            loading = misc.Loading(self)
            if not loading.ON:
                misc.Loading.ON = True
                fetch_instance = fetch.Fetch()
                fetch_instance.series_path = path
                loading.show()

                def finished(status):
                    def hide_loading():
                        loading.hide()

                    if status:
                        if len(status) != 0:

                            def add_gallery(gallery_list):
                                def append_to_model(x):
                                    self.manga_list_view.gallery_model.insertRows(x, None, len(x))

                                class A(QObject):
                                    done = pyqtSignal()
                                    prog = pyqtSignal(int)

                                    def __init__(self, obj, parent=None):
                                        super().__init__(parent)
                                        self.obj = obj
                                        self.galleries = []

                                    def add_to_db(self):
                                        gui_constants.NOTIF_BAR.begin_show()
                                        gui_constants.NOTIF_BAR.add_text("Populating database...")
                                        for y, x in enumerate(self.obj):
                                            gui_constants.NOTIF_BAR.add_text(
                                                "Populating database {}/{}".format(y + 1, len(self.obj))
                                            )
                                            gallerydb.add_method_queue(gallerydb.GalleryDB.add_gallery_return, False, x)
                                            self.galleries.append(x)
                                            y += 1
                                            self.prog.emit(y)
                                        append_to_model(self.galleries)
                                        gui_constants.NOTIF_BAR.end_show()
                                        self.done.emit()

                                loading.progress.setMaximum(len(gallery_list))
                                a_instance = A(gallery_list)
                                thread = QThread(self)
                                thread.setObjectName("Database populate")

                                def loading_show():
                                    loading.setText("Populating database.\nPlease wait...")
                                    loading.show()

                                def loading_hide():
                                    loading.close()
                                    self.manga_list_view.gallery_model.ROWCOUNT_CHANGE.emit()

                                def del_later():
                                    try:
                                        a_instance.deleteLater()
                                    except NameError:
                                        pass

                                a_instance.moveToThread(thread)
                                a_instance.prog.connect(loading.progress.setValue)
                                thread.started.connect(loading_show)
                                thread.started.connect(a_instance.add_to_db)
                                a_instance.done.connect(loading_hide)
                                a_instance.done.connect(del_later)
                                thread.finished.connect(thread.deleteLater)
                                thread.start()

                            data_thread.quit
                            hide_loading()
                            log_i("Populating DB from gallery folder: OK")
                            if validate:
                                gallery_list = misc.GalleryListView(self)
                                gallery_list.SERIES.connect(add_gallery)
                                for ser in status:
                                    gallery_list.add_gallery(ser, os.path.split(ser.path)[1])
                                    # self.manga_list_view.gallery_model.populate_data()
                                gallery_list.show()
                            else:
                                add_gallery(status)
                            misc.Loading.ON = False
                        else:
                            log_d("No new gallery was found")
                            loading.setText("No new gallery found")
                            data_thread.quit
                            misc.Loading.ON = False

                    else:
                        log_e("Populating DB from gallery folder: Nothing was added!")
                        loading.setText("<font color=red>Nothing was added. Check happypanda_log for details..</font>")
                        loading.progress.setStyleSheet("background-color:red;")
                        data_thread.quit
                        QTimer.singleShot(10000, loading.close)

                def fetch_deleteLater():
                    try:
                        fetch_instance.deleteLater
                    except NameError:
                        pass

                def a_progress(prog):
                    loading.progress.setValue(prog)
                    loading.setText("Searching for galleries...")

                fetch_instance.moveToThread(data_thread)
                fetch_instance.DATA_COUNT.connect(loading.progress.setMaximum)
                fetch_instance.PROGRESS.connect(a_progress)
                data_thread.started.connect(fetch_instance.local)
                fetch_instance.FINISHED.connect(finished)
                fetch_instance.FINISHED.connect(fetch_deleteLater)
                data_thread.finished.connect(data_thread.deleteLater)
                data_thread.start()
                log_i("Populating DB from gallery folder")

    def resizeEvent(self, event):
        try:
            self.notification_bar.resize(event.size().width())
        except AttributeError:
            pass
        return super().resizeEvent(event)

    def closeEvent(self, event):
        # watchers
        try:
            self.watchers.stop_all()
        except AttributeError:
            pass

            # settings
        settings.set(self.manga_list_view.current_sort, "General", "current sort")
        settings.win_save(self, "AppWindow")

        # temp dir
        try:
            for root, dirs, files in os.walk("temp", topdown=False):
                for name in files:
                    os.remove(os.path.join(root, name))
                for name in dirs:
                    os.rmdir(os.path.join(root, name))
            log_d("Empty temp on exit: OK")
        except:
            log_d("Empty temp on exit: FAIL")

            # error
        err = sys.exc_info()
        if all(err):
            log_c("Last error before exit:\n{}\n{}\n{}".format(err[0], err[1], err[2]))
        else:
            log_d("Normal Exit App: OK")
        super().closeEvent(event)
        app = QApplication.instance()
        app.quit()
        sys.exit()
Beispiel #50
0
class AppWindow(QMainWindow):
	"The application's main window"
	def __init__(self):
		super().__init__()
		self.center = QWidget()
		self.display = QStackedLayout()
		self.center.setLayout(self.display)
		# init the manga view variables
		self.manga_display()
		# init the chapter view variables
		self.chapter_display()
		# init toolbar
		self.init_toolbar()
		# init status bar
		self.init_stat_bar()

		self.display.addWidget(self.manga_main)
		self.display.addWidget(self.chapter_main)

		self.setCentralWidget(self.center)
		self.setWindowTitle("Happypanda")
		self.resize(1029, 650)
		self.show()
	
	def init_stat_bar(self):
		self.status_bar = self.statusBar()
		self.status_bar.setMaximumHeight(20)
		self.status_bar.setSizeGripEnabled(False)
		self.stat_info = QLabel()
		self.stat_info.setIndent(5)
		self.sort_main = QAction("Asc", self)
		sort_menu = QMenu()
		self.sort_main.setMenu(sort_menu)
		s_by_title = QAction("Title", sort_menu)
		s_by_artist = QAction("Artist", sort_menu)
		sort_menu.addAction(s_by_title)
		sort_menu.addAction(s_by_artist)
		self.status_bar.addPermanentWidget(self.stat_info)
		#self.status_bar.addAction(self.sort_main)
		self.temp_msg = QLabel()
		self.temp_timer = QTimer()
		self.manga_list_view.series_model.ROWCOUNT_CHANGE.connect(self.stat_row_info)
		self.manga_list_view.series_model.STATUSBAR_MSG.connect(self.stat_temp_msg)

	def stat_temp_msg(self, msg):
		self.temp_timer.stop()
		self.temp_msg.setText(msg)
		self.status_bar.addWidget(self.temp_msg)
		self.temp_timer.timeout.connect(self.temp_msg.clear)
		self.temp_timer.setSingleShot(True)
		self.temp_timer.start(5000)

	def stat_row_info(self):
		r = self.manga_list_view.series_model.rowCount()
		t = len(self.manga_list_view.series_model._data)
		self.stat_info.setText("<b>Showing {} of {} </b>".format(r, t))

	def manga_display(self):
		"initiates the manga view"
		self.manga_main = QWidget()
		self.manga_main.setContentsMargins(-10, -12, -10, -10)
		self.manga_view = QHBoxLayout()
		self.manga_main.setLayout(self.manga_view)

		manga_delegate = series.CustomDelegate()
		manga_delegate.BUTTON_CLICKED.connect(self.setCurrentIndex)
		self.manga_list_view = series.MangaView()
		self.manga_list_view.setItemDelegate(manga_delegate)
		self.manga_view.addWidget(self.manga_list_view)

	def favourite_display(self):
		"initiates favourite display"
		pass

	def chapter_display(self):
		"Initiates chapter view"
		self.chapter_main = QWidget()
		self.chapter_main.setObjectName("chapter_main") # to allow styling this object
		self.chapter_layout = QHBoxLayout()
		self.chapter_main.setLayout(self.chapter_layout)

		#self.chapter_info.setContentsMargins(-8,-7,-7,-7)
		#self.chapter_info.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
		self.chapter_info_view = series.ChapterInfo()
		self.chapter_layout.addWidget(self.chapter_info_view)

		chapter_list_view = series.ChapterView()
		self.chapter_layout.addWidget(chapter_list_view)
		#self.chapter.setCollapsible(0, True)
		#self.chapter.setCollapsible(1, False)

	def init_toolbar(self):
		self.toolbar = QToolBar()
		self.toolbar.setFixedHeight(30)
		self.toolbar.setWindowTitle("Show") # text for the contextmenu
		#self.toolbar.setStyleSheet("QToolBar {border:0px}") # make it user defined?
		self.toolbar.setMovable(False)
		self.toolbar.setFloatable(False)
		#self.toolbar.setIconSize(QSize(20,20))
		self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

		spacer_start = QWidget() # aligns the first actions properly
		spacer_start.setFixedSize(QSize(10, 1))
		self.toolbar.addWidget(spacer_start)

		favourite_view_icon = QIcon(gui_constants.STAR_BTN_PATH)
		favourite_view_action = QAction(favourite_view_icon, "Favourite", self)
		#favourite_view_action.setText("Manga View")
		favourite_view_action.triggered.connect(lambda: self.setCurrentIndex(1)) #need lambda to pass extra args
		self.toolbar.addAction(favourite_view_action)

		catalog_view_icon = QIcon(gui_constants.HOME_BTN_PATH)
		catalog_view_action = QAction(catalog_view_icon, "Library", self)
		#catalog_view_action.setText("Catalog")
		catalog_view_action.triggered.connect(lambda: self.setCurrentIndex(0)) #need lambda to pass extra args
		self.toolbar.addAction(catalog_view_action)
		self.toolbar.addSeparator()

		series_icon = QIcon(gui_constants.PLUS_PATH)
		series_action = QAction(series_icon, "Add series...", self)
		series_action.triggered.connect(self.manga_list_view.SERIES_DIALOG.emit)
		series_menu = QMenu()
		series_menu.addSeparator()
		populate_action = QAction("Populate from folder...", self)
		populate_action.triggered.connect(self.populate)
		series_menu.addAction(populate_action)
		series_action.setMenu(series_menu)
		self.toolbar.addAction(series_action)

		spacer_middle = QWidget() # aligns buttons to the right
		spacer_middle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
		self.toolbar.addWidget(spacer_middle)
		
		self.search_bar = QLineEdit()
		self.search_bar.setPlaceholderText("Search title, artist, genres")
		self.search_bar.setMaximumWidth(200)
		self.toolbar.addWidget(self.search_bar)
		self.toolbar.addSeparator()
		settings_icon = QIcon(gui_constants.SETTINGS_PATH)
		settings_action = QAction(settings_icon, "Set&tings", self)
		self.toolbar.addAction(settings_action)
		self.addToolBar(self.toolbar)
		
		spacer_end = QWidget() # aligns About action properly
		spacer_end.setFixedSize(QSize(10, 1))
		self.toolbar.addWidget(spacer_end)

	def setCurrentIndex(self, number, index=None):
		"""Changes the current display view.
		Params:
			number <- int (0 for manga view, 1 for chapter view
		Optional:
			index <- QModelIndex for chapter view
		Note: 0-based indexing
		"""
		if index is not None:
			self.chapter_info_view.display_manga(index)
			self.display.setCurrentIndex(number)
		else:
			self.display.setCurrentIndex(number)

	# TODO: Improve this so that it adds to the series dialog,
	# so user can edit data before inserting (make it a choice)
	def populate(self):
		"Populates the database with series from local drive'"
		msgbox = QMessageBox()
		msgbox.setText("<font color='red'><b>Use with care.</b></font> Choose a folder containing all your series'.")
		msgbox.setInformativeText("Oniichan, are you sure you want to do this?")
		msgbox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
		msgbox.setDefaultButton(QMessageBox.No)
		if msgbox.exec() == QMessageBox.Yes:
			path = QFileDialog.getExistingDirectory(None, "Choose a folder containing your series'")
			if len(path) is not 0:
				data_thread = QThread()
				loading_thread = QThread()
				loading = misc.Loading()

				if not loading.ON:
					misc.Loading.ON = True
					fetch_instance = fetch.Fetch()
					fetch_instance.series_path = path
					loading.show()

					def finished(status):
						if status:
							self.manga_list_view.series_model.populate_data()
							# TODO: make it spawn a dialog instead (from utils.py or misc.py)
							if loading.progress.maximum() == loading.progress.value():
								misc.Loading.ON = False
								loading.hide()
							data_thread.quit
						else:
							loading.setText("<font color=red>An error occured. Try restarting..</font>")
							loading.progress.setStyleSheet("background-color:red")
							data_thread.quit

					def fetch_deleteLater():
						try:
							fetch_instance.deleteLater
						except NameError:
							pass

					def thread_deleteLater(): #NOTE: Isn't this bad?
						data_thread.deleteLater

					def a_progress(prog):
						loading.progress.setValue(prog)
						loading.setText("Searching on local disk...\n(Will take a while on first time)")

					fetch_instance.moveToThread(data_thread)
					fetch_instance.DATA_COUNT.connect(loading.progress.setMaximum)
					fetch_instance.PROGRESS.connect(a_progress)
					data_thread.started.connect(fetch_instance.local)
					fetch_instance.FINISHED.connect(finished)
					fetch_instance.FINISHED.connect(fetch_deleteLater)
					fetch_instance.FINISHED.connect(thread_deleteLater)
					data_thread.start()
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)
Beispiel #52
0
class MusicPlayer(QMainWindow):
    """MusicPlayer houses all of elements that directly interact with the main window."""

    def __init__(self, parent=None):
        """Initialize the QMainWindow widget.

        The window title, window icon, and window size are initialized here as well
        as the following widgets: QMediaPlayer, QMediaPlaylist, QMediaContent, QMenuBar,
        QToolBar, QLabel, QPixmap, QSlider, QDockWidget, QListWidget, QWidget, and
        QVBoxLayout. The connect signals for relavant widgets are also initialized.
        """
        super(MusicPlayer, self).__init__(parent)
        self.setWindowTitle('Mosaic')

        window_icon = utilities.resource_filename('mosaic.images', 'icon.png')
        self.setWindowIcon(QIcon(window_icon))
        self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

        # Initiates Qt objects to be used by MusicPlayer
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.playlist_location = defaults.Settings().playlist_path
        self.content = QMediaContent()
        self.menu = self.menuBar()
        self.toolbar = QToolBar()
        self.art = QLabel()
        self.pixmap = QPixmap()
        self.slider = QSlider(Qt.Horizontal)
        self.duration_label = QLabel()
        self.playlist_dock = QDockWidget('Playlist', self)
        self.library_dock = QDockWidget('Media Library', self)
        self.playlist_view = QListWidget()
        self.library_view = library.MediaLibraryView()
        self.library_model = library.MediaLibraryModel()
        self.preferences = configuration.PreferencesDialog()
        self.widget = QWidget()
        self.layout = QVBoxLayout(self.widget)
        self.duration = 0
        self.playlist_dock_state = None
        self.library_dock_state = None

        # Sets QWidget() as the central widget of the main window
        self.setCentralWidget(self.widget)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.art.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        # Initiates the playlist dock widget and the library dock widget
        self.addDockWidget(defaults.Settings().dock_position, self.playlist_dock)
        self.playlist_dock.setWidget(self.playlist_view)
        self.playlist_dock.setVisible(defaults.Settings().playlist_on_start)
        self.playlist_dock.setFeatures(QDockWidget.DockWidgetClosable)

        self.addDockWidget(defaults.Settings().dock_position, self.library_dock)
        self.library_dock.setWidget(self.library_view)
        self.library_dock.setVisible(defaults.Settings().media_library_on_start)
        self.library_dock.setFeatures(QDockWidget.DockWidgetClosable)
        self.tabifyDockWidget(self.playlist_dock, self.library_dock)

        # Sets the range of the playback slider and sets the playback mode as looping
        self.slider.setRange(0, self.player.duration() / 1000)
        self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)

        # OSX system menu bar causes conflicts with PyQt5 menu bar
        if sys.platform == 'darwin':
            self.menu.setNativeMenuBar(False)

        # Initiates Settings in the defaults module to give access to settings.toml
        defaults.Settings()

        # Signals that connect to other methods when they're called
        self.player.metaDataChanged.connect(self.display_meta_data)
        self.slider.sliderMoved.connect(self.seek)
        self.player.durationChanged.connect(self.song_duration)
        self.player.positionChanged.connect(self.song_position)
        self.player.stateChanged.connect(self.set_state)
        self.playlist_view.itemActivated.connect(self.activate_playlist_item)
        self.library_view.activated.connect(self.open_media_library)
        self.playlist.currentIndexChanged.connect(self.change_index)
        self.playlist.mediaInserted.connect(self.initialize_playlist)
        self.playlist_dock.visibilityChanged.connect(self.dock_visiblity_change)
        self.library_dock.visibilityChanged.connect(self.dock_visiblity_change)
        self.preferences.dialog_media_library.media_library_line.textChanged.connect(self.change_media_library_path)
        self.preferences.dialog_view_options.dropdown_box.currentIndexChanged.connect(self.change_window_size)
        self.art.mousePressEvent = self.press_playback

        # Creating the menu controls, media controls, and window size of the music player
        self.menu_controls()
        self.media_controls()
        self.load_saved_playlist()

    def menu_controls(self):
        """Initiate the menu bar and add it to the QMainWindow widget."""
        self.file = self.menu.addMenu('File')
        self.edit = self.menu.addMenu('Edit')
        self.playback = self.menu.addMenu('Playback')
        self.view = self.menu.addMenu('View')
        self.help_ = self.menu.addMenu('Help')

        self.file_menu()
        self.edit_menu()
        self.playback_menu()
        self.view_menu()
        self.help_menu()

    def media_controls(self):
        """Create the bottom toolbar and controls used for media playback."""
        self.addToolBar(Qt.BottomToolBarArea, self.toolbar)
        self.toolbar.setMovable(False)

        play_icon = utilities.resource_filename('mosaic.images', 'md_play.png')
        self.play_action = QAction(QIcon(play_icon), 'Play', self)
        self.play_action.triggered.connect(self.player.play)

        stop_icon = utilities.resource_filename('mosaic.images', 'md_stop.png')
        self.stop_action = QAction(QIcon(stop_icon), 'Stop', self)
        self.stop_action.triggered.connect(self.player.stop)

        previous_icon = utilities.resource_filename('mosaic.images', 'md_previous.png')
        self.previous_action = QAction(QIcon(previous_icon), 'Previous', self)
        self.previous_action.triggered.connect(self.previous)

        next_icon = utilities.resource_filename('mosaic.images', 'md_next.png')
        self.next_action = QAction(QIcon(next_icon), 'Next', self)
        self.next_action.triggered.connect(self.playlist.next)

        repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png')
        self.repeat_action = QAction(QIcon(repeat_icon), 'Repeat', self)
        self.repeat_action.setShortcut('R')
        self.repeat_action.triggered.connect(self.repeat_song)

        self.toolbar.addAction(self.play_action)
        self.toolbar.addAction(self.stop_action)
        self.toolbar.addAction(self.previous_action)
        self.toolbar.addAction(self.next_action)
        self.toolbar.addAction(self.repeat_action)
        self.toolbar.addWidget(self.slider)
        self.toolbar.addWidget(self.duration_label)

    def file_menu(self):
        """Add a file menu to the menu bar.

        The file menu houses the Open File, Open Multiple Files, Open Playlist,
        Open Directory, and Exit Application menu items.
        """
        self.open_action = QAction('Open File', self)
        self.open_action.setShortcut('O')
        self.open_action.triggered.connect(self.open_file)

        self.open_multiple_files_action = QAction('Open Multiple Files', self)
        self.open_multiple_files_action.setShortcut('M')
        self.open_multiple_files_action.triggered.connect(self.open_multiple_files)

        self.open_playlist_action = QAction('Open Playlist', self)
        self.open_playlist_action.setShortcut('CTRL+P')
        self.open_playlist_action.triggered.connect(self.open_playlist)

        self.open_directory_action = QAction('Open Directory', self)
        self.open_directory_action.setShortcut('D')
        self.open_directory_action.triggered.connect(self.open_directory)

        self.save_playlist_action = QAction('Save Playlist', self)
        self.save_playlist_action.setShortcut('CTRL+S')
        self.save_playlist_action.triggered.connect(self.save_playlist)

        self.exit_action = QAction('Quit', self)
        self.exit_action.setShortcut('CTRL+Q')
        self.exit_action.triggered.connect(self.closeEvent)

        self.file.addAction(self.open_action)
        self.file.addAction(self.open_multiple_files_action)
        self.file.addAction(self.open_playlist_action)
        self.file.addAction(self.open_directory_action)
        self.file.addSeparator()
        self.file.addAction(self.save_playlist_action)
        self.file.addSeparator()
        self.file.addAction(self.exit_action)

    def edit_menu(self):
        """Add an edit menu to the menu bar.

        The edit menu houses the preferences item that opens a preferences dialog
        that allows the user to customize features of the music player.
        """
        self.preferences_action = QAction('Preferences', self)
        self.preferences_action.setShortcut('CTRL+SHIFT+P')
        self.preferences_action.triggered.connect(lambda: self.preferences.exec_())

        self.edit.addAction(self.preferences_action)

    def playback_menu(self):
        """Add a playback menu to the menu bar.

        The playback menu houses
        """
        self.play_playback_action = QAction('Play', self)
        self.play_playback_action.setShortcut('P')
        self.play_playback_action.triggered.connect(self.player.play)

        self.stop_playback_action = QAction('Stop', self)
        self.stop_playback_action.setShortcut('S')
        self.stop_playback_action.triggered.connect(self.player.stop)

        self.previous_playback_action = QAction('Previous', self)
        self.previous_playback_action.setShortcut('B')
        self.previous_playback_action.triggered.connect(self.previous)

        self.next_playback_action = QAction('Next', self)
        self.next_playback_action.setShortcut('N')
        self.next_playback_action.triggered.connect(self.playlist.next)

        self.playback.addAction(self.play_playback_action)
        self.playback.addAction(self.stop_playback_action)
        self.playback.addAction(self.previous_playback_action)
        self.playback.addAction(self.next_playback_action)

    def view_menu(self):
        """Add a view menu to the menu bar.

        The view menu houses the Playlist, Media Library, Minimalist View, and Media
        Information menu items. The Playlist item toggles the playlist dock into and
        out of view. The Media Library items toggles the media library dock into and
        out of view. The Minimalist View item resizes the window and shows only the
        menu bar and player controls. The Media Information item opens a dialog that
        shows information relevant to the currently playing song.
        """
        self.dock_action = self.playlist_dock.toggleViewAction()
        self.dock_action.setShortcut('CTRL+ALT+P')

        self.library_dock_action = self.library_dock.toggleViewAction()
        self.library_dock_action.setShortcut('CTRL+ALT+L')

        self.minimalist_view_action = QAction('Minimalist View', self)
        self.minimalist_view_action.setShortcut('CTRL+ALT+M')
        self.minimalist_view_action.setCheckable(True)
        self.minimalist_view_action.triggered.connect(self.minimalist_view)

        self.view_media_info_action = QAction('Media Information', self)
        self.view_media_info_action.setShortcut('CTRL+SHIFT+M')
        self.view_media_info_action.triggered.connect(self.media_information_dialog)

        self.view.addAction(self.dock_action)
        self.view.addAction(self.library_dock_action)
        self.view.addSeparator()
        self.view.addAction(self.minimalist_view_action)
        self.view.addSeparator()
        self.view.addAction(self.view_media_info_action)

    def help_menu(self):
        """Add a help menu to the menu bar.

        The help menu houses the about dialog that shows the user information
        related to the application.
        """
        self.about_action = QAction('About', self)
        self.about_action.setShortcut('H')
        self.about_action.triggered.connect(lambda: about.AboutDialog().exec_())

        self.help_.addAction(self.about_action)

    def open_file(self):
        """Open the selected file and add it to a new playlist."""
        filename, success = QFileDialog.getOpenFileName(self, 'Open File', '', 'Audio (*.mp3 *.flac)', '', QFileDialog.ReadOnly)

        if success:
            file_info = QFileInfo(filename).fileName()
            playlist_item = QListWidgetItem(file_info)
            self.playlist.clear()
            self.playlist_view.clear()
            self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(filename)))
            self.player.setPlaylist(self.playlist)
            playlist_item.setToolTip(file_info)
            self.playlist_view.addItem(playlist_item)
            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def open_multiple_files(self):
        """Open the selected files and add them to a new playlist."""
        filenames, success = QFileDialog.getOpenFileNames(self, 'Open Multiple Files', '', 'Audio (*.mp3 *.flac)', '', QFileDialog.ReadOnly)

        if success:
            self.playlist.clear()
            self.playlist_view.clear()
            for file in natsort.natsorted(filenames, alg=natsort.ns.PATH):
                file_info = QFileInfo(file).fileName()
                playlist_item = QListWidgetItem(file_info)
                self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file)))
                self.player.setPlaylist(self.playlist)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)
                self.playlist_view.setCurrentRow(0)
                self.player.play()

    def open_playlist(self):
        """Load an M3U or PLS file into a new playlist."""
        playlist, success = QFileDialog.getOpenFileName(self, 'Open Playlist', '', 'Playlist (*.m3u *.pls)', '', QFileDialog.ReadOnly)

        if success:
            playlist = QUrl.fromLocalFile(playlist)
            self.playlist.clear()
            self.playlist_view.clear()
            self.playlist.load(playlist)
            self.player.setPlaylist(self.playlist)

            for song_index in range(self.playlist.mediaCount()):
                file_info = self.playlist.media(song_index).canonicalUrl().fileName()
                playlist_item = QListWidgetItem(file_info)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)

            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def save_playlist(self):
        """Save the media in the playlist dock as a new M3U playlist."""
        playlist, success = QFileDialog.getSaveFileName(self, 'Save Playlist', '', 'Playlist (*.m3u)', '')
        if success:
            saved_playlist = "{}.m3u" .format(playlist)
            self.playlist.save(QUrl().fromLocalFile(saved_playlist), "m3u")

    def load_saved_playlist(self):
        """Load the saved playlist if user setting permits."""
        saved_playlist = "{}/.m3u" .format(self.playlist_location)
        if os.path.exists(saved_playlist):
            playlist = QUrl().fromLocalFile(saved_playlist)
            self.playlist.load(playlist)
            self.player.setPlaylist(self.playlist)

            for song_index in range(self.playlist.mediaCount()):
                file_info = self.playlist.media(song_index).canonicalUrl().fileName()
                playlist_item = QListWidgetItem(file_info)
                playlist_item.setToolTip(file_info)
                self.playlist_view.addItem(playlist_item)

            self.playlist_view.setCurrentRow(0)

    def open_directory(self):
        """Open the selected directory and add the files within to an empty playlist."""
        directory = QFileDialog.getExistingDirectory(self, 'Open Directory', '', QFileDialog.ReadOnly)

        if directory:
            self.playlist.clear()
            self.playlist_view.clear()
            for dirpath, __, files in os.walk(directory):
                for filename in natsort.natsorted(files, alg=natsort.ns.PATH):
                    file = os.path.join(dirpath, filename)
                    if filename.endswith(('mp3', 'flac')):
                        self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file)))
                        playlist_item = QListWidgetItem(filename)
                        playlist_item.setToolTip(filename)
                        self.playlist_view.addItem(playlist_item)

            self.player.setPlaylist(self.playlist)
            self.playlist_view.setCurrentRow(0)
            self.player.play()

    def open_media_library(self, index):
        """Open a directory or file from the media library into an empty playlist."""
        self.playlist.clear()
        self.playlist_view.clear()

        if self.library_model.fileName(index).endswith(('mp3', 'flac')):
            self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(self.library_model.filePath(index))))
            self.playlist_view.addItem(self.library_model.fileName(index))

        elif self.library_model.isDir(index):
            directory = self.library_model.filePath(index)
            for dirpath, __, files in os.walk(directory):
                for filename in natsort.natsorted(files, alg=natsort.ns.PATH):
                    file = os.path.join(dirpath, filename)
                    if filename.endswith(('mp3', 'flac')):
                        self.playlist.addMedia(QMediaContent(QUrl().fromLocalFile(file)))
                        playlist_item = QListWidgetItem(filename)
                        playlist_item.setToolTip(filename)
                        self.playlist_view.addItem(playlist_item)

        self.player.setPlaylist(self.playlist)
        self.player.play()

    def display_meta_data(self):
        """Display the current song's metadata in the main window.

        If the current song contains metadata, its cover art is extracted and shown in
        the main window while the track number, artist, album, and track title are shown
        in the window title.
        """
        if self.player.isMetaDataAvailable():
            file_path = self.player.currentMedia().canonicalUrl().toLocalFile()
            (album, artist, title, track_number, *__, artwork) = metadata.metadata(file_path)

            try:
                self.pixmap.loadFromData(artwork)
            except TypeError:
                self.pixmap = QPixmap(artwork)

            meta_data = '{} - {} - {} - {}' .format(track_number, artist, album, title)

            self.setWindowTitle(meta_data)
            self.art.setScaledContents(True)
            self.art.setPixmap(self.pixmap)
            self.layout.addWidget(self.art)

    def initialize_playlist(self, start):
        """Display playlist and reset playback mode when media inserted into playlist."""
        if start == 0:
            if self.library_dock.isVisible():
                self.playlist_dock.setVisible(True)
                self.playlist_dock.show()
                self.playlist_dock.raise_()

            if self.playlist.playbackMode() != QMediaPlaylist.Sequential:
                self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
                repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png')
                self.repeat_action.setIcon(QIcon(repeat_icon))

    def press_playback(self, event):
        """Change the playback of the player on cover art mouse event.

        When the cover art is clicked, the player will play the media if the player is
        either paused or stopped. If the media is playing, the media is set
        to pause.
        """
        if event.button() == 1 and configuration.Playback().cover_art_playback.isChecked():
            if (self.player.state() == QMediaPlayer.StoppedState or
                    self.player.state() == QMediaPlayer.PausedState):
                self.player.play()
            elif self.player.state() == QMediaPlayer.PlayingState:
                self.player.pause()

    def seek(self, seconds):
        """Set the position of the song to the position dragged to by the user."""
        self.player.setPosition(seconds * 1000)

    def song_duration(self, duration):
        """Set the slider to the duration of the currently played media."""
        duration /= 1000
        self.duration = duration
        self.slider.setMaximum(duration)

    def song_position(self, progress):
        """Move the horizontal slider in sync with the duration of the song.

        The progress is relayed to update_duration() in order
        to display the time label next to the slider.
        """
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

        self.update_duration(progress)

    def update_duration(self, current_duration):
        """Calculate the time played and the length of the song.

        Both of these times are sent to duration_label() in order to display the
        times on the toolbar.
        """
        duration = self.duration

        if current_duration or duration:
            time_played = QTime((current_duration / 3600) % 60, (current_duration / 60) % 60,
                                (current_duration % 60), (current_duration * 1000) % 1000)
            song_length = QTime((duration / 3600) % 60, (duration / 60) % 60, (duration % 60),
                                (duration * 1000) % 1000)

            if duration > 3600:
                time_format = "hh:mm:ss"
            else:
                time_format = "mm:ss"

            time_display = "{} / {}" .format(time_played.toString(time_format), song_length.toString(time_format))

        else:
            time_display = ""

        self.duration_label.setText(time_display)

    def set_state(self, state):
        """Change the icon in the toolbar in relation to the state of the player.

        The play icon changes to the pause icon when a song is playing and
        the pause icon changes back to the play icon when either paused or
        stopped.
        """
        if self.player.state() == QMediaPlayer.PlayingState:
            pause_icon = utilities.resource_filename('mosaic.images', 'md_pause.png')
            self.play_action.setIcon(QIcon(pause_icon))
            self.play_action.triggered.connect(self.player.pause)

        elif (self.player.state() == QMediaPlayer.PausedState or self.player.state() == QMediaPlayer.StoppedState):
            self.play_action.triggered.connect(self.player.play)
            play_icon = utilities.resource_filename('mosaic.images', 'md_play.png')
            self.play_action.setIcon(QIcon(play_icon))

    def previous(self):
        """Move to the previous song in the playlist.

        Moves to the previous song in the playlist if the current song is less
        than five seconds in. Otherwise, restarts the current song.
        """
        if self.player.position() <= 5000:
            self.playlist.previous()
        else:
            self.player.setPosition(0)

    def repeat_song(self):
        """Set the current media to repeat and change the repeat icon accordingly.

        There are four playback modes: repeat none, repeat all, repeat once, and shuffle.
        Clicking the repeat button cycles through each playback mode.
        """
        if self.playlist.playbackMode() == QMediaPlaylist.Sequential:
            self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
            repeat_on_icon = utilities.resource_filename('mosaic.images', 'md_repeat_all.png')
            self.repeat_action.setIcon(QIcon(repeat_on_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.Loop:
            self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
            repeat_on_icon = utilities.resource_filename('mosaic.images', 'md_repeat_once.png')
            self.repeat_action.setIcon(QIcon(repeat_on_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.CurrentItemInLoop:
            self.playlist.setPlaybackMode(QMediaPlaylist.Random)
            repeat_icon = utilities.resource_filename('mosaic.images', 'md_shuffle.png')
            self.repeat_action.setIcon(QIcon(repeat_icon))

        elif self.playlist.playbackMode() == QMediaPlaylist.Random:
            self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
            repeat_icon = utilities.resource_filename('mosaic.images', 'md_repeat_none.png')
            self.repeat_action.setIcon(QIcon(repeat_icon))

    def activate_playlist_item(self, item):
        """Set the active media to the playlist item dobule-clicked on by the user."""
        current_index = self.playlist_view.row(item)
        if self.playlist.currentIndex() != current_index:
            self.playlist.setCurrentIndex(current_index)

        if self.player.state() != QMediaPlayer.PlayingState:
            self.player.play()

    def change_index(self, row):
        """Highlight the row in the playlist of the active media."""
        self.playlist_view.setCurrentRow(row)

    def minimalist_view(self):
        """Resize the window to only show the menu bar and audio controls."""
        if self.minimalist_view_action.isChecked():

            if self.playlist_dock.isVisible():
                self.playlist_dock_state = True
            if self.library_dock.isVisible():
                self.library_dock_state = True

            self.library_dock.close()
            self.playlist_dock.close()

            QTimer.singleShot(10, lambda: self.resize(500, 0))

        else:
            self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

            if self.library_dock_state:
                self.library_dock.setVisible(True)

            if self.playlist_dock_state:
                self.playlist_dock.setVisible(True)

    def dock_visiblity_change(self, visible):
        """Change the size of the main window when the docks are toggled."""
        if visible and self.playlist_dock.isVisible() and not self.library_dock.isVisible():
            self.resize(defaults.Settings().window_size + self.playlist_dock.width() + 6,
                        self.height())

        elif visible and not self.playlist_dock.isVisible() and self.library_dock.isVisible():
            self.resize(defaults.Settings().window_size + self.library_dock.width() + 6,
                        self.height())

        elif visible and self.playlist_dock.isVisible() and self.library_dock.isVisible():
            self.resize(defaults.Settings().window_size + self.library_dock.width() + 6,
                        self.height())

        elif (not visible and not self.playlist_dock.isVisible() and not
                self.library_dock.isVisible()):
            self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

    def media_information_dialog(self):
        """Show a dialog of the current song's metadata."""
        if self.player.isMetaDataAvailable():
            file_path = self.player.currentMedia().canonicalUrl().toLocalFile()
        else:
            file_path = None
        dialog = information.InformationDialog(file_path)
        dialog.exec_()

    def change_window_size(self):
        """Change the window size of the music player."""
        self.playlist_dock.close()
        self.library_dock.close()
        self.resize(defaults.Settings().window_size, defaults.Settings().window_size + 63)

    def change_media_library_path(self, path):
        """Change the media library path to the new path selected in the preferences dialog."""
        self.library_model.setRootPath(path)
        self.library_view.setModel(self.library_model)
        self.library_view.setRootIndex(self.library_model.index(path))

    def closeEvent(self, event):
        """Override the PyQt close event in order to handle save playlist on close."""
        playlist = "{}/.m3u" .format(self.playlist_location)
        if defaults.Settings().save_playlist_on_close:
            self.playlist.save(QUrl().fromLocalFile(playlist), "m3u")
        else:
            if os.path.exists(playlist):
                os.remove(playlist)
        QApplication.quit()
Beispiel #53
0
class MainWindow(QMainWindow):

    def __init__(self):

        super(MainWindow, self).__init__()
        self.initUI()

    def initUI(self):

        self.setWindowTitle('Fanns - Finance Analysis Neural-Nets System')
        self.setMinimumSize(800, 600)
        self.initToolBar()
        self.initMenuBar()
        self.initMainBoard()

        self.show()

    def initMainBoard(self):

        self.mainBoard = QWidget()
        self.setCentralWidget(self.mainBoard)
        self.pagesStatus = [0]*5
        self.pages = [QWidget(self.mainBoard) for i in self.pagesStatus]

        self.mainBoard.setStyleSheet("padding:10px")

    def initToolBar(self):

        self.toolBar = QToolBar("Tools")
        self.toolBar.setMovable(False)
        self.addToolBar(Qt.LeftToolBarArea, self.toolBar)
        self.toolBar.setIconSize(QSize(20, 20))
        self.setStyleSheet(
            "QToolBar {" +
                "background-color: #a1afc9;" +
                "border-right: 1px solid #065279;" + 
                "padding: 5px}" +
            "QToolBar > QToolButton:hover {" +
                "background-color: #f0f0f4;" +
                "border-radius:3px}")

        configButton = QToolButton()
        configButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        configButton.setIcon(QIcon("Image/Icon/file.png"))
        configButton.setText("Configure")
        configButton.setFixedSize(120, 30)
        envAnaButton = QToolButton()
        envAnaButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        envAnaButton.setIcon(QIcon("Image/Icon/file.png"))
        envAnaButton.setText("Environment")
        envAnaButton.setFixedSize(120, 30)
        stoHisButton = QToolButton()
        stoHisButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        stoHisButton.setIcon(QIcon("Image/Icon/file.png"))
        stoHisButton.setText("Stock History")
        stoHisButton.setFixedSize(120, 30)
        stoAnaButton = QToolButton()
        stoAnaButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        stoAnaButton.setIcon(QIcon("Image/Icon/file.png"))
        stoAnaButton.setText("Stocks Analysis")
        stoAnaButton.setFixedSize(120, 30)
        autoTrButton = QToolButton()
        autoTrButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        autoTrButton.setIcon(QIcon("Image/Icon/file.png"))
        autoTrButton.setText("Auto Trading")
        autoTrButton.setFixedSize(120, 30)

        configButton.clicked.connect(self.configPage)
        envAnaButton.clicked.connect(self.envAnaPage)
        stoHisButton.clicked.connect(self.stoHisPage)
        stoAnaButton.clicked.connect(self.stoAnaPage)
        autoTrButton.clicked.connect(self.autoTrPage)

        self.toolBar.addWidget(configButton)
        self.toolBar.addWidget(envAnaButton)
        self.toolBar.addWidget(stoHisButton)
        self.toolBar.addWidget(stoAnaButton)
        self.toolBar.addWidget(autoTrButton)

    def initMenuBar(self):

        exitAction = QAction('&Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.triggered.connect(qApp.quit)

        launchAction = QAction('&Launch', self)
        launchAction.setShortcut('Ctrl+L')
        launchAction.triggered.connect(self.execute)

        menubar = self.menuBar()
        menubar.setNativeMenuBar(False)
        fannsMenu = menubar.addMenu('&App')
        fannsMenu.addAction(exitAction)
        editMenu = menubar.addMenu('&Func')
        editMenu.addAction(launchAction)

    def execute(self):

        print 'have a lunch!'

    def configPage(self):

        print "in config page"
        ci = 0
        page = self.pages[ci]

        if self.pagesStatus[ci] == 0:

            self.label = QLabel("This is configure page.", page)
            self.label.show()
            self.pagesStatus[ci] = 1

        for pi in range(0,len(self.pages)): self.pages[pi].hide()
        page.show()

    def envAnaPage(self):

        print "in environment page"
        ci = 1
        page = self.pages[ci]

        if self.pagesStatus[ci] == 0:

            self.label = QLabel("This is environment page.", page)
            self.label.show()
            self.pagesStatus[ci] = 1

        for pi in range(0,len(self.pages)): self.pages[pi].hide()
        page.show()

    def stoHisPage(self):

        print "in stock history page"
        ci = 2
        page = self.pages[ci]

        if self.pagesStatus[ci] == 0:

            self.label = QLabel("This is stock history page.", page)
            self.label.show()
            self.pagesStatus[ci] = 1

        for pi in range(0,len(self.pages)): self.pages[pi].hide()
        page.show()

    def stoAnaPage(self):

        print "in stock analysis page"
        ci = 3
        page = self.pages[ci]

        if self.pagesStatus[ci] == 0:

            self.label = QLabel("This is stock analysis page.", page)
            self.label.show()
            self.pagesStatus[ci] = 1

        for pi in range(0,len(self.pages)): self.pages[pi].hide()
        page.show()

    def autoTrPage(self):

        print "in auto trading page"
        ci = 4
        page = self.pages[ci]

        if self.pagesStatus[ci] == 0:

            self.label = QLabel("This is auto trading page.", page)
            self.label.show()
            self.pagesStatus[ci] = 1

        for pi in range(0,len(self.pages)): self.pages[pi].hide()
        page.show()
Beispiel #54
0
class MainWindow(QMainWindow):

    def __init__(self, autoTradingSystem):

        super(MainWindow, self).__init__()
        self.ATM = autoTradingSystem
        self.initUI()

    def initUI(self):

        self.setStyle()
        self.setWindowTitle('Auto Trading System')
        self.initToolBar()
        self.initMenuBar()
        self.initMainBoard()
        self.techAnPage()
        #self.pairTrPage()

        # make window in center point
        self.setFixedSize(1000, 700)
        qr = self.frameGeometry()
        qr.moveCenter(QDesktopWidget().availableGeometry().center())
        self.move(qr.topLeft())

        self.show()

    def initMainBoard(self):

        self.mainBoard = QWidget()
        self.setCentralWidget(self.mainBoard)
        self.pagesStatus = [0]*5
        self.pages = [QWidget(self.mainBoard) for i in self.pagesStatus]
        self.toolButtons

        self.mainBoard.setStyleSheet(self.mainBoardQSS)
        for page in self.pages: page.setStyleSheet(self.pagesQSS)

    def initToolBar(self):

        self.toolBar = QToolBar("Tools")
        self.toolBar.setMovable(False)
        self.addToolBar(Qt.LeftToolBarArea, self.toolBar)
        self.toolBar.setIconSize(QSize(20, 20))

        self.techAnButton = QToolButton()
        self.techAnButton.setText("Technical analysis")
        self.techAnButton.setFixedSize(130, 25)
        self.pairTrButton = QToolButton()
        self.pairTrButton.setText("Pair Trading")
        self.pairTrButton.setFixedSize(130, 25)
        self.atoTrdButton = QToolButton()
        self.atoTrdButton.setText("Monitor")
        self.atoTrdButton.setFixedSize(130, 25)
        self.trdPnlButton = QToolButton()
        self.trdPnlButton.setText("PnL Report")
        self.trdPnlButton.setFixedSize(130, 25)
        self.trdHisButton = QToolButton()
        self.trdHisButton.setText("Trade History")
        self.trdHisButton.setFixedSize(130, 25)

        self.techAnButton.clicked.connect(self.techAnPage)
        self.pairTrButton.clicked.connect(self.pairTrPage)
        self.atoTrdButton.clicked.connect(self.atoTrdPage)
        self.trdPnlButton.clicked.connect(self.trdPnlPage)
        self.trdHisButton.clicked.connect(self.trdHisPage)

        self.toolBar.addWidget(self.techAnButton)
        self.toolBar.addWidget(self.pairTrButton)
        self.toolBar.addWidget(self.atoTrdButton)
        self.toolBar.addWidget(self.trdPnlButton)
        self.toolBar.addWidget(self.trdHisButton)
        self.toolButtons = [self.techAnButton, self.pairTrButton, self.atoTrdButton, self.trdPnlButton, self.trdHisButton]

    def initMenuBar(self):

        exitAction = QAction('&Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.triggered.connect(qApp.quit)

        techAnAction = QAction('&Technical Analysis', self)
        techAnAction.setShortcut('Ctrl+T')
        techAnAction.triggered.connect(self.techAnPage)
        pairTrAction = QAction('&Pair Trading', self)
        pairTrAction.setShortcut('Ctrl+P')
        pairTrAction.triggered.connect(self.pairTrPage)
        atoTrdAction = QAction('&Monitor', self)
        atoTrdAction.setShortcut('Ctrl+M')
        atoTrdAction.triggered.connect(self.atoTrdPage)
        trdPnlAction = QAction('&Profit And Loss Report', self)
        trdPnlAction.setShortcut('Ctrl+R')
        trdPnlAction.triggered.connect(self.trdPnlPage)
        trdHisAction = QAction('&Trade History', self)
        trdHisAction.setShortcut('Ctrl+H')
        trdHisAction.triggered.connect(self.trdHisPage)

        menubar = self.menuBar()
        menubar.setNativeMenuBar(False)
        fannsMenu = menubar.addMenu('&App')
        fannsMenu.addAction(exitAction)
        naviMenu = menubar.addMenu('&Navigate')
        naviMenu.addAction(techAnAction)
        naviMenu.addAction(pairTrAction)
        naviMenu.addAction(atoTrdAction)
        naviMenu.addAction(trdPnlAction)
        naviMenu.addAction(trdHisAction)

    # The technical analysis page
    def techAnPage(self):

        # hide all pages to show self page
        for pi in range(0,len(self.pages)):
            self.toolButtons[pi].setStyleSheet(self.toolButtonHideQSS)
            self.pages[pi].hide()

        print "in technical analysis page"
        ci = 0
        page = self.pages[ci]
        self.toolButtons[ci].setStyleSheet(self.toolButtonFocusQSS)

        if self.pagesStatus[ci] == 0:

            self.pageTechAnConfigWidget = QWidget(page)
            self.pageTechAnConfigWidget.setFixedSize(860, 700)

            pageMainVerticalBox = QVBoxLayout()
            pageMainVerticalBox.setContentsMargins(0, 5, 0, 0)

            self.pageTechAnTitleLabel = QLabel("Technical Analysis", page)
            self.pageTechAnTitleLabel.setFixedSize(860, 25)
            self.pageTechAnTitleLabel.setStyleSheet(self.pageTitleQSS)
            pageMainVerticalBox.addWidget(self.pageTechAnTitleLabel)

            # capital config components
            self.pageTechAnCapitalLabel = QLabel("Capital Config", page)
            self.pageTechAnCapitalLabel.setFixedSize(860, 25)
            self.pageTechAnCapitalLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pageTechAnCapitalLabel)
            capitalHbox = QHBoxLayout()
            capitalHbox.setContentsMargins(30, 10, 0, 10)
            self.pageTechAnCapitalInputLabel = QLabel("Capital: ", page)
            self.pageTechAnCapitalInputLabel.setFont(self.contentFont)
            self.pageTechAnCapitalInputLabel.setFixedSize(100, 25)
            self.pageTechAnCapitalInputLabel.setStyleSheet(self.itemNameQSS)
            capitalHbox.addWidget(self.pageTechAnCapitalInputLabel)
            self.pageTechAnCapitalEdit = QLineEdit("$ 100,000,000")
            self.pageTechAnCapitalEdit.setStyleSheet(self.lineEditQSS)
            self.pageTechAnCapitalEdit.setFixedSize(300, 25)
            self.pageTechAnCapitalEdit.setEnabled(False)
            capitalHbox.addWidget(self.pageTechAnCapitalEdit)
            capitalHbox.addStretch(1)
            pageMainVerticalBox.addLayout(capitalHbox)

            # security code select components
            self.pageTechAnSecurityLabel = QLabel("Security Select", page)
            self.pageTechAnSecurityLabel.setFixedSize(860, 25)
            self.pageTechAnSecurityLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pageTechAnSecurityLabel)
            securityHbox = QHBoxLayout()
            securityHbox.setContentsMargins(30, 10, 0, 10)
            self.pageTechAnSecurityCode= QLabel("Security Code: ", page)
            self.pageTechAnSecurityCode.setFont(self.contentFont)
            self.pageTechAnSecurityCode.setFixedSize(100, 25)
            self.pageTechAnSecurityCode.setStyleSheet(self.itemNameQSS)
            securityHbox.addWidget(self.pageTechAnSecurityCode)
            self.pageTechAnSecurityCombo = QComboBox(page)
            self.pageTechAnSecurityCombo.setFixedSize(300, 25)
            self.pageTechAnSecurityCombo.setStyleSheet(self.comboQSS)
            self.pageTechAnSecurityCombo.addItem("hsi_futures_jan")
            for item in self.ATM.data.getAssetList("./dataManager/data/hsi_futures"): self.pageTechAnSecurityCombo.addItem(item)
            securityHbox.addWidget(self.pageTechAnSecurityCombo)
            securityHbox.addStretch(1)
            pageMainVerticalBox.addLayout(securityHbox)

            # investment strategies select components
            self.pageTechAnStrategiesLabel = QLabel("Investment Strategies Select", page)
            self.pageTechAnStrategiesLabel.setFixedSize(860, 25)
            self.pageTechAnStrategiesLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pageTechAnStrategiesLabel)
            self.pageTechAnStrategiesWidget = QWidget(page)
            self.pageTechAnStrategiesWidget.setFixedSize(700, 80)
            strategiesGrid = QGridLayout()
            strategiesGrid.setContentsMargins(30, 10, 0, 10)
            self.pageTechAnStrategyCheckBoxACOscillator = QCheckBox("  ACOscillator")
            self.pageTechAnStrategyCheckBoxCCICorrection= QCheckBox("  CCI Correction")
            self.pageTechAnStrategyCheckBoxDMRSIADX     = QCheckBox("  DM RSI ADX")
            self.pageTechAnStrategyCheckBoxMACD         = QCheckBox("  MACD")
            self.pageTechAnStrategyCheckBoxBreakoutsSwing=QCheckBox("  Breakouts Swing")
            self.pageTechAnStrategyCheckBoxOscillator313= QCheckBox("  Oscillator3 13")
            self.pageTechAnStrategyCheckBoxACOscillator.setChecked(False)
            self.pageTechAnStrategyCheckBoxCCICorrection.setChecked(False)
            self.pageTechAnStrategyCheckBoxDMRSIADX.setChecked(False)
            self.pageTechAnStrategyCheckBoxMACD.setChecked(True)
            self.pageTechAnStrategyCheckBoxBreakoutsSwing.setChecked(False)
            self.pageTechAnStrategyCheckBoxOscillator313.setChecked(False)
            strategiesGrid.addWidget(self.pageTechAnStrategyCheckBoxACOscillator, *(1, 1))
            strategiesGrid.addWidget(self.pageTechAnStrategyCheckBoxCCICorrection, *(1, 2))
            strategiesGrid.addWidget(self.pageTechAnStrategyCheckBoxDMRSIADX, *(1, 3))
            strategiesGrid.addWidget(self.pageTechAnStrategyCheckBoxMACD, *(2,1))
            strategiesGrid.addWidget(self.pageTechAnStrategyCheckBoxBreakoutsSwing, *(2,2))
            strategiesGrid.addWidget(self.pageTechAnStrategyCheckBoxOscillator313, *(2,3))
            self.pageTechAnStrategiesWidget.setLayout(strategiesGrid)
            pageMainVerticalBox.addWidget(self.pageTechAnStrategiesWidget)

            # trading time config components
            self.pageTechAnTimeSpanLabel = QLabel("Trading Time Config", page)
            self.pageTechAnTimeSpanLabel.setFixedSize(860, 25)
            self.pageTechAnTimeSpanLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pageTechAnTimeSpanLabel)
            timeVbox = QVBoxLayout()
            timeVbox.setContentsMargins(30, 10, 0, 10)
            startTimeHbox = QHBoxLayout()
            self.pageTechAnStartTimeName = QLabel("Start Time: ", page)
            self.pageTechAnStartTimeName.setFont(self.contentFont)
            self.pageTechAnStartTimeName.setFixedSize(100, 25)
            self.pageTechAnStartTimeName.setStyleSheet(self.itemNameQSS)
            startTimeHbox.addWidget(self.pageTechAnStartTimeName)
            self.pageTechAnStartTimeEdit = QLineEdit("2016-02-10 16:00:00")
            self.pageTechAnStartTimeEdit.setEnabled(False)
            self.pageTechAnStartTimeEdit.setStyleSheet(self.lineEditQSS)
            self.pageTechAnStartTimeEdit.setFixedSize(300, 25)
            startTimeHbox.addWidget(self.pageTechAnStartTimeEdit)
            startTimeHbox.addStretch(1)
            timeVbox.addLayout(startTimeHbox)
            endTimeHbox = QHBoxLayout()
            self.pageTechAnEndTimeName = QLabel("End Time: ", page)
            self.pageTechAnEndTimeName.setFont(self.contentFont)
            self.pageTechAnEndTimeName.setFixedSize(100, 25)
            self.pageTechAnEndTimeName.setStyleSheet(self.itemNameQSS)
            endTimeHbox.addWidget(self.pageTechAnEndTimeName)
            self.pageTechAnEndTimeEdit = QLineEdit("2016-02-26 16:00:00")
            self.pageTechAnEndTimeEdit.setEnabled(False)
            self.pageTechAnEndTimeEdit.setStyleSheet(self.lineEditQSS)
            self.pageTechAnEndTimeEdit.setFixedSize(300, 25)
            endTimeHbox.addWidget(self.pageTechAnEndTimeEdit)
            endTimeHbox.addStretch(1)
            timeVbox.addLayout(endTimeHbox)
            pageMainVerticalBox.addLayout(timeVbox)

            # trading strategies select components
            self.pageTechAnTStrSpanLabel = QLabel("Trading Strategies Select", page)
            self.pageTechAnTStrSpanLabel.setFixedSize(860, 25)
            self.pageTechAnTStrSpanLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pageTechAnTStrSpanLabel)
            self.pageTechAnTradeStrateWidget = QWidget(page)
            self.pageTechAnTradeStrateWidget.setFixedSize(700, 40)
            tradeStratGrid = QGridLayout()
            tradeStratGrid.setContentsMargins(30, 5, 0, 5)
            self.pageTechAnTStrRadioButtonVWAP = QRadioButton("  VWAP")
            self.pageTechAnTStrRadioButtonVWAP.setCheckable(False)
            self.pageTechAnTStrRadioButtonTWAP = QRadioButton("  TWAP")
            self.pageTechAnTStrRadioButtonTWAP.setChecked(True)
            self.pageTechAnTStrRadioButtonNONE = QRadioButton("  NONE")
            tradeStratGrid.addWidget(self.pageTechAnTStrRadioButtonVWAP, *(1, 1))
            tradeStratGrid.addWidget(self.pageTechAnTStrRadioButtonTWAP, *(1, 2))
            tradeStratGrid.addWidget(self.pageTechAnTStrRadioButtonNONE, *(1, 3))
            tradeStratGrid.addWidget(QLabel(), *(1, 4))
            tradeStratGrid.addWidget(QLabel(), *(1, 5))
            self.pageTechAnTradeStrateWidget.setLayout(tradeStratGrid)
            pageMainVerticalBox.addWidget(self.pageTechAnTradeStrateWidget)

            # position management method select components
            self.pageTechAnPManSpanLabel = QLabel("Position Management Method Select", page)
            self.pageTechAnPManSpanLabel.setFixedSize(860, 25)
            self.pageTechAnPManSpanLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pageTechAnPManSpanLabel)
            self.pageTechAnPManageMthdWidget = QWidget(page)
            self.pageTechAnPManageMthdWidget.setFixedSize(700, 40)
            pManageMtdGrid = QGridLayout()
            pManageMtdGrid.setContentsMargins(30, 10, 0, 10)
            self.pageTechAnPMtdRadioButtonFixedFraction = QRadioButton("  Fixed Fraction")
            self.pageTechAnPMtdRadioButtonFixedFraction.setChecked(True)
            self.pageTechAnPMtdRadioButtonMaximDrawDown = QRadioButton("  Max Draw Down")
            pManageMtdGrid.addWidget(self.pageTechAnPMtdRadioButtonFixedFraction, *(1, 1))
            pManageMtdGrid.addWidget(self.pageTechAnPMtdRadioButtonMaximDrawDown, *(1, 2))
            pManageMtdGrid.addWidget(QLabel(), *(1, 3))
            pManageMtdGrid.addWidget(QLabel(), *(1, 4))
            pManageMtdGrid.addWidget(QLabel(), *(1, 5))
            self.pageTechAnPManageMthdWidget.setLayout(pManageMtdGrid)
            pageMainVerticalBox.addWidget(self.pageTechAnPManageMthdWidget)

            space = QWidget()
            space.setFixedSize(0, 0)
            pageMainVerticalBox.addWidget(space)

            self.pageTechAnLaunchButton = QPushButton("Launch")
            self.pageTechAnLaunchButton.setFont(self.contentFont)
            self.pageTechAnLaunchButton.setFixedSize(860, 40)
            self.pageTechAnLaunchButton.setStyleSheet(self.launchWdgtReadyQSS)
            self.pageTechAnLaunchButton.clicked.connect(self.pageTechAnLaunch)
            pageMainVerticalBox.addWidget(self.pageTechAnLaunchButton)

            page.setLayout(pageMainVerticalBox)

            self.pagesStatus[ci] = 1

        page.show()

    def pageTechAnLaunch(self):

        capital      = int("".join(re.split("\$| |,", self.pageTechAnCapitalEdit.text())))
        securityCode = self.pageTechAnSecurityCombo.currentText()

        investmentStrategies = []
        if self.pageTechAnStrategyCheckBoxACOscillator.isChecked()  : investmentStrategies.append("ACOscillator")
        if self.pageTechAnStrategyCheckBoxCCICorrection.isChecked() : investmentStrategies.append("CCI_Correction")
        if self.pageTechAnStrategyCheckBoxDMRSIADX.isChecked()      : investmentStrategies.append("DM_RSI_ADX")
        if self.pageTechAnStrategyCheckBoxMACD.isChecked()          : investmentStrategies.append("MACD")
        if self.pageTechAnStrategyCheckBoxBreakoutsSwing.isChecked(): investmentStrategies.append("breakouts_swing")
        if self.pageTechAnStrategyCheckBoxOscillator313.isChecked() : investmentStrategies.append("oscillator3_13")

        startTime = self.pageTechAnStartTimeEdit.text()
        endTime   = self.pageTechAnEndTimeEdit.text()

        tradeStrategy = None
        if self.pageTechAnTStrRadioButtonVWAP.isChecked()   : tradeStrategy = "VWAP"
        if self.pageTechAnTStrRadioButtonTWAP.isChecked()   : tradeStrategy = "TWAP"
        # if self.pageTechAnTStrRadioButtonPOV.isChecked()    : tradeStrategy = "POV"
        # if self.pageTechAnTStrRadioButtonSimple.isChecked() : tradeStrategy = "Simple"
        if self.pageTechAnTStrRadioButtonNONE.isChecked()   : tradeStrategy = "Default"

        positionManagement = None
        if self.pageTechAnPMtdRadioButtonFixedFraction.isChecked()  : positionManagement = "FixedFraction"
        if self.pageTechAnPMtdRadioButtonMaximDrawDown.isChecked()  : positionManagement = "MaximumDrawDown"

        thread.start_new_thread(self.ATM.launchTechnicalAnalysis, (capital, securityCode, investmentStrategies, startTime, endTime, tradeStrategy, positionManagement))

    def pageTechAnLaunchProcess(self):
        self.pageTechAnLaunchButton.setStyleSheet(self.launchWdgtProcesQSS)
        self.pageTechAnLaunchButton.setText("Processing")

    def pageTechAnLaunchFinish(self):
        self.pageTechAnLaunchButton.setStyleSheet(self.launchWdgtReadyQSS)
        self.pageTechAnLaunchButton.setText("Re-Launch")

    # The pair trading page
    def pairTrPage(self):

        # hide all pages to show self page
        for pi in range(0, len(self.pages)):
            self.toolButtons[pi].setStyleSheet(self.toolButtonHideQSS)
            self.pages[pi].hide()

        print "in pair trading page"
        ci = 1
        page = self.pages[ci]
        self.toolButtons[ci].setStyleSheet(self.toolButtonFocusQSS)

        if self.pagesStatus[ci] == 0:
            self.pagePairTrConfigWidget = QWidget(page)
            self.pagePairTrConfigWidget.setFixedSize(860, 700)

            pageMainVerticalBox = QVBoxLayout()
            pageMainVerticalBox.setContentsMargins(0, 5, 0, 0)

            self.pagePairTrTitleLabel = QLabel("Pair Trading")
            self.pagePairTrTitleLabel.setFixedSize(860, 25)
            self.pagePairTrTitleLabel.setStyleSheet(self.pageTitleQSS)
            pageMainVerticalBox.addWidget(self.pagePairTrTitleLabel)

            self.pagePairTrCapitalLabel = QLabel("Capital Config", page)
            self.pagePairTrCapitalLabel.setFixedSize(860, 25)
            self.pagePairTrCapitalLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pagePairTrCapitalLabel)
            capitalHbox = QHBoxLayout()
            capitalHbox.setContentsMargins(30, 10, 0, 10)
            self.pagePairTrCapitalInputLabel = QLabel("Capital: ", page)
            self.pagePairTrCapitalInputLabel.setFont(self.contentFont)
            self.pagePairTrCapitalInputLabel.setFixedSize(100, 25)
            self.pagePairTrCapitalInputLabel.setStyleSheet(self.itemNameQSS)
            capitalHbox.addWidget(self.pagePairTrCapitalInputLabel)
            self.pagePairTrCapitalEdit = QLineEdit("$ 100,000,000")
            self.pagePairTrCapitalEdit.setStyleSheet(self.lineEditQSS)
            self.pagePairTrCapitalEdit.setFixedSize(300, 25)
            self.pagePairTrCapitalEdit.setEnabled(False)
            capitalHbox.addWidget(self.pagePairTrCapitalEdit)
            capitalHbox.addStretch(1)
            pageMainVerticalBox.addLayout(capitalHbox)

            self.pagePairTrSecurityLabel = QLabel("Security Select", page)
            self.pagePairTrSecurityLabel.setFixedSize(860, 25)
            self.pagePairTrSecurityLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pagePairTrSecurityLabel)
            securityHbox = QHBoxLayout()
            securityHbox.setContentsMargins(30, 10, 0, 10)
            self.pagePairTrSecurityCode = QLabel("Security Basket: ", page)
            self.pagePairTrSecurityCode.setFont(self.contentFont)
            self.pagePairTrSecurityCode.setFixedSize(100, 25)
            self.pagePairTrSecurityCode.setStyleSheet(self.itemNameQSS)
            securityHbox.addWidget(self.pagePairTrSecurityCode)
            self.pagePairTrSecurities = QTextEdit(page)
            self.pagePairTrSecurities.setEnabled(False)
            self.pagePairTrSecurities.setFixedSize(600, 148)
            securities = ""
            for item in self.ATM.data.getAssetList("./dataManager/data/hsi_stocks"): securities += item + '   '
            self.pagePairTrSecurities.setText(securities)
            securityHbox.addWidget(self.pagePairTrSecurities)
            securityHbox.addStretch(1)
            pageMainVerticalBox.addLayout(securityHbox)

            self.pagePairTrTimeSpanLabel = QLabel("Trading Time Config", page)
            self.pagePairTrTimeSpanLabel.setFixedSize(860, 25)
            self.pagePairTrTimeSpanLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pagePairTrTimeSpanLabel)
            timeVbox = QVBoxLayout()
            timeVbox.setContentsMargins(30, 10, 0, 10)
            startTimeHbox = QHBoxLayout()
            self.pagePairTrStartTimeName = QLabel("Start Time: ", page)
            self.pagePairTrStartTimeName.setFont(self.contentFont)
            self.pagePairTrStartTimeName.setFixedSize(100, 25)
            self.pagePairTrStartTimeName.setStyleSheet(self.itemNameQSS)
            startTimeHbox.addWidget(self.pagePairTrStartTimeName)
            self.pagePairTrStartTimeEdit = QLineEdit("2016-02-10 16:00:00")
            self.pagePairTrStartTimeEdit.setEnabled(False)
            self.pagePairTrStartTimeEdit.setStyleSheet(self.lineEditQSS)
            self.pagePairTrStartTimeEdit.setFixedSize(300, 25)
            startTimeHbox.addWidget(self.pagePairTrStartTimeEdit)
            startTimeHbox.addStretch(1)
            timeVbox.addLayout(startTimeHbox)
            endTimeHbox = QHBoxLayout()
            self.pagePairTrEndTimeName = QLabel("End Time: ", page)
            self.pagePairTrEndTimeName.setFont(self.contentFont)
            self.pagePairTrEndTimeName.setFixedSize(100, 25)
            self.pagePairTrEndTimeName.setStyleSheet(self.itemNameQSS)
            endTimeHbox.addWidget(self.pagePairTrEndTimeName)
            self.pagePairTrEndTimeEdit = QLineEdit("2016-02-26 16:00:00")
            self.pagePairTrEndTimeEdit.setEnabled(False)
            self.pagePairTrEndTimeEdit.setStyleSheet(self.lineEditQSS)
            self.pagePairTrEndTimeEdit.setFixedSize(300, 25)
            endTimeHbox.addWidget(self.pagePairTrEndTimeEdit)
            endTimeHbox.addStretch(1)
            timeVbox.addLayout(endTimeHbox)
            pageMainVerticalBox.addLayout(timeVbox)

            self.pagePairTrTStrSpanLabel = QLabel("Trading Strategies Select", page)
            self.pagePairTrTStrSpanLabel.setFixedSize(860, 25)
            self.pagePairTrTStrSpanLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pagePairTrTStrSpanLabel)
            self.pagePairTrTradeStrateWidget = QWidget(page)
            self.pagePairTrTradeStrateWidget.setFixedSize(700, 40)
            tradeStratGrid = QGridLayout()
            tradeStratGrid.setContentsMargins(30, 5, 0, 5)
            self.pagePairTrTStrRadioButtonVWAP = QRadioButton("  VWAP")
            self.pagePairTrTStrRadioButtonVWAP.setCheckable(False)
            self.pagePairTrTStrRadioButtonTWAP = QRadioButton("  TWAP")
            self.pagePairTrTStrRadioButtonTWAP.setChecked(True)
            self.pagePairTrTStrRadioButtonNONE = QRadioButton("  NONE")
            tradeStratGrid.addWidget(self.pagePairTrTStrRadioButtonVWAP, *(1, 1))
            tradeStratGrid.addWidget(self.pagePairTrTStrRadioButtonTWAP, *(1, 2))
            tradeStratGrid.addWidget(self.pagePairTrTStrRadioButtonNONE, *(1, 3))
            tradeStratGrid.addWidget(QLabel(), *(1, 4))
            tradeStratGrid.addWidget(QLabel(), *(1, 5))
            self.pagePairTrTradeStrateWidget.setLayout(tradeStratGrid)
            pageMainVerticalBox.addWidget(self.pagePairTrTradeStrateWidget)

            self.pagePairTrPManSpanLabel = QLabel("Position Management Method Select", page)
            self.pagePairTrPManSpanLabel.setFixedSize(860, 25)
            self.pagePairTrPManSpanLabel.setStyleSheet(self.pageSubTitleQSS)
            pageMainVerticalBox.addWidget(self.pagePairTrPManSpanLabel)
            self.pagePairTrPManageMthdWidget = QWidget(page)
            self.pagePairTrPManageMthdWidget.setFixedSize(700, 40)
            pManageMtdGrid = QGridLayout()
            pManageMtdGrid.setContentsMargins(30, 10, 0, 10)
            self.pagePairTrPMtdRadioButtonFixedFraction = QRadioButton("  Fixed Fraction")
            self.pagePairTrPMtdRadioButtonFixedFraction.setChecked(True)
            self.pagePairTrPMtdRadioButtonMaximDrawDown = QRadioButton("  Max Draw Down")
            pManageMtdGrid.addWidget(self.pagePairTrPMtdRadioButtonFixedFraction, *(1, 1))
            pManageMtdGrid.addWidget(self.pagePairTrPMtdRadioButtonMaximDrawDown, *(1, 2))
            pManageMtdGrid.addWidget(QLabel(), *(1, 3))
            pManageMtdGrid.addWidget(QLabel(), *(1, 4))
            pManageMtdGrid.addWidget(QLabel(), *(1, 5))
            self.pagePairTrPManageMthdWidget.setLayout(pManageMtdGrid)
            pageMainVerticalBox.addWidget(self.pagePairTrPManageMthdWidget)

            space = QWidget()
            space.setFixedSize(0, 0)
            pageMainVerticalBox.addWidget(space)

            self.pagePairTrLaunchButton = QPushButton("Launch")
            self.pagePairTrLaunchButton.setFont(self.contentFont)
            self.pagePairTrLaunchButton.setFixedSize(860, 40)
            self.pagePairTrLaunchButton.setStyleSheet(self.launchWdgtReadyQSS)
            self.pagePairTrLaunchButton.clicked.connect(self.pagePairTrdLaunch)
            pageMainVerticalBox.addWidget(self.pagePairTrLaunchButton)

            page.setLayout(pageMainVerticalBox)

            self.pagesStatus[ci] = 1

        page.show()

    def pagePairTrdLaunch(self):

        capital = int("".join(re.split("\$| |,", self.pagePairTrCapitalEdit.text())))

        investmentStrategies = ["pairstrading", ]

        startTime = self.pagePairTrStartTimeEdit.text()
        endTime = self.pagePairTrEndTimeEdit.text()

        tradeStrategy = None
        if self.pagePairTrTStrRadioButtonVWAP.isChecked(): tradeStrategy = "VWAP"
        if self.pagePairTrTStrRadioButtonTWAP.isChecked(): tradeStrategy = "TWAP"
        if self.pagePairTrTStrRadioButtonNONE.isChecked(): tradeStrategy = "Default"

        positionManagement = None
        if self.pagePairTrPMtdRadioButtonFixedFraction.isChecked(): positionManagement = "FixedFraction"
        if self.pagePairTrPMtdRadioButtonMaximDrawDown.isChecked(): positionManagement = "MaximumDrawDown"

        thread.start_new_thread(self.ATM.launchPairTradingAnalysis, (capital, investmentStrategies, startTime, endTime, tradeStrategy, positionManagement))

    def pagePairTrdLaunchProcess(self):
        self.pagePairTrLaunchButton.setStyleSheet(self.launchWdgtProcesQSS)
        self.pagePairTrLaunchButton.setText("Processing")

    def pagePairTrdLaunchFinish(self):
        self.pagePairTrLaunchButton.setStyleSheet(self.launchWdgtReadyQSS)
        self.pagePairTrLaunchButton.setText("Re-Launch")

    def atoTrdPage(self):

        for pi in range(0,len(self.pages)):
            self.toolButtons[pi].setStyleSheet(self.toolButtonHideQSS)
            self.pages[pi].hide()

        print "in monitor page"
        ci = 2
        page = self.pages[ci]
        self.toolButtons[ci].setStyleSheet(self.toolButtonFocusQSS)

        if self.pagesStatus[ci] == 0:

            if not page.layout() == None:
                while page.layout().count() > 0:
                    page.layout().takeAt(0).widget().setParent(None)

            if page.layout() == None:
                self.pageAutoTrdPageMainVerticalBox = QVBoxLayout()
                self.pageAutoTrdPageMainVerticalBox.setContentsMargins(0, 5, 0, 0)
                page.setLayout(self.pageAutoTrdPageMainVerticalBox)

            self.pageAutoTrdTitleLabel = QLabel("Monitor", page)
            self.pageAutoTrdTitleLabel.setFixedSize(860, 25)
            self.pageAutoTrdTitleLabel.setStyleSheet(self.pageTitleQSS)
            self.pageAutoTrdPageMainVerticalBox.addWidget(self.pageAutoTrdTitleLabel)

            pnlReport = self.ATM.report
            if not len(self.ATM.strategies.strategiesPool.keys()) == 0:
                self.pageAtoTrdPageScroll = QScrollArea(page)
                self.pageAtoTrdPageScroll.setWidgetResizable(True)
                self.pageAtoTrdPageScroll.setBackgroundRole(QPalette.NoRole)
                self.pageAtoTrdPageScroll.setStyleSheet("background: transparent")
                self.pageAtoTrdPageScroll.setFixedSize(860, 635)
                self.pageAtoTrdScrollContentsWidget = QWidget(page)
                scrollContentVBox = QVBoxLayout()
                scrollContentVBox.setAlignment(Qt.AlignTop)
                scrollContentVBox.setContentsMargins(0, 0, 0, 0)

                self.pageAtoTrdSignalPlotLabel = QLabel("Signals Plots", page)
                self.pageAtoTrdSignalPlotLabel.setFixedSize(860, 25)
                self.pageAtoTrdSignalPlotLabel.setStyleSheet(self.pageSubTitleQSS)
                scrollContentVBox.addWidget(self.pageAtoTrdSignalPlotLabel)

                path = "./strategies/image/"
                for file in os.listdir(path):
                    if file.endswith(".png") and file.split('.')[0] in self.ATM.strategies.strategiesPool.keys():
                        pageAtoTrdSignalPlotStrategyLabel = QLabel(file.split('.')[0], page)
                        pageAtoTrdSignalPlotStrategyLabel.setFixedSize(860, 25)
                        pageAtoTrdSignalPlotStrategyLabel.setStyleSheet(self.pageSubSubTitleQSS)
                        scrollContentVBox.addWidget(pageAtoTrdSignalPlotStrategyLabel)

                        widget = QWidget()
                        widget.setFixedHeight(300)
                        hbox = QHBoxLayout()
                        hbox.setContentsMargins(0, 0, 0, 0)
                        hbox.setAlignment(Qt.AlignCenter)
                        lbl = QLabel()
                        pixmap = QPixmap(path + file)
                        scaled_pixmap = pixmap.scaled(860, 330, Qt.KeepAspectRatio)
                        lbl.setPixmap(scaled_pixmap)
                        hbox.addWidget(lbl)
                        widget.setLayout(hbox)
                        scrollContentVBox.addWidget(widget)

                self.pageAtoTrdAllSignalsLabel = QLabel("All Signals", page)
                self.pageAtoTrdAllSignalsLabel.setFixedSize(860, 25)
                self.pageAtoTrdAllSignalsLabel.setStyleSheet(self.pageSubTitleQSS)
                scrollContentVBox.addWidget(self.pageAtoTrdAllSignalsLabel)

                self.pageAtoTrdAllSignalsTitle = QWidget(page)
                self.pageAtoTrdAllSignalsTitle.setFixedSize(860, 25)
                self.pageAtoTrdAllSignalsTitle.setStyleSheet(self.pageSubSubTitleQSS)
                titlesHBox = QHBoxLayout()
                titlesHBox.setContentsMargins(10, 0, 20, 0)
                titlesHBox.addWidget(QLabel("Code"))
                titlesHBox.addWidget(QLabel("Time"))
                titlesHBox.addWidget(QLabel("Action"))
                titlesHBox.addWidget(QLabel("Qnt"))
                titlesHBox.addWidget(QLabel("Price"))
                titlesHBox.addWidget(QLabel("Volumn"))
                titlesHBox.addWidget(QLabel("Strategy"))
                self.pageAtoTrdAllSignalsTitle.setLayout(titlesHBox)
                scrollContentVBox.addWidget(self.pageAtoTrdAllSignalsTitle)

                signals = self.ATM.strategies.signals
                if not len(signals) == 0:
                    for i in xrange(len(signals)):
                        widget = QWidget(page)
                        widget.setFixedHeight(15)
                        widget.setStyleSheet("color:#ffffff")
                        signalHBox = QHBoxLayout()
                        signalHBox.setContentsMargins(20, 0, 10, 0)
                        signalHBox.addWidget(QLabel(signals.ix[i]["Code"]))
                        signalHBox.addWidget(QLabel(str(signals.ix[i]["Time"])))
                        signalHBox.addWidget(QLabel(signals.ix[i]["Action"]))
                        signalHBox.addWidget(QLabel(str(signals.ix[i]["Qnt"])))
                        signalHBox.addWidget(QLabel(str(signals.ix[i]["Price"])))
                        signalHBox.addWidget(QLabel(str(signals.ix[i]["Volume"])))
                        signalHBox.addWidget(QLabel(signals.ix[i]["Strategy"]))
                        widget.setLayout(signalHBox)
                        scrollContentVBox.addWidget(widget)

                else:
                    widget = QLabel("No Data.")
                    widget.setFixedSize(860, 550)
                    widget.setStyleSheet(self.noDataLabelQSS)
                    widget.setAlignment(Qt.AlignCenter)
                    scrollContentVBox.addWidget(widget)

                self.pageAtoTrdScrollContentsWidget.setLayout(scrollContentVBox)
                self.pageAtoTrdPageScroll.setWidget(self.pageAtoTrdScrollContentsWidget)
                self.pageAutoTrdPageMainVerticalBox.addWidget(self.pageAtoTrdPageScroll)

            else:
                widget = QLabel("No Data.")
                widget.setFixedSize(860, 550)
                widget.setStyleSheet(self.noDataLabelQSS)
                widget.setAlignment(Qt.AlignCenter)
                self.pageAutoTrdPageMainVerticalBox.addWidget(widget)

            self.pagesStatus[ci] = 1

        page.show()

    def trdPnlPage(self):

        for pi in range(0,len(self.pages)):
            self.toolButtons[pi].setStyleSheet(self.toolButtonHideQSS)
            self.pages[pi].hide()

        print "in profit and loss report page"
        ci = 3
        page = self.pages[ci]
        self.toolButtons[ci].setStyleSheet(self.toolButtonFocusQSS)

        if self.pagesStatus[ci] == 0:

            if not page.layout() == None:
                while page.layout().count() > 0:
                    page.layout().takeAt(0).widget().setParent(None)

            if page.layout() == None:
                self.pageTrdPnlPageMainVerticalBox = QVBoxLayout()
                self.pageTrdPnlPageMainVerticalBox.setContentsMargins(0, 5, 0, 0)
                page.setLayout(self.pageTrdPnlPageMainVerticalBox)

            self.pageTrdHisTitleLabel = QLabel("Profit And Loss Report", page)
            self.pageTrdHisTitleLabel.setFixedSize(860, 25)
            self.pageTrdHisTitleLabel.setStyleSheet(self.pageTitleQSS)
            self.pageTrdPnlPageMainVerticalBox.addWidget(self.pageTrdHisTitleLabel)

            pnlReport = self.ATM.report
            if not len(pnlReport) == 0:

                self.pageTrdHisBookTitles = QWidget(page)
                self.pageTrdHisBookTitles.setFixedSize(860, 25)
                self.pageTrdHisBookTitles.setStyleSheet(self.pageSubTitleQSS)
                titlesHBox = QHBoxLayout()
                titlesHBox.setContentsMargins(10, 0, 20, 0)
                strategy = QLabel("Strategy")
                titlesHBox.addWidget(QLabel("Strategy"))
                titlesHBox.addWidget(QLabel("Realized PnL"))
                titlesHBox.addWidget(QLabel("Return"))
                areturn = QLabel("Annual Return")
                areturn.setFixedWidth(130)
                titlesHBox.addWidget(areturn)
                titlesHBox.addWidget(QLabel("Volatility"))
                titlesHBox.addWidget(QLabel("Sharpe Ratio"))
                mdd = QLabel("Maximum Draw Down")
                mdd.setFixedWidth(155)
                titlesHBox.addWidget(mdd)
                self.pageTrdHisBookTitles.setLayout(titlesHBox)
                self.pageTrdPnlPageMainVerticalBox.addWidget(self.pageTrdHisBookTitles)


                self.pageTrdHisPageScroll = QScrollArea(page)
                self.pageTrdHisPageScroll.setWidgetResizable(True)
                self.pageTrdHisPageScroll.setBackgroundRole(QPalette.NoRole)
                self.pageTrdHisPageScroll.setStyleSheet("background: transparent")
                self.pageTrdHisPageScroll.setFixedSize(860, 600)
                self.pageTrdHisScrollContentsWidget = QWidget(page)
                scrollContentVBox = QVBoxLayout()
                scrollContentVBox.setAlignment(Qt.AlignTop)
                scrollContentVBox.setContentsMargins(0, 0, 0, 0)
                for i in xrange(0, len(pnlReport)):
                    widget = QWidget()
                    widget.setFixedHeight(15)
                    if pnlReport.ix[i]["realized PnL"] > 0: widget.setStyleSheet("color:#fa2020")
                    if pnlReport.ix[i]["realized PnL"] < 0: widget.setStyleSheet("color:#27AE60")
                    hbox   = QHBoxLayout()
                    hbox.setContentsMargins(20, 0, 10, 0)
                    strategy = QLabel(pnlReport.ix[i]["Strategy"])
                    strategy.setFixedWidth(100)
                    hbox.addWidget(strategy)
                    hbox.addWidget(QLabel(str("{0:.2f}".format(pnlReport.ix[i]["realized PnL"]))))
                    hbox.addWidget(QLabel(str("{0:.4f}".format(pnlReport.ix[i]["Return"]))))
                    areturn = QLabel(str("{0:.4f}".format(pnlReport.ix[i]["Annualized Return"])))
                    # hbox.addWidget(QLabel(str("{0:.2f}".format(tradeHistory.ix[i]["QntPer"] * 100))))
                    areturn.setFixedWidth(130)
                    hbox.addWidget(areturn)
                    hbox.addWidget(QLabel(str("{0:.4f}".format(pnlReport.ix[i]["Volatility"]))))
                    hbox.addWidget(QLabel(str("{0:.4f}".format(pnlReport.ix[i]["Sharpe Ratio"]))))
                    mdd = QLabel(str("{0:.6f}".format(pnlReport.ix[i]["MDD"])))
                    mdd.setFixedWidth(155)
                    hbox.addWidget(mdd)
                    widget.setLayout(hbox)
                    scrollContentVBox.addWidget(widget)
                self.pageTrdHisScrollContentsWidget.setLayout(scrollContentVBox)
                self.pageTrdHisPageScroll.setWidget(self.pageTrdHisScrollContentsWidget)
                self.pageTrdPnlPageMainVerticalBox.addWidget(self.pageTrdHisPageScroll)

            else:
                widget = QLabel("No Data.")
                widget.setFixedSize(860, 550)
                widget.setStyleSheet(self.noDataLabelQSS)
                widget.setAlignment(Qt.AlignCenter)
                self.pageTrdPnlPageMainVerticalBox.addWidget(widget)

            self.pagesStatus[ci] = 1

        page.show()

    def trdHisPage(self):

        for pi in range(0,len(self.pages)):
            self.toolButtons[pi].setStyleSheet(self.toolButtonHideQSS)
            self.pages[pi].hide()

        print "in trade history page"
        ci = 4
        page = self.pages[ci]
        self.toolButtons[ci].setStyleSheet(self.toolButtonFocusQSS)

        if self.pagesStatus[ci] == 0:

            if not page.layout() == None:
                while page.layout().count() > 0:
                    page.layout().takeAt(0).widget().setParent(None)

            if page.layout() == None:
                self.pageTrdHisPageMainVerticalBox = QVBoxLayout()
                self.pageTrdHisPageMainVerticalBox.setContentsMargins(0, 5, 0, 0)
                page.setLayout(self.pageTrdHisPageMainVerticalBox)

            self.pageTrdHisTitleLabel = QLabel("Trade History", page)
            self.pageTrdHisTitleLabel.setFixedSize(860, 25)
            self.pageTrdHisTitleLabel.setStyleSheet(self.pageTitleQSS)
            self.pageTrdHisPageMainVerticalBox.addWidget(self.pageTrdHisTitleLabel)

            tradeHistory = self.ATM.account.queryTradeHistory()

            if not len(tradeHistory) == 0:
                self.pageTrdHisBookTitles = QWidget(page)
                self.pageTrdHisBookTitles.setFixedSize(860, 25)
                self.pageTrdHisBookTitles.setStyleSheet(self.pageSubTitleQSS)
                titlesHBox = QHBoxLayout()
                titlesHBox.setContentsMargins(10, 0, 20, 0)
                code = QLabel("Code")
                code.setFixedWidth(100)
                titlesHBox.addWidget(code)
                time = QLabel("Time")
                time.setFixedWidth(145)
                titlesHBox.addWidget(time)
                titlesHBox.addWidget(QLabel("Action"))
                qnt = QLabel("Qnt")
                qnt.setFixedWidth(50)
                titlesHBox.addWidget(qnt)
                titlesHBox.addWidget(QLabel("Occupy"))
                titlesHBox.addWidget(QLabel("Price"))
                titlesHBox.addWidget(QLabel("PnL"))
                titlesHBox.addWidget(QLabel("Equity"))
                strategy = QLabel("Strategy")
                strategy.setFixedWidth(100)
                titlesHBox.addWidget(strategy)
                self.pageTrdHisBookTitles.setLayout(titlesHBox)
                self.pageTrdHisPageMainVerticalBox.addWidget(self.pageTrdHisBookTitles)

                self.pageTrdHisPageScroll = QScrollArea(page)
                self.pageTrdHisPageScroll.setWidgetResizable(True)
                self.pageTrdHisPageScroll.setBackgroundRole(QPalette.NoRole)
                self.pageTrdHisPageScroll.setStyleSheet("background: transparent")
                self.pageTrdHisPageScroll.setFixedSize(860, 600)
                self.pageTrdHisScrollContentsWidget = QWidget(page)
                scrollContentVBox = QVBoxLayout()
                scrollContentVBox.setContentsMargins(0, 0, 0, 0)
                scrollContentVBox.setAlignment(Qt.AlignTop)
                for i in xrange(0, len(tradeHistory)):
                    widget = QWidget()
                    widget.setFixedHeight(15)
                    if tradeHistory.ix[i]["Action"] == "Short" : widget.setStyleSheet("color:#27AE60")
                    if tradeHistory.ix[i]["Action"] == "SellToCover"  : widget.setStyleSheet("color:#27AE60")
                    if tradeHistory.ix[i]["Action"] == "Long" : widget.setStyleSheet("color:#fa2020")
                    if tradeHistory.ix[i]["Action"] == "BuyToCover" : widget.setStyleSheet("color:#fa2020")
                    hbox   = QHBoxLayout()
                    hbox.setContentsMargins(20, 0, 10, 0)
                    code = QLabel(str(tradeHistory.ix[i]["Code"])); code.setFixedWidth(100); hbox.addWidget(code);
                    time = QLabel(str(tradeHistory.ix[i]["Time"])); time.setFixedWidth(145); hbox.addWidget(time);
                    hbox.addWidget(QLabel(tradeHistory.ix[i]["Action"]))
                    qnt = QLabel(str(tradeHistory.ix[i]["Qnt"])); qnt.setFixedWidth(50); hbox.addWidget(qnt);
                    hbox.addWidget(QLabel(str("{0:.2f}".format(tradeHistory.ix[i]["QntPer"] * 100))+"%"))
                    hbox.addWidget(QLabel(str(round(tradeHistory.ix[i]["Price"]))))
                    pnl = QLabel()
                    if not tradeHistory.ix[i]["PnL"] == "": pnl = QLabel(str(round(float(tradeHistory.ix[i]["PnL"]))));
                    hbox.addWidget(pnl)
                    hbox.addWidget(QLabel(str(round(tradeHistory.ix[i]["Equity"]))))
                    strategy = QLabel(tradeHistory.ix[i]["Strategy"]); strategy.setFixedWidth(100); hbox.addWidget(strategy);
                    widget.setLayout(hbox)
                    scrollContentVBox.addWidget(widget)
                self.pageTrdHisScrollContentsWidget.setLayout(scrollContentVBox)
                self.pageTrdHisPageScroll.setWidget(self.pageTrdHisScrollContentsWidget)
                self.pageTrdHisPageMainVerticalBox.addWidget(self.pageTrdHisPageScroll)

            else:
                widget = QLabel("No Data.")
                widget.setFixedSize(860, 550)
                widget.setStyleSheet(self.noDataLabelQSS)
                widget.setAlignment(Qt.AlignCenter)
                self.pageTrdHisPageMainVerticalBox.addWidget(widget)

            self.pagesStatus[ci] = 1

        page.show()

    def setStyle(self):

        self.setStyleSheet(
            "QToolBar {" +
                "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #203138, stop: 1.0 #000000);" +
                "border-right: 1px solid #065279;" +
                "padding: 5px}" +
            "QToolBar > QToolButton {" +
                "color: #ffffff;" +
                "font-family:'ArialRegular';" +
                "font-size: 14px}" +
            "QToolBar > QToolButton:hover {" +
                "background: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0, stop: 0 #ffcb06, stop: 1.0 #ff9c28);" +
                "border-radius:3px}" +
            "QLabel {" +
                "font-family:'ArialRegular';" +
                "padding: 10px;}" +
            "QPushButton {" +
                "height: 20px}" +
            "QComboBox {" +
                "border-radius: 1px; " +
                "border-top-right-radius:11px;" +
                "border-bottom-right-radius:11px;" +
                "font-family:'ArialRegular'}" +
            "QComboBox::drop-down {" +
                "width:15px;" +
                "background-color: #ff9c28;" +
                "border-top-right-radius:10px;" +
                "border-bottom-right-radius:10px;}" +
            "QCheckBox {" +
                "color: #ffffff;" +
                "font-family:'ArialRegular'}" +
            "QCheckBox::indicator {" +
                "background-color:#ffffff;" +
                "border-radius: 1px}" +
            "QCheckBox::indicator:checked {" +
                "background-color:#ff9c28}" +
            "QLineEdit {" +
                "background:#ff9c28;" +
                "border-radius:1px}" +
            "QLineEdit:focus {" +
                "border-radius:1px;}" +
            "QRadioButton {color: #ffffff}" +
            "QScrollArea {border:0px; background:transparent}" +
            "QTextEdit {padding-left: 5px; border: 0px; font-family: 'ArialRegular'; font-weight:20; font-size:14px; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ec2f4b, stop: 1.0 #85030f);}"
        )

        self.mainBoardQSS       = "padding:0px; background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #203138, stop: 1.0 #000000);"
        self.pagesQSS           = "background:none; padding: 0px"
        self.pageTitleQSS       = "padding-left:5px; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ec2f4b, stop: 1.0 #85030f); color: #ffffff; font-family: 'ArialRegular'; font-weight:20; font-size: 16px"
        self.pageSubTitleQSS    = "padding-left:5px; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #495d76, stop: 1.0 #1f4e7c); color: #dddddd; font-family: 'ArialRegular'; font-weight:20; font-size: 14px"
        self.pageSubSubTitleQSS = "padding-left:5px; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #646464, stop: 1.0 #838683); color: #dddddd; font-family: 'ArialRegular'; font-weight:20; font-size: 14px"
        self.toolButtonHideQSS  = "background:none; font-size: 14px; font-family:'ArialRegular'"
        self.toolButtonFocusQSS = "background:qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0, stop: 0 #ffcb06, stop: 1.0 #ff9c28);border-radius:3px; color:#000000"
        self.itemNameQSS        = "color: #ffffff; font-family: 'ArialRegular'"
        self.comboQSS           = "padding-left:5px;background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #eeeeee, stop: 1.0 #dddddd);"
        self.lineEditQSS        = "background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #eeeeee, stop: 1.0 #dddddd);border: 0px; padding-left:5px; font-family:'ArialRegular'; font-weight:20; font-size: 14px"
        self.launchWdgtReadyQSS = "background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #004900, stop: 1.0 #033502);border: 0px; color:#ffffff"
        self.launchWdgtProcesQSS= "background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #006602, stop: 1.0 #007b03);border: 0px; color:#ffffff"
        self.tableTitleQSS      = "padding-left:5px; background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #495d76, stop: 1.0 #1f4e7c); color: #dddddd; font-family: 'ArialRegular'; font-weight:20; font-size: 14px"
        self.noDataLabelQSS     = "color: #ffffff; font-family: ArialRegular; font-weight: 20; font-size: 14px"
        self.pageTitleFont  = QFont('ArialRegular')
        self.titleFont      = QFont('ArialRegular')
        self.contentFont    = QFont('ArialRegular')

        self.pageTitleColor = "#ffffff"
        self.titleColor     = "#ffffff"
        self.contentColor   = "#ffffff"
Beispiel #55
0
class MainWindow_Ui(QMainWindow):
    def __init__(self, persepolis_setting):
        super().__init__()
        # MainWindow
        self.persepolis_setting = persepolis_setting

        # add support for other languages
        locale = str(self.persepolis_setting.value('settings/locale'))
        QLocale.setDefault(QLocale(locale))
        self.translator = QTranslator()
        if self.translator.load(':/translations/locales/ui_' + locale, 'ts'):
            QCoreApplication.installTranslator(self.translator)


        # set ui direction
        ui_direction = self.persepolis_setting.value('ui_direction')

        if ui_direction == 'rtl':
            self.setLayoutDirection(Qt.RightToLeft)
        
        elif ui_direction in 'ltr':
            self.setLayoutDirection(Qt.LeftToRight)



        icons = ':/' + \
            str(self.persepolis_setting.value('settings/icons')) + '/'

        self.setWindowTitle(QCoreApplication.translate("mainwindow_ui_tr", "Persepolis Download Manager"))
        self.setWindowIcon(QIcon.fromTheme('persepolis', QIcon(':/persepolis.svg')))

        self.centralwidget = QWidget(self)
        self.verticalLayout = QVBoxLayout(self.centralwidget)
        # enable drag and drop
        self.setAcceptDrops(True)
# frame
        self.frame = QFrame(self.centralwidget)

# download_table_horizontalLayout
        download_table_horizontalLayout = QHBoxLayout()
        tabels_splitter = QSplitter(Qt.Horizontal)
# category_tree
        self.category_tree_qwidget = QWidget(self)
        category_tree_verticalLayout = QVBoxLayout()
        self.category_tree = CategoryTreeView(self)
        category_tree_verticalLayout.addWidget(self.category_tree)

        self.category_tree_model = QStandardItemModel()
        self.category_tree.setModel(self.category_tree_model)
        category_table_header = [QCoreApplication.translate("mainwindow_ui_tr", 'Category')]

        self.category_tree_model.setHorizontalHeaderLabels(
            category_table_header)
        self.category_tree.header().setStretchLastSection(True)

        self.category_tree.header().setDefaultAlignment(Qt.AlignCenter)
        
# queue_panel
        self.queue_panel_widget = QWidget(self)

        queue_panel_verticalLayout_main = QVBoxLayout(self.queue_panel_widget)
# queue_panel_show_button
        self.queue_panel_show_button = QPushButton(self)

        queue_panel_verticalLayout_main.addWidget(self.queue_panel_show_button)
# queue_panel_widget_frame
        self.queue_panel_widget_frame = QFrame(self)
        self.queue_panel_widget_frame.setFrameShape(QFrame.StyledPanel)
        self.queue_panel_widget_frame.setFrameShadow(QFrame.Raised)

        queue_panel_verticalLayout_main.addWidget(
            self.queue_panel_widget_frame)

        queue_panel_verticalLayout = QVBoxLayout(self.queue_panel_widget_frame)
        queue_panel_verticalLayout_main.setContentsMargins(50, -1, 50, -1)

# start_end_frame
        self.start_end_frame = QFrame(self)

# start time
        start_verticalLayout = QVBoxLayout(self.start_end_frame)
        self.start_checkBox = QCheckBox(self)
        start_verticalLayout.addWidget(self.start_checkBox)

        self.start_frame = QFrame(self)
        self.start_frame.setFrameShape(QFrame.StyledPanel)
        self.start_frame.setFrameShadow(QFrame.Raised)

        start_frame_verticalLayout = QVBoxLayout(self.start_frame)

        self.start_time_qDataTimeEdit = QDateTimeEdit(self.start_frame)
        self.start_time_qDataTimeEdit.setDisplayFormat('H:mm')
        start_frame_verticalLayout.addWidget(self.start_time_qDataTimeEdit)
  
        start_verticalLayout.addWidget(self.start_frame)
# end time

        self.end_checkBox = QCheckBox(self)
        start_verticalLayout.addWidget(self.end_checkBox)

        self.end_frame = QFrame(self)
        self.end_frame.setFrameShape(QFrame.StyledPanel)
        self.end_frame.setFrameShadow(QFrame.Raised)

        end_frame_verticalLayout = QVBoxLayout(self.end_frame)

        self.end_time_qDateTimeEdit = QDateTimeEdit(self.end_frame)
        self.end_time_qDateTimeEdit.setDisplayFormat('H:mm')
        end_frame_verticalLayout.addWidget(self.end_time_qDateTimeEdit)
 
        start_verticalLayout.addWidget(self.end_frame)

        self.reverse_checkBox = QCheckBox(self)
        start_verticalLayout.addWidget(self.reverse_checkBox)

        queue_panel_verticalLayout.addWidget(self.start_end_frame)

# limit_after_frame
        self.limit_after_frame = QFrame(self)
# limit_checkBox
        limit_verticalLayout = QVBoxLayout(self.limit_after_frame)
        self.limit_checkBox = QCheckBox(self)
        limit_verticalLayout.addWidget(self.limit_checkBox)
# limit_frame
        self.limit_frame = QFrame(self)
        self.limit_frame.setFrameShape(QFrame.StyledPanel)
        self.limit_frame.setFrameShadow(QFrame.Raised)
        limit_verticalLayout.addWidget(self.limit_frame)

        limit_frame_verticalLayout = QVBoxLayout(self.limit_frame)
# limit_spinBox
        limit_frame_horizontalLayout = QHBoxLayout()
        self.limit_spinBox = QDoubleSpinBox(self)
        self.limit_spinBox.setMinimum(1)
        self.limit_spinBox.setMaximum(1023)
        limit_frame_horizontalLayout.addWidget(self.limit_spinBox)
# limit_comboBox
        self.limit_comboBox = QComboBox(self)
        self.limit_comboBox.addItem("")
        self.limit_comboBox.addItem("")
        limit_frame_horizontalLayout.addWidget(self.limit_comboBox)
        limit_frame_verticalLayout.addLayout(limit_frame_horizontalLayout)
# limit_pushButton
        self.limit_pushButton = QPushButton(self)
        limit_frame_verticalLayout.addWidget(self.limit_pushButton)

# after_checkBox
        self.after_checkBox = QtWidgets.QCheckBox(self)
        limit_verticalLayout.addWidget(self.after_checkBox)
# after_frame
        self.after_frame = QtWidgets.QFrame(self)
        self.after_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.after_frame.setFrameShadow(QtWidgets.QFrame.Raised)
        limit_verticalLayout.addWidget(self.after_frame)

        after_frame_verticalLayout = QVBoxLayout(self.after_frame)
# after_comboBox
        self.after_comboBox = QComboBox(self)
        self.after_comboBox.addItem("")

        after_frame_verticalLayout.addWidget(self.after_comboBox)
# after_pushButton
        self.after_pushButton = QPushButton(self)
        after_frame_verticalLayout.addWidget(self.after_pushButton)

        queue_panel_verticalLayout.addWidget(self.limit_after_frame)
        category_tree_verticalLayout.addWidget(self.queue_panel_widget)

# keep_awake_checkBox
        self.keep_awake_checkBox = QCheckBox(self)
        queue_panel_verticalLayout.addWidget(self.keep_awake_checkBox)

        self.category_tree_qwidget.setLayout(category_tree_verticalLayout)
        tabels_splitter.addWidget(self.category_tree_qwidget)

# download table widget
        self.download_table_content_widget = QWidget(self)
        download_table_content_widget_verticalLayout = QVBoxLayout(
            self.download_table_content_widget)

        self.download_table = DownloadTableWidget(self)
        download_table_content_widget_verticalLayout.addWidget(
            self.download_table)
        tabels_splitter.addWidget(self.download_table_content_widget)

        self.download_table.setColumnCount(13)
        self.download_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.download_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.download_table.verticalHeader().hide()

# hide gid and download dictioanry section
        self.download_table.setColumnHidden(8, True)
        self.download_table.setColumnHidden(9, True)

        download_table_header = [QCoreApplication.translate("mainwindow_ui_tr", 'File Name'), QCoreApplication.translate("mainwindow_ui_tr",'Status'), QCoreApplication.translate("mainwindow_ui_tr", 'Size'), QCoreApplication.translate("mainwindow_ui_tr", 'Downloaded'), QCoreApplication.translate("mainwindow_ui_tr", 'Percentage'), QCoreApplication.translate("mainwindow_ui_tr", 'Connections'),
                                 QCoreApplication.translate("mainwindow_ui_tr", 'Transfer rate'), QCoreApplication.translate("mainwindow_ui_tr",'Estimated time left'), 'Gid', QCoreApplication.translate("mainwindow_ui_tr",'Link'), QCoreApplication.translate("mainwindow_ui_tr", 'First try date'), QCoreApplication.translate("mainwindow_ui_tr", 'Last try date'), QCoreApplication.translate("mainwindow_ui_tr",'Category')]

        self.download_table.setHorizontalHeaderLabels(download_table_header)

# fixing the size of download_table when window is Maximized!
        self.download_table.horizontalHeader().setSectionResizeMode(0)
        self.download_table.horizontalHeader().setStretchLastSection(True)

        tabels_splitter.setStretchFactor(0, 3) # category_tree width
        tabels_splitter.setStretchFactor(1, 10)  # ratio of tables's width
        download_table_horizontalLayout.addWidget(tabels_splitter)
        self.frame.setLayout(download_table_horizontalLayout)
        self.verticalLayout.addWidget(self.frame)
        self.setCentralWidget(self.centralwidget)

# menubar
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(QRect(0, 0, 600, 24))
        self.setMenuBar(self.menubar)
        fileMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&File'))
        editMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&Edit'))
        viewMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&View'))
        downloadMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&Download'))
        queueMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&Queue'))
        videoFinderMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", 'V&ideo Finder'))
        helpMenu = self.menubar.addMenu(QCoreApplication.translate("mainwindow_ui_tr", '&Help'))


# viewMenu submenus
        sortMenu = viewMenu.addMenu(QCoreApplication.translate("mainwindow_ui_tr", 'Sort by'))
# statusbar
        self.statusbar = QStatusBar(self)
        self.setStatusBar(self.statusbar)
        self.statusbar.showMessage(QCoreApplication.translate("mainwindow_ui_tr", "Persepolis Download Manager"))
# toolBar
        self.toolBar2 = QToolBar(self)
        self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar2)
        self.toolBar2.setWindowTitle(QCoreApplication.translate("mainwindow_ui_tr", 'Menu'))
        self.toolBar2.setFloatable(False)
        self.toolBar2.setMovable(False)

        self.toolBar = QToolBar(self)
        self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
        self.toolBar.setWindowTitle(QCoreApplication.translate("mainwindow_ui_tr", 'Toolbar'))
        self.toolBar.setFloatable(False)
        self.toolBar.setMovable(False)


#toolBar and menubar and actions
        self.videoFinderAddLinkAction = QAction(QIcon(icons + 'video_finder'), QCoreApplication.translate("mainwindow_ui_tr", 'Find Video Links'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Download video or audio from Youtube, Vimeo, etc...'),
                                            triggered=self.showVideoFinderAddLinkWindow)

        QShortcut(QKeySequence('Ctrl+I'), self, self.showVideoFinderAddLinkWindow)

        videoFinderMenu.addAction(self.videoFinderAddLinkAction)

        self.stopAllAction = QAction(QIcon(icons + 'stop_all'), QCoreApplication.translate("mainwindow_ui_tr", 'Stop all active downloads'),
                                     self, statusTip='Stop all active downloads', triggered=self.stopAllDownloads)
        downloadMenu.addAction(self.stopAllAction)

        self.sort_file_name_Action = QAction(
            QCoreApplication.translate("mainwindow_ui_tr", 'File name'), self, triggered=self.sortByName)
        sortMenu.addAction(self.sort_file_name_Action)

        self.sort_file_size_Action = QAction(
            QCoreApplication.translate("mainwindow_ui_tr", 'File size'), self, triggered=self.sortBySize)
        sortMenu.addAction(self.sort_file_size_Action)

        self.sort_first_try_date_Action = QAction(
            QCoreApplication.translate("mainwindow_ui_tr", 'First try date'), self, triggered=self.sortByFirstTry)
        sortMenu.addAction(self.sort_first_try_date_Action)

        self.sort_last_try_date_Action = QAction(
            QCoreApplication.translate("mainwindow_ui_tr", 'Last try date'), self, triggered=self.sortByLastTry)
        sortMenu.addAction(self.sort_last_try_date_Action)

        self.sort_download_status_Action = QAction(
            QCoreApplication.translate("mainwindow_ui_tr", 'Download status'), self, triggered=self.sortByStatus)
        sortMenu.addAction(self.sort_download_status_Action)

        self.trayAction = QAction(QCoreApplication.translate("mainwindow_ui_tr", 'Show system tray icon'), self,
                                  statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Show/Hide system tray icon"), triggered=self.showTray)
        self.trayAction.setCheckable(True)
        viewMenu.addAction(self.trayAction)

        self.showMenuBarAction = QAction(
            QCoreApplication.translate("mainwindow_ui_tr", 'Show menubar'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Show menubar'), triggered=self.showMenuBar)
        self.showMenuBarAction.setCheckable(True)
        viewMenu.addAction(self.showMenuBarAction)

        self.showSidePanelAction = QAction(
            QCoreApplication.translate("mainwindow_ui_tr", 'Show side panel'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Show side panel'), triggered=self.showSidePanel)
        self.showSidePanelAction.setCheckable(True)
        viewMenu.addAction(self.showSidePanelAction)

        self.minimizeAction = QAction(QIcon(icons + 'minimize'), QCoreApplication.translate("mainwindow_ui_tr", 'Minimize to system tray'), self,
                                      statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Minimize to system tray"), triggered=self.minMaxTray)
        QShortcut(QKeySequence('Ctrl+W'), self, self.minMaxTray)

        viewMenu.addAction(self.minimizeAction)

        self.addlinkAction = QAction(QIcon(icons + 'add'), QCoreApplication.translate("mainwindow_ui_tr", 'Add New Download Link'), self,
                                     statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Add New Download Link"), triggered=self.addLinkButtonPressed)
        QShortcut(QKeySequence('Ctrl+N'), self, self.addLinkButtonPressed)
        fileMenu.addAction(self.addlinkAction)

        self.addtextfileAction = QAction(QIcon(icons + 'file'), QCoreApplication.translate("mainwindow_ui_tr", 'Import links from text file'), self,
                                         statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Create a Text file and put links in it.line by line!'), triggered=self.importText)
        fileMenu.addAction(self.addtextfileAction)

        self.resumeAction = QAction(QIcon(icons + 'play'), QCoreApplication.translate("mainwindow_ui_tr", 'Resume Download'), self,
                                    statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Resume Download"), triggered=self.resumeButtonPressed)
        QShortcut(QKeySequence('Ctrl+R'), self, self.resumeButtonPressed)
        downloadMenu.addAction(self.resumeAction)

        self.pauseAction = QAction(QIcon(icons + 'pause'), QCoreApplication.translate("mainwindow_ui_tr", 'Pause Download'), self,
                                   statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Pause Download"), triggered=self.pauseButtonPressed)
        QShortcut(QKeySequence('Ctrl+C'), self, self.pauseButtonPressed)
        downloadMenu.addAction(self.pauseAction)

        self.stopAction = QAction(QIcon(icons + 'stop'), QCoreApplication.translate("mainwindow_ui_tr", 'Stop Download'), self,
                                  statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Stop/Cancel Download"), triggered=self.stopButtonPressed)
        QShortcut(QKeySequence('Ctrl+S'), self, self.stopButtonPressed)
        downloadMenu.addAction(self.stopAction)

        self.propertiesAction = QAction(QIcon(icons + 'setting'), QCoreApplication.translate("mainwindow_ui_tr", 'Properties'), self,
                                        statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Properties"), triggered=self.propertiesButtonPressed)
        QShortcut(QKeySequence('Ctrl+P'), self, self.propertiesButtonPressed)
        downloadMenu.addAction(self.propertiesAction)

        self.progressAction = QAction(QIcon(icons + 'window'), QCoreApplication.translate("mainwindow_ui_tr", 'Progress'), self,
                                      statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Progress"), triggered=self.progressButtonPressed)
        QShortcut(QKeySequence('Ctrl+Z'), self, self.progressButtonPressed)
        downloadMenu.addAction(self.progressAction)

        self.openFileAction = QAction(QIcon(
            icons + 'file'), QCoreApplication.translate("mainwindow_ui_tr", 'Open file'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Open file'), triggered=self.openFile)
        fileMenu.addAction(self.openFileAction)

        self.openDownloadFolderAction = QAction(QIcon(
            icons + 'folder'), QCoreApplication.translate("mainwindow_ui_tr", 'Open download folder'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Open download folder'), triggered=self.openDownloadFolder)
        fileMenu.addAction(self.openDownloadFolderAction)

        self.openDefaultDownloadFolderAction = QAction(QIcon(
            icons + 'folder'), QCoreApplication.translate("mainwindow_ui_tr", 'Open default download folder'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Open default download folder'), triggered=self.openDefaultDownloadFolder)
        fileMenu.addAction(self.openDefaultDownloadFolderAction)

        self.exitAction = QAction(QIcon(icons + 'exit'), QCoreApplication.translate("mainwindow_ui_tr", 'Exit'), self,
                                  statusTip=QCoreApplication.translate("mainwindow_ui_tr", "Exit"), triggered=self.closeEvent)
        QShortcut(QKeySequence('Ctrl+Q'), self, self.closeEvent)
        fileMenu.addAction(self.exitAction)

        self.clearAction = QAction(QIcon(icons + 'multi_remove'), QCoreApplication.translate("mainwindow_ui_tr", 'Clear download list'),
                                         self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Clear all items in download list'), triggered=self.clearDownloadList)
        editMenu.addAction(self.clearAction)

        self.removeSelectedAction = QAction(QIcon(icons + 'remove'), QCoreApplication.translate("mainwindow_ui_tr", 'Remove selected downloads from list'),
                                            self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Remove selected downloads form list'), triggered=self.removeSelected)
        editMenu.addAction(self.removeSelectedAction)
        self.removeSelectedAction.setEnabled(False)

        self.deleteSelectedAction = QAction(QIcon(icons + 'trash'), QCoreApplication.translate("mainwindow_ui_tr", 'Delete selected download files'),
                                            self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Delete selected download files'), triggered=self.deleteSelected)
        editMenu.addAction(self.deleteSelectedAction)
        self.deleteSelectedAction.setEnabled(False)

        self.createQueueAction = QAction(QIcon(icons + 'add_queue'), QCoreApplication.translate("mainwindow_ui_tr", 'Create new queue'),
                                         self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Create new download queue'), triggered=self.createQueue)
        queueMenu.addAction(self.createQueueAction)

        self.removeQueueAction = QAction(QIcon(icons + 'remove_queue'), QCoreApplication.translate("mainwindow_ui_tr", 'Remove this queue'),
                                         self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Remove this queue'), triggered=self.removeQueue)
        queueMenu.addAction(self.removeQueueAction)

        self.startQueueAction = QAction(QIcon(
            icons + 'start_queue'), QCoreApplication.translate("mainwindow_ui_tr", 'Start this queue'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Start this queue'), triggered=self.startQueue)
        queueMenu.addAction(self.startQueueAction)

        self.stopQueueAction = QAction(QIcon(
            icons + 'stop_queue'), QCoreApplication.translate("mainwindow_ui_tr", 'Stop this queue'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Stop this queue'), triggered=self.stopQueue)
        queueMenu.addAction(self.stopQueueAction)

        self.moveUpSelectedAction = QAction(QIcon(icons + 'multi_up'), QCoreApplication.translate("mainwindow_ui_tr", 'Move up selected items'), self,
                                            statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Move currently selected items up by one row'), triggered=self.moveUpSelected)
        queueMenu.addAction(self.moveUpSelectedAction)

        self.moveDownSelectedAction = QAction(QIcon(icons + 'multi_down'), QCoreApplication.translate("mainwindow_ui_tr", 'Move down selected items'),
                                              self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Move currently selected items down by one row'), triggered=self.moveDownSelected)
        queueMenu.addAction(self.moveDownSelectedAction)

        self.preferencesAction = QAction(QIcon(icons + 'preferences'), QCoreApplication.translate("mainwindow_ui_tr", 'Preferences'),
                                         self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Preferences'), triggered=self.openPreferences, menuRole=5)
        editMenu.addAction(self.preferencesAction)

        self.aboutAction = QAction(QIcon(
            icons + 'about'), QCoreApplication.translate("mainwindow_ui_tr", 'About'), self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'About'), triggered=self.openAbout, menuRole=4)
        helpMenu.addAction(self.aboutAction)

        self.issueAction = QAction(QIcon(icons + 'about'), QCoreApplication.translate("mainwindow_ui_tr", 'Report an issue'),
                                   self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Report an issue'), triggered=self.reportIssue)
        helpMenu.addAction(self.issueAction)

        self.updateAction = QAction(QIcon(icons + 'about'), QCoreApplication.translate("mainwindow_ui_tr", 'Check for newer version'),
                                    self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Check for newer release'), triggered=self.newUpdate)
        helpMenu.addAction(self.updateAction)

        self.logAction = QAction(QIcon(icons + 'about'), QCoreApplication.translate("mainwindow_ui_tr", 'Show log file'),
                                   self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Help'), triggered=self.showLog)
        helpMenu.addAction(self.logAction)

        self.helpAction = QAction(QIcon(icons + 'about'), QCoreApplication.translate("mainwindow_ui_tr", 'Help'),
                                   self, statusTip=QCoreApplication.translate("mainwindow_ui_tr", 'Help'), triggered=self.persepolisHelp)
        helpMenu.addAction(self.helpAction)

        self.qmenu = MenuWidget(self)

        self.toolBar2.addWidget(self.qmenu)

# labels
        self.queue_panel_show_button.setText(QCoreApplication.translate("mainwindow_ui_tr", "Hide options"))
        self.start_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "Start Time"))

        self.end_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "End Time"))

        self.reverse_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "Download bottom of\n the list first"))

        self.limit_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "Limit Speed"))
        self.limit_comboBox.setItemText(0, "KiB/s")
        self.limit_comboBox.setItemText(1, "MiB/s")
        self.limit_pushButton.setText(QCoreApplication.translate("mainwindow_ui_tr", "Apply"))

        self.after_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "After download"))
        self.after_comboBox.setItemText(0, QCoreApplication.translate("mainwindow_ui_tr", "Shut Down"))

        self.keep_awake_checkBox.setText(QCoreApplication.translate("mainwindow_ui_tr", "Keep system awake!"))
        self.keep_awake_checkBox.setToolTip(
            QCoreApplication.translate("mainwindow_ui_tr", "<html><head/><body><p>This option is preventing system from going to sleep.\
            This is necessary if your power manager is suspending system automatically. </p></body></html>"))
 
        self.after_pushButton.setText(QCoreApplication.translate("mainwindow_ui_tr", "Apply"))

    def changeIcon(self, icons):
        icons = ':/' + str(icons) + '/'

        action_icon_dict = {self.stopAllAction: 'stop_all', self.minimizeAction: 'minimize', self.addlinkAction: 'add', self.addtextfileAction: 'file', self.resumeAction: 'play', self.pauseAction: 'pause', self.stopAction: 'stop', self.propertiesAction: 'setting', self.progressAction: 'window', self.openFileAction: 'file', self.openDownloadFolderAction: 'folder', self.openDefaultDownloadFolderAction: 'folder', self.exitAction: 'exit',
                self.removeSelectedAction: 'multi_remove', self.deleteSelectedAction: 'multi_trash', self.createQueueAction: 'add_queue', self.removeQueueAction: 'remove_queue', self.startQueueAction: 'start_queue', self.stopQueueAction: 'stop_queue', self.preferencesAction: 'preferences', self.aboutAction: 'about', self.issueAction: 'about', self.updateAction: 'about', self.videoFinderAddLinkAction: 'video_finder', self.qmenu: 'menu'}
        for key in action_icon_dict.keys():
            key.setIcon(QIcon(icons + str(action_icon_dict[key])))
Beispiel #56
0
class AppWindow(QMainWindow):
	"The application's main window"
	move_listener = pyqtSignal()
	db_activity_checker = pyqtSignal()
	graphics_blur = QGraphicsBlurEffect()
	def __init__(self):
		super().__init__()
		app_constants.GENERAL_THREAD = QThread(self)
		app_constants.GENERAL_THREAD.finished.connect(app_constants.GENERAL_THREAD.deleteLater)
		app_constants.GENERAL_THREAD.start()
		self.setAcceptDrops(True)
		self.initUI()
		self.start_up()
		QTimer.singleShot(3000, self._check_update)
		self.setFocusPolicy(Qt.NoFocus)
		self.set_shortcuts()
		self.graphics_blur.setParent(self)
		#ex = settings.ExProperties()
		#d = pewnet.ExHenManager(ex.ipb_id, ex.ipb_pass)
		#item = d.from_gallery_url('http://exhentai.org/g/861957/02741dc584/')
		#def a(): print(item.file)
		#if not item.file:
		#	item.file_rdy.connect(a)
		#else:
		#	a()

	def set_shortcuts(self):
		quit = QShortcut(QKeySequence('Ctrl+Q'), self, self.close)

	def init_watchers(self):

		def remove_gallery(g):
			index = self.manga_list_view.find_index(g.id, True)
			if index:
				self.manga_list_view.remove_gallery([index])

		def create_gallery(path):
			g_dia = gallerydialog.GalleryDialog(self, path)
			g_dia.SERIES.connect(self.manga_list_view.gallery_model.addRows)
			g_dia.show()

		def update_gallery(g):
			index = self.manga_list_view.find_index(g.id)
			if index:
				self.manga_list_view.replace_edit_gallery([g], index.row())
			else:
				log_e('Could not find gallery to update from watcher')

		def created(path):
			c_popup = io_misc.CreatedPopup(path, self)
			c_popup.ADD_SIGNAL.connect(create_gallery)
		def modified(path, gallery):
			mod_popup = io_misc.ModifiedPopup(path, gallery, self)
		def deleted(path, gallery):
			d_popup = io_misc.DeletedPopup(path, gallery, self)
			d_popup.UPDATE_SIGNAL.connect(update_gallery)
			d_popup.REMOVE_SIGNAL.connect(remove_gallery)
		def moved(new_path, gallery):
			mov_popup = io_misc.MovedPopup(new_path, gallery, self)
			mov_popup.UPDATE_SIGNAL.connect(update_gallery)

		self.watchers = io_misc.Watchers()
		self.watchers.gallery_handler.CREATE_SIGNAL.connect(created)
		self.watchers.gallery_handler.MODIFIED_SIGNAL.connect(modified)
		self.watchers.gallery_handler.MOVED_SIGNAL.connect(moved)
		self.watchers.gallery_handler.DELETED_SIGNAL.connect(deleted)

	admin_db_method_invoker = pyqtSignal(str)
	def start_up(self):
		hello = ["Hello!", "Hi!", "Onii-chan!", "Senpai!", "Hisashiburi!", "Welcome!", "Okaerinasai!", "Welcome back!", "Hajimemashite!"]
		self.notification_bar.add_text("{} Please don't hesitate to report any bugs you find.".format(hello[random.randint(0, len(hello)-1)])+
								 " Go to Settings -> About -> Bug Reporting for more info!")
		level = 5
		def normalize_first_time():
			settings.set(level, 'Application', 'first time level')
			settings.save()

		def done(status=True):
			gallerydb.DatabaseEmitter.RUN = True
			if app_constants.FIRST_TIME_LEVEL != level:
				normalize_first_time()
			if app_constants.ENABLE_MONITOR and\
				app_constants.MONITOR_PATHS and all(app_constants.MONITOR_PATHS):
				self.init_watchers()
				if app_constants.LOOK_NEW_GALLERY_STARTUP:
					if self.manga_list_view.gallery_model.db_emitter.count == app_constants.GALLERY_DATA:
						self.scan_for_new_galleries()
					else:
						self.manga_list_view.gallery_model.db_emitter.DONE.connect(self.scan_for_new_galleries)
			self.download_manager = pewnet.Downloader()
			app_constants.DOWNLOAD_MANAGER = self.download_manager
			self.download_manager.start_manager(4)

		if app_constants.FIRST_TIME_LEVEL < 4:
			log_i('Invoking first time level {}'.format(4))
			settings.set([], 'Application', 'monitor paths')
			settings.set([], 'Application', 'ignore paths')
			app_constants.MONITOR_PATHS = []
			app_constants.IGNORE_PATHS = []
			settings.save()
			done()
		elif app_constants.FIRST_TIME_LEVEL < 5:
			log_i('Invoking first time level {}'.format(5))
			app_widget = misc.ApplicationPopup(self)
			app_widget.note_info.setText("<font color='red'>IMPORTANT:</font> Application restart is required when done")
			app_widget.restart_info.hide()
			self.admin_db = gallerydb.AdminDB()
			self.admin_db.moveToThread(app_constants.GENERAL_THREAD)
			self.admin_db.DONE.connect(done)
			self.admin_db.DONE.connect(lambda: app_constants.NOTIF_BAR.add_text("Application requires a restart"))
			self.admin_db.DONE.connect(self.admin_db.deleteLater)
			self.admin_db.DATA_COUNT.connect(app_widget.prog.setMaximum)
			self.admin_db.PROGRESS.connect(app_widget.prog.setValue)
			self.admin_db_method_invoker.connect(self.admin_db.rebuild_db)
			self.admin_db_method_invoker.connect(app_widget.show)
			app_widget.adjustSize()
			db_p = os.path.join(os.path.split(database.db_constants.DB_PATH)[0], 'sadpanda.db')
			self.admin_db_method_invoker.emit(db_p)
		else:
			done()

	def initUI(self):
		self.center = QWidget()
		self.display = QStackedLayout()
		self._main_layout = QVBoxLayout()
		self._main_layout.setSpacing(0)
		self._main_layout.setContentsMargins(0,0,0,0)
		self._main_layout.addLayout(self.display)
		self.center.setLayout(self._main_layout)
		# init the manga view variables
		self.manga_display()
		log_d('Create manga display: OK')
		# init the chapter view variables
		#self.chapter_display()
		self.m_l_view_index = self.display.addWidget(self.manga_list_view)
		self.m_t_view_index = self.display.addWidget(self.manga_table_view)
		self.download_window = io_misc.GalleryDownloader(self)
		self.download_window.hide()
		# init toolbar
		self.init_toolbar()
		log_d('Create toolbar: OK')
		# init status bar
		self.init_stat_bar()
		log_d('Create statusbar: OK')

		self.tags_treeview = None
		if app_constants.TAGS_TREEVIEW_ON_START:
			def tags_tree_none(): self.tags_treeview = None
			self.tags_treeview = misc_db.DBOverview(self, True)
			self.tags_treeview.about_to_close.connect(tags_tree_none)
			self.tags_treeview.show()

		self.system_tray = misc.SystemTray(QIcon(app_constants.APP_ICO_PATH), self)
		app_constants.SYSTEM_TRAY = self.system_tray
		tray_menu = QMenu(self)
		self.system_tray.setContextMenu(tray_menu)
		self.system_tray.setToolTip('Happypanda {}'.format(app_constants.vs))
		tray_quit = QAction('Quit', tray_menu)
		tray_update = tray_menu.addAction('Check for update')
		tray_update.triggered.connect(self._check_update)
		tray_menu.addAction(tray_quit)
		tray_quit.triggered.connect(self.close)
		self.system_tray.show()
		def tray_activate(r=None):
			if not r or r == QSystemTrayIcon.Trigger:
				self.showNormal()
				self.activateWindow()
		self.system_tray.messageClicked.connect(tray_activate)
		self.system_tray.activated.connect(tray_activate)
		log_d('Create system tray: OK')
		#self.display.addWidget(self.chapter_main)

		self.setCentralWidget(self.center)
		self.setWindowIcon(QIcon(app_constants.APP_ICO_PATH))


		props = settings.win_read(self, 'AppWindow')
		if props.resize:
			x, y = props.resize
			self.resize(x, y)
		else:
			self.resize(app_constants.MAIN_W, app_constants.MAIN_H)
		posx, posy = props.pos
		self.move(posx, posy)
		self.init_spinners()
		self.show()
		log_d('Show window: OK')

		self.notification_bar = misc.NotificationOverlay(self)
		p = self.toolbar.pos()
		self.notification_bar.move(p.x(), p.y()+self.toolbar.height())
		self.notification_bar.resize(self.width())
		app_constants.NOTIF_BAR = self.notification_bar
		log_d('Create notificationbar: OK')

		log_d('Window Create: OK')

	def _check_update(self):
		class upd_chk(QObject):
			UPDATE_CHECK = pyqtSignal(str)
			def __init__(self, **kwargs):
				super().__init__(**kwargs)
			def fetch_vs(self):
				import requests
				import time
				log_d('Checking Update')
				time.sleep(1.5)
				try:
					if os.path.exists('cacert.pem'):
						r = requests.get("https://raw.githubusercontent.com/Pewpews/happypanda/master/VS.txt",
							  verify='cacert.pem')
					else:
						r = requests.get("https://raw.githubusercontent.com/Pewpews/happypanda/master/VS.txt")
					a = r.text
					vs = a.strip()
					self.UPDATE_CHECK.emit(vs)
				except:
					log.exception('Checking Update: FAIL')
					self.UPDATE_CHECK.emit('this is a very long text which is sure to be over limit')

		def check_update(vs):
			log_i('Received version: {}\nCurrent version: {}'.format(vs, app_constants.vs))
			if vs != app_constants.vs:
				if len(vs) < 10:
					self.notification_bar.begin_show()
					self.notification_bar.add_text("Version {} of Happypanda is".format(vs)+
									   " available. Click here to update!", False)
					self.notification_bar.clicked.connect(lambda: utils.open_web_link(
						'https://github.com/Pewpews/happypanda/releases'))
					self.notification_bar.set_clickable(True)
				else:
					self.notification_bar.add_text("An error occurred while checking for new version")

		self.update_instance = upd_chk()
		thread = QThread(self)
		self.update_instance.moveToThread(thread)
		thread.started.connect(self.update_instance.fetch_vs)
		self.update_instance.UPDATE_CHECK.connect(check_update)
		self.update_instance.UPDATE_CHECK.connect(self.update_instance.deleteLater)
		thread.finished.connect(thread.deleteLater)
		thread.start()

	def _web_metadata_picker(self, gallery, title_url_list, queue, parent=None):
		if not parent:
			parent = self
		text = "Which gallery do you want to extract metadata from?"
		s_gallery_popup = misc.SingleGalleryChoices(gallery, title_url_list,
											  text, parent)
		s_gallery_popup.USER_CHOICE.connect(queue.put)

	def get_metadata(self, gal=None):
		metadata_spinner = misc.Spinner(self)
		def move_md_spinner():
			metadata_spinner.update_move(
			QPoint(
				self.pos().x()+self.width()-65,
				self.pos().y()+self.toolbar.height()+55))
		metadata_spinner.set_text("Metadata")
		metadata_spinner.set_size(55)
		metadata_spinner.move(QPoint(self.pos().x()+self.width()-65,
							   self.pos().y()+self.toolbar.height()+55))
		self.move_listener.connect(move_md_spinner)
		thread = QThread(self)
		thread.setObjectName('App.get_metadata')
		fetch_instance = fetch.Fetch()
		if gal:
			if not isinstance(gal, list):
				galleries = [gal]
			else:
				galleries = gal
		else:
			if app_constants.CONTINUE_AUTO_METADATA_FETCHER:
				galleries = [g for g in self.manga_list_view.gallery_model._data if not g.exed]
			else:
				galleries = self.manga_list_view.gallery_model._data
			if not galleries:
				self.notification_bar.add_text('Looks like we\'ve already gone through all galleries!')
				return None
		fetch_instance.galleries = galleries

		self.notification_bar.begin_show()
		fetch_instance.moveToThread(thread)

		def done(status):
			self.notification_bar.end_show()
			fetch_instance.deleteLater()
			if not isinstance(status, bool):
				galleries = []
				for tup in status:
					galleries.append(tup[0])

				class GalleryContextMenu(QMenu):
					app_instance = self
					def __init__(self, parent=None):
						super().__init__(parent)
						show_in_library_act = self.addAction('Show in library')
						show_in_library_act.triggered.connect(self.show_in_library)

					def show_in_library(self):
						viewer = self.app_instance.manga_list_view
						index = viewer.find_index(self.gallery_widget.gallery.id, True)
						if index:
							self.app_instance.manga_table_view.scroll_to_index(index)
							self.app_instance.manga_list_view.scroll_to_index(index)

				g_popup = io_misc.GalleryPopup(('Fecthing metadata for these galleries failed.'+
									  ' Check happypanda.log for details.', galleries), self, menu=GalleryContextMenu())
				#errors = {g[0].id: g[1] for g in status}
				#for g_item in g_popup.get_all_items():
				#	g_item.setToolTip(errors[g_item.gallery.id])
				g_popup.graphics_blur.setEnabled(False)
				close_button = g_popup.add_buttons('Close')[0]
				close_button.clicked.connect(g_popup.close)

		fetch_instance.GALLERY_PICKER.connect(self._web_metadata_picker)
		fetch_instance.GALLERY_EMITTER.connect(self.manga_list_view.replace_edit_gallery)
		fetch_instance.AUTO_METADATA_PROGRESS.connect(self.notification_bar.add_text)
		thread.started.connect(fetch_instance.auto_web_metadata)
		fetch_instance.FINISHED.connect(done)
		fetch_instance.FINISHED.connect(metadata_spinner.close)
		fetch_instance.FINISHED.connect(lambda: self.move_listener.disconnect(move_md_spinner))
		thread.finished.connect(thread.deleteLater)
		thread.start()
		metadata_spinner.show()

	def init_stat_bar(self):
		self.status_bar = self.statusBar()
		self.status_bar.setMaximumHeight(20)
		self.status_bar.setSizeGripEnabled(False)
		self.stat_info = QLabel()
		self.stat_info.setIndent(5)
		self.sort_main = QAction("Asc", self)
		sort_menu = QMenu()
		self.sort_main.setMenu(sort_menu)
		s_by_title = QAction("Title", sort_menu)
		s_by_artist = QAction("Artist", sort_menu)
		sort_menu.addAction(s_by_title)
		sort_menu.addAction(s_by_artist)
		self.status_bar.addPermanentWidget(self.stat_info)
		#self.status_bar.addAction(self.sort_main)
		self.temp_msg = QLabel()
		self.temp_timer = QTimer()

		self.manga_list_view.gallery_model.ROWCOUNT_CHANGE.connect(self.stat_row_info)
		self.manga_list_view.gallery_model.db_emitter.COUNT_CHANGE.connect(self.stat_row_info)
		self.manga_list_view.gallery_model.STATUSBAR_MSG.connect(self.stat_temp_msg)
		self.manga_list_view.STATUS_BAR_MSG.connect(self.stat_temp_msg)
		self.manga_table_view.STATUS_BAR_MSG.connect(self.stat_temp_msg)
		self.stat_row_info()
		app_constants.STAT_MSG_METHOD = self.stat_temp_msg

	def stat_temp_msg(self, msg):
		self.temp_timer.stop()
		self.temp_msg.setText(msg)
		self.status_bar.addWidget(self.temp_msg)
		self.temp_timer.timeout.connect(self.temp_msg.clear)
		self.temp_timer.setSingleShot(True)
		self.temp_timer.start(5000)

	def stat_row_info(self):
		r = self.manga_list_view.model().rowCount()
		t = self.manga_list_view.gallery_model.db_emitter.count
		self.stat_info.setText("Loaded {} of {} ".format(r, t))

	def manga_display(self):
		"initiates the manga view and related things"
		#list view
		self.manga_list_view = gallery.MangaView(self)

		#table view

		self.manga_table_view = gallery.MangaTableView(self)
		self.manga_table_view.gallery_model = self.manga_list_view.gallery_model
		self.manga_table_view.sort_model = self.manga_list_view.sort_model
		self.manga_table_view.setModel(self.manga_table_view.sort_model)
		self.manga_table_view.sort_model.change_model(self.manga_table_view.gallery_model)
		self.manga_table_view.setColumnWidth(app_constants.FAV, 20)
		self.manga_table_view.setColumnWidth(app_constants.ARTIST, 200)
		self.manga_table_view.setColumnWidth(app_constants.TITLE, 400)
		self.manga_table_view.setColumnWidth(app_constants.TAGS, 300)
		self.manga_table_view.setColumnWidth(app_constants.TYPE, 60)
		self.manga_table_view.setColumnWidth(app_constants.CHAPTERS, 60)
		self.manga_table_view.setColumnWidth(app_constants.LANGUAGE, 100)
		self.manga_table_view.setColumnWidth(app_constants.LINK, 400)


	def init_spinners(self):
		# fetching spinner
		self.data_fetch_spinner = misc.Spinner(self)
		self.data_fetch_spinner.set_size(60)
		self.move_listener.connect(
			lambda: self.data_fetch_spinner.update_move(
				QPoint(self.pos().x()+self.width()//2, self.pos().y()+self.height()//2)))
		
		self.manga_list_view.gallery_model.ADD_MORE.connect(self.data_fetch_spinner.show)
		self.manga_list_view.gallery_model.db_emitter.START.connect(self.data_fetch_spinner.show)
		self.manga_list_view.gallery_model.ADDED_ROWS.connect(self.data_fetch_spinner.before_hide)
		self.manga_list_view.gallery_model.db_emitter.CANNOT_FETCH_MORE.connect(self.data_fetch_spinner.before_hide)

		## deleting spinner
		#self.gallery_delete_spinner = misc.Spinner(self)
		#self.gallery_delete_spinner.set_size(40,40)
		##self.gallery_delete_spinner.set_text('Removing...')
		#self.manga_list_view.gallery_model.rowsAboutToBeRemoved.connect(self.gallery_delete_spinner.show)
		#self.manga_list_view.gallery_model.rowsRemoved.connect(self.gallery_delete_spinner.before_hide)


	def search(self, srch_string):
		self.search_bar.setText(srch_string)
		self.search_backward.setVisible(True)
		self.manga_list_view.sort_model.init_search(srch_string)
		old_cursor_pos = self._search_cursor_pos[0]
		self.search_bar.end(False)
		if self.search_bar.cursorPosition() != old_cursor_pos+1:
			self.search_bar.setCursorPosition(old_cursor_pos)


	def favourite_display(self):
		"Switches to favourite display"
		self.manga_table_view.sort_model.fav_view()
		self.favourite_btn.selected = True
		self.library_btn.selected = False

	def catalog_display(self):
		"Switches to catalog display"
		self.manga_table_view.sort_model.catalog_view()
		self.library_btn.selected = True
		self.favourite_btn.selected = False

	def settings(self):
		sett = settingsdialog.SettingsDialog(self)
		sett.scroll_speed_changed.connect(self.manga_list_view.updateGeometries)
		#sett.show()

	def init_toolbar(self):
		self.toolbar = QToolBar()
		self.toolbar.setFixedHeight(25)
		self.toolbar.setWindowTitle("Show") # text for the contextmenu
		#self.toolbar.setStyleSheet("QToolBar {border:0px}") # make it user defined?
		self.toolbar.setMovable(False)
		self.toolbar.setFloatable(False)
		#self.toolbar.setIconSize(QSize(20,20))
		self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		self.toolbar.setIconSize(QSize(20,20))

		spacer_start = QWidget() # aligns the first actions properly
		spacer_start.setFixedSize(QSize(10, 1))
		self.toolbar.addWidget(spacer_start)

		self.favourite_btn = misc.ToolbarButton(self.toolbar, 'Favorites')
		self.toolbar.addWidget(self.favourite_btn)
		self.favourite_btn.clicked.connect(self.favourite_display) #need lambda to pass extra args

		self.library_btn = misc.ToolbarButton(self.toolbar, 'Library')
		self.toolbar.addWidget(self.library_btn)
		self.library_btn.clicked.connect(self.catalog_display) #need lambda to pass extra args
		self.library_btn.selected = True

		self.toolbar.addSeparator()

		gallery_menu = QMenu()
		gallery_action = QToolButton()
		gallery_action.setText('Gallery ')
		gallery_action.setPopupMode(QToolButton.InstantPopup)
		gallery_action.setToolTip('Contains various gallery related features')
		gallery_action.setMenu(gallery_menu)
		add_gallery_icon = QIcon(app_constants.PLUS_PATH)
		gallery_action_add = QAction(add_gallery_icon, "Add single gallery...", self)
		gallery_action_add.triggered.connect(self.manga_list_view.SERIES_DIALOG.emit)
		gallery_action_add.setToolTip('Add a single gallery thoroughly')
		gallery_menu.addAction(gallery_action_add)
		add_more_action = QAction(add_gallery_icon, "Add galleries...", self)
		add_more_action.setStatusTip('Add galleries from different folders')
		add_more_action.triggered.connect(lambda: self.populate(True))
		gallery_menu.addAction(add_more_action)
		populate_action = QAction(add_gallery_icon, "Populate from directory/archive...", self)
		populate_action.setStatusTip('Populates the DB with galleries from a single folder or archive')
		populate_action.triggered.connect(self.populate)
		gallery_menu.addAction(populate_action)
		gallery_menu.addSeparator()
		metadata_action = QAction('Get metadata for all galleries', self)
		metadata_action.triggered.connect(self.get_metadata)
		gallery_menu.addAction(metadata_action)
		scan_galleries_action = QAction('Scan for new galleries', self)
		scan_galleries_action.triggered.connect(self.scan_for_new_galleries)
		scan_galleries_action.setStatusTip('Scan monitored folders for new galleries')
		gallery_menu.addAction(scan_galleries_action)
		gallery_action_random = gallery_menu.addAction("Open random gallery")
		gallery_action_random.triggered.connect(self.manga_list_view.open_random_gallery)
		self.toolbar.addWidget(gallery_action)


		misc_action = QToolButton()
		misc_action.setText('Tools ')
		misc_action_menu = QMenu()
		misc_action.setMenu(misc_action_menu)
		misc_action.setPopupMode(QToolButton.InstantPopup)
		misc_action.setToolTip("Contains misc. features")
		gallery_downloader = QAction("Gallery Downloader", misc_action_menu)
		gallery_downloader.triggered.connect(self.download_window.show)
		misc_action_menu.addAction(gallery_downloader)
		duplicate_check_simple = QAction("Simple Duplicate Finder", misc_action_menu)
		duplicate_check_simple.triggered.connect(lambda: self.manga_list_view.duplicate_check())
		misc_action_menu.addAction(duplicate_check_simple)
		self.toolbar.addWidget(misc_action)

		spacer_middle = QWidget() # aligns buttons to the right
		spacer_middle.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
		self.toolbar.addWidget(spacer_middle)


		sort_action = QToolButton()
		sort_action.setIcon(QIcon(app_constants.SORT_PATH))
		sort_action.setMenu(misc.SortMenu(self.toolbar, self.manga_list_view))
		sort_action.setPopupMode(QToolButton.InstantPopup)
		self.toolbar.addWidget(sort_action)
		
		self.grid_toggle_g_icon = QIcon(app_constants.GRID_PATH)
		self.grid_toggle_l_icon = QIcon(app_constants.LIST_PATH)
		self.grid_toggle = QToolButton()
		if self.display.currentIndex() == self.m_l_view_index:
			self.grid_toggle.setIcon(self.grid_toggle_l_icon)
		else:
			self.grid_toggle.setIcon(self.grid_toggle_g_icon)
		self.grid_toggle.setObjectName('gridtoggle')
		self.grid_toggle.clicked.connect(self.toggle_view)
		self.toolbar.addWidget(self.grid_toggle)

		spacer_mid2 = QWidget()
		spacer_mid2.setFixedSize(QSize(5, 1))
		self.toolbar.addWidget(spacer_mid2)

		def set_search_case(b):
			app_constants.GALLERY_SEARCH_CASE = b
			settings.set(b, 'Application', 'gallery search case')
			settings.save()

		def set_search_strict(b):
			app_constants.GALLERY_SEARCH_STRICT = b
			settings.set(b, 'Application', 'gallery search strict')
			settings.save()

		self.search_bar = misc.LineEdit()
		search_options = self.search_bar.addAction(QIcon(app_constants.SEARCH_OPTIONS_PATH), QLineEdit.TrailingPosition)
		search_options_menu = QMenu(self)
		search_options.triggered.connect(lambda: search_options_menu.popup(QCursor.pos()))
		search_options.setMenu(search_options_menu)
		case_search_option = search_options_menu.addAction('Case Sensitive')
		case_search_option.setCheckable(True)
		case_search_option.setChecked(app_constants.GALLERY_SEARCH_CASE)
		case_search_option.toggled.connect(set_search_case)
		strict_search_option = search_options_menu.addAction('Match whole terms')
		strict_search_option.setCheckable(True)
		strict_search_option.setChecked(app_constants.GALLERY_SEARCH_STRICT)
		strict_search_option.toggled.connect(set_search_strict)
		self.search_bar.setObjectName('search_bar')
		self.search_timer = QTimer(self)
		self.search_timer.setSingleShot(True)
		self.search_timer.timeout.connect(lambda: self.search(self.search_bar.text()))
		self._search_cursor_pos = [0, 0]
		def set_cursor_pos(old, new):
			self._search_cursor_pos[0] = old
			self._search_cursor_pos[1] = new
		self.search_bar.cursorPositionChanged.connect(set_cursor_pos)

		if app_constants.SEARCH_AUTOCOMPLETE:
			completer = QCompleter(self)
			completer_view = misc.CompleterPopupView()
			completer.setPopup(completer_view)
			completer_view._setup()
			completer.setModel(self.manga_list_view.gallery_model)
			completer.setCaseSensitivity(Qt.CaseInsensitive)
			completer.setCompletionMode(QCompleter.PopupCompletion)
			completer.setCompletionRole(Qt.DisplayRole)
			completer.setCompletionColumn(app_constants.TITLE)
			completer.setFilterMode(Qt.MatchContains)
			self.search_bar.setCompleter(completer)
			self.search_bar.returnPressed.connect(lambda: self.search(self.search_bar.text()))
		if not app_constants.SEARCH_ON_ENTER:
			self.search_bar.textEdited.connect(lambda: self.search_timer.start(800))
		self.search_bar.setPlaceholderText("Search title, artist, namespace & tags")
		self.search_bar.setMinimumWidth(150)
		self.search_bar.setMaximumWidth(500)
		self.search_bar.setFixedHeight(19)
		self.manga_list_view.sort_model.HISTORY_SEARCH_TERM.connect(lambda a: self.search_bar.setText(a))
		self.toolbar.addWidget(self.search_bar)

		def search_history(_, back=True): # clicked signal passes a bool
			sort_model =  self.manga_list_view.sort_model
			nav = sort_model.PREV if back else sort_model.NEXT
			history_term = sort_model.navigate_history(nav)
			if back:
				self.search_forward.setVisible(True)

		back = QShortcut(QKeySequence(QKeySequence.Back), self, lambda: search_history(None))
		forward = QShortcut(QKeySequence(QKeySequence.Forward), self, lambda: search_history(None, False))

		search_backbutton = QToolButton(self.toolbar)
		search_backbutton.setText(u'\u25C0')
		search_backbutton.setFixedWidth(15)
		search_backbutton.clicked.connect(search_history)
		self.search_backward = self.toolbar.addWidget(search_backbutton)
		self.search_backward.setVisible(False)
		search_forwardbutton = QToolButton(self.toolbar)
		search_forwardbutton.setText(u'\u25B6')
		search_forwardbutton.setFixedWidth(15)
		search_forwardbutton.clicked.connect(lambda: search_history(None, False))
		self.search_forward = self.toolbar.addWidget(search_forwardbutton)
		self.search_forward.setVisible(False)

		spacer_end = QWidget() # aligns settings action properly
		spacer_end.setFixedSize(QSize(10, 1))
		self.toolbar.addWidget(spacer_end)

		settings_act = QToolButton(self.toolbar)
		settings_act.setIcon(QIcon(app_constants.SETTINGS_PATH))
		settings_act.clicked.connect(self.settings)
		self.toolbar.addWidget(settings_act)

		spacer_end2 = QWidget() # aligns About action properly
		spacer_end2.setFixedSize(QSize(5, 1))
		self.toolbar.addWidget(spacer_end2)
		self.addToolBar(self.toolbar)

	def toggle_view(self):
		"""
		Toggles the current display view
		"""
		if self.display.currentIndex() == self.m_l_view_index:
			self.display.setCurrentIndex(self.m_t_view_index)
			self.grid_toggle.setIcon(self.grid_toggle_g_icon)
		else:
			self.display.setCurrentIndex(self.m_l_view_index)
			self.grid_toggle.setIcon(self.grid_toggle_l_icon)

	# TODO: Improve this so that it adds to the gallery dialog,
	# so user can edit data before inserting (make it a choice)
	def populate(self, mixed=None):
		"Populates the database with gallery from local drive'"
		if mixed:
			gallery_view = misc.GalleryListView(self, True)
			gallery_view.SERIES.connect(self.gallery_populate)
			gallery_view.show()
		else:
			msg_box = misc.BasePopup(self)
			l = QVBoxLayout()
			msg_box.main_widget.setLayout(l)
			l.addWidget(QLabel('Directory or Archive?'))
			l.addLayout(msg_box.buttons_layout)

			def from_dir():
				path = QFileDialog.getExistingDirectory(self, "Choose a directory containing your galleries")
				if not path:
					return
				msg_box.close()
				app_constants.OVERRIDE_SUBFOLDER_AS_GALLERY = True
				self.gallery_populate(path, True)
			def from_arch():
				path = QFileDialog.getOpenFileName(self, 'Choose an archive containing your galleries',
									   filter=utils.FILE_FILTER)
				path = [path[0]]
				if not all(path) or not path:
					return
				msg_box.close()
				app_constants.OVERRIDE_SUBFOLDER_AS_GALLERY = True
				self.gallery_populate(path, True)

			buttons = msg_box.add_buttons('Directory', 'Archive', 'Close')
			buttons[2].clicked.connect(msg_box.close)
			buttons[0].clicked.connect(from_dir)
			buttons[1].clicked.connect(from_arch)
			msg_box.adjustSize()
			msg_box.show()

	def gallery_populate(self, path, validate=False):
		"Scans the given path for gallery to add into the DB"
		if len(path) is not 0:
			data_thread = QThread(self)
			data_thread.setObjectName('General gallery populate')
			loading = misc.Loading(self)
			self.g_populate_inst = fetch.Fetch()
			self.g_populate_inst.series_path = path
			loading.show()

			def finished(status):
				def hide_loading():
					loading.hide()
				if status:
					if len(status) != 0:
						def add_gallery(gallery_list):
							def append_to_model(x):
								self.manga_list_view.sort_model.insertRows(x, None, len(x))
								self.manga_list_view.sort_model.init_search(
									self.manga_list_view.sort_model.current_term)

							class A(QObject):
								done = pyqtSignal()
								prog = pyqtSignal(int)
								def __init__(self, obj, parent=None):
									super().__init__(parent)
									self.obj = obj
									self.galleries = []

								def add_to_db(self):
									for y, x in enumerate(self.obj):
										gallerydb.add_method_queue(
											gallerydb.GalleryDB.add_gallery_return, False, x)
										self.galleries.append(x)
										y += 1
										self.prog.emit(y)
									append_to_model(self.galleries)
									self.done.emit()
							loading.progress.setMaximum(len(gallery_list))
							self.a_instance = A(gallery_list)
							thread = QThread(self)
							thread.setObjectName('Database populate')
							def loading_show(numb):
								if loading.isHidden():
									loading.show()
								loading.setText('Populating database ({}/{})\nPlease wait...'.format(
									numb, loading.progress.maximum()))
								loading.progress.setValue(numb)
								loading.show()

							def loading_hide():
								loading.close()
								self.manga_list_view.gallery_model.ROWCOUNT_CHANGE.emit()

							self.a_instance.moveToThread(thread)
							self.a_instance.prog.connect(loading_show)
							thread.started.connect(self.a_instance.add_to_db)
							self.a_instance.done.connect(loading_hide)
							self.a_instance.done.connect(self.a_instance.deleteLater)
							#a_instance.add_to_db()
							thread.finished.connect(thread.deleteLater)
							thread.start()
						#data_thread.quit
						hide_loading()
						log_i('Populating DB from gallery folder: OK')
						if validate:
							gallery_list = misc.GalleryListView(self)
							gallery_list.SERIES.connect(add_gallery)
							for ser in status:
								if ser.is_archive and app_constants.SUBFOLDER_AS_GALLERY:
									p = os.path.split(ser.path)[1]
									if ser.chapters[0].path:
										pt_in_arch = os.path.split(ser.path_in_archive)
										pt_in_arch = pt_in_arch[1] or pt_in_arch[0]
										text = '{}: {}'.format(p, pt_in_arch)
									else:
										text = p
									gallery_list.add_gallery(ser, text)
								else:
									gallery_list.add_gallery(ser, os.path.split(ser.path)[1])
							#self.manga_list_view.gallery_model.populate_data()
							gallery_list.update_count()
							gallery_list.show()
						else:
							add_gallery(status)
					else:
						log_d('No new gallery was found')
						loading.setText("No new gallery found")
						#data_thread.quit

				else:
					log_e('Populating DB from gallery folder: Nothing was added!')
					loading.setText("<font color=red>Nothing was added. Check happypanda_log for details..</font>")
					loading.progress.setStyleSheet("background-color:red;")
					data_thread.quit
					QTimer.singleShot(8000, loading.close)

			def skipped_gs(s_list):
				"Skipped galleries"
				msg_box = QMessageBox(self)
				msg_box.setIcon(QMessageBox.Question)
				msg_box.setText('Do you want to view skipped paths?')
				msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
				msg_box.setDefaultButton(QMessageBox.No)
				if msg_box.exec() == QMessageBox.Yes:
					list_wid = QTableWidget(self)
					list_wid.setAttribute(Qt.WA_DeleteOnClose)
					list_wid.setRowCount(len(s_list))
					list_wid.setColumnCount(2)
					list_wid.setAlternatingRowColors(True)
					list_wid.setEditTriggers(list_wid.NoEditTriggers)
					list_wid.setHorizontalHeaderLabels(['Reason', 'Path'])
					list_wid.setSelectionBehavior(list_wid.SelectRows)
					list_wid.setSelectionMode(list_wid.SingleSelection)
					list_wid.setSortingEnabled(True)
					list_wid.verticalHeader().hide()
					list_wid.setAutoScroll(False)
					for x, g in enumerate(s_list):
						list_wid.setItem(x, 0, QTableWidgetItem(g[1]))
						list_wid.setItem(x, 1, QTableWidgetItem(g[0]))
					list_wid.resizeColumnsToContents()
					list_wid.setWindowTitle('{} skipped paths'.format(len(s_list)))
					list_wid.setWindowFlags(Qt.Window)
					list_wid.resize(900,400)

					list_wid.doubleClicked.connect(lambda i: utils.open_path(
						list_wid.item(i.row(), 1).text(), list_wid.item(i.row(), 1).text()))

					list_wid.show()

			def a_progress(prog):
				loading.progress.setValue(prog)
				loading.setText("Preparing galleries...")

			self.g_populate_inst.moveToThread(data_thread)
			self.g_populate_inst.DATA_COUNT.connect(loading.progress.setMaximum)
			self.g_populate_inst.PROGRESS.connect(a_progress)
			self.g_populate_inst.FINISHED.connect(finished)
			self.g_populate_inst.FINISHED.connect(self.g_populate_inst.deleteLater)
			self.g_populate_inst.SKIPPED.connect(skipped_gs)
			data_thread.finished.connect(data_thread.deleteLater)
			data_thread.started.connect(self.g_populate_inst.local)
			data_thread.start()
			#.g_populate_inst.local()
			log_i('Populating DB from directory/archive')

	def scan_for_new_galleries(self):
		available_folders =  app_constants.ENABLE_MONITOR and\
									app_constants.MONITOR_PATHS and all(app_constants.MONITOR_PATHS)
		if available_folders and not app_constants.SCANNING_FOR_GALLERIES:
			app_constants.SCANNING_FOR_GALLERIES = True
			self.notification_bar.add_text("Scanning for new galleries...")
			log_i('Scanning for new galleries...')
			try:
				class ScanDir(QObject):
					final_paths_and_galleries = pyqtSignal(list, list)
					finished = pyqtSignal()
					def __init__(self, parent=None):
						super().__init__(parent)
						self.scanned_data = []
					def scan_dirs(self):
						paths = []
						for p in app_constants.MONITOR_PATHS:
							if os.path.exists(p):
								dir_content = scandir.scandir(p)
								for d in dir_content:
									paths.append(d.path)
							else:
								log_e("Monitored path does not exists: {}".format(p.encode(errors='ignore')))

						fetch_inst = fetch.Fetch(self)
						fetch_inst.series_path = paths
						def set_scanned_d(d):
							self.scanned_data = d
						fetch_inst.FINISHED.connect(set_scanned_d)
						fetch_inst.local()
						#contents = []
						#for g in self.scanned_data:
						#	contents.append(g)

						#paths = sorted(paths)
						#new_galleries = []
						#for x in contents:
						#	y = utils.b_search(paths, os.path.normcase(x.path))
						#	if not y:
						#		new_galleries.append(x)

						galleries = []
						final_paths = []
						if self.scanned_data:
							for g in self.scanned_data:
								try:
									if g.is_archive:
										g.profile = utils.get_gallery_img(g.chapters[0].path, g.path)
									else:
										g.profile = utils.get_gallery_img(g.chapters[0].path)
									if not g.profile:
										raise Exception
								except:
									g.profile = app_constants.NO_IMAGE_PATH
							
								galleries.append(g)
								final_paths.append(g.path)
						self.final_paths_and_galleries.emit(final_paths, galleries)
						self.finished.emit()
						self.deleteLater()
					#if app_constants.LOOK_NEW_GALLERY_AUTOADD:
					#	QTimer.singleShot(10000, self.gallery_populate(final_paths))
					#	return

				def show_new_galleries(final_paths, galleries):
					if final_paths and galleries:
						app_constants.OVERRIDE_MOVE_IMPORTED_IN_FETCH = True
						if app_constants.LOOK_NEW_GALLERY_AUTOADD:
							self.gallery_populate(final_paths)
						else:

							class NewGalleryMenu(QMenu):

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

									ignore_act = self.addAction('Add to ignore list')
									ignore_act.triggered.connect(self.add_to_ignore)

								def add_to_ignore(self):
									gallery = self.gallery_widget.gallery
									app_constants.IGNORE_PATHS.append(gallery.path)
									settings.set(app_constants.IGNORE_PATHS, 'Application', 'ignore paths')
									if self.gallery_widget.parent_widget.gallery_layout.count() == 1:
										self.gallery_widget.parent_widget.close()
									else:
										self.gallery_widget.close()

							if len(galleries) == 1:
								self.notification_bar.add_text("{} new gallery was discovered in one of your monitored directories".format(len(galleries)))
							else:
								self.notification_bar.add_text("{} new galleries were discovered in one of your monitored directories".format(len(galleries)))
							text = "These new galleries were discovered! Do you want to add them?"\
								if len(galleries) > 1 else "This new gallery was discovered! Do you want to add it?"
							g_popup = io_misc.GalleryPopup((text, galleries), self, NewGalleryMenu())
							buttons = g_popup.add_buttons('Add', 'Close')

							def populate_n_close():
								g_popup.close()
								self.gallery_populate(final_paths)
							buttons[0].clicked.connect(populate_n_close)
							buttons[1].clicked.connect(g_popup.close)

				def finished(): app_constants.SCANNING_FOR_GALLERIES = False

				thread = QThread(self)
				self.scan_inst = ScanDir()
				self.scan_inst.moveToThread(thread)
				self.scan_inst.final_paths_and_galleries.connect(show_new_galleries)
				self.scan_inst.finished.connect(finished)
				thread.started.connect(self.scan_inst.scan_dirs)
				#self.scan_inst.scan_dirs()
				thread.finished.connect(thread.deleteLater)
				thread.start()
			except:
				self.notification_bar.add_text('An error occured while attempting to scan for new galleries. Check happypanda.log.')
				log.exception('An error occured while attempting to scan for new galleries.')
				app_constants.SCANNING_FOR_GALLERIES = False

	def dragEnterEvent(self, event):
		if event.mimeData().hasUrls():
			event.acceptProposedAction()
		else:
			self.notification_bar.add_text('File is not supported')

	def dropEvent(self, event):
		acceptable = []
		unaccept = []
		for u in event.mimeData().urls():
			path = u.toLocalFile()
			if os.path.isdir(path) or path.endswith(utils.ARCHIVE_FILES):
				acceptable.append(path)
			else:
				unaccept.append(path)
		log_i('Acceptable dropped items: {}'.format(len(acceptable)))
		log_i('Unacceptable dropped items: {}'.format(len(unaccept)))
		log_d('Dropped items: {}\n{}'.format(acceptable, unaccept).encode(errors='ignore'))
		if acceptable:
			self.notification_bar.add_text('Adding dropped items...')
			log_i('Adding dropped items')
			l = len(acceptable) == 1
			f_item = acceptable[0]
			if f_item.endswith(utils.ARCHIVE_FILES):
				f_item = utils.check_archive(f_item)
			else:
				f_item = utils.recursive_gallery_check(f_item)
			f_item_l = len(f_item) < 2
			subfolder_as_c = not app_constants.SUBFOLDER_AS_GALLERY
			if l and subfolder_as_c or l and f_item_l:
				g_d = gallerydialog.GalleryDialog(self, acceptable[0])
				g_d.SERIES.connect(self.manga_list_view.gallery_model.addRows)
				g_d.show()
			else:
				self.gallery_populate(acceptable, True)
		else:
			text = 'File not supported' if len(unaccept) < 2 else 'Files not supported'
			self.notification_bar.add_text(text)

		if unaccept:
			self.notification_bar.add_text('Some unsupported files did not get added')

	def resizeEvent(self, event):
		try:
			self.notification_bar.resize(event.size().width())
		except AttributeError:
			pass
		self.move_listener.emit()
		return super().resizeEvent(event)

	def moveEvent(self, event):
		self.move_listener.emit()
		return super().moveEvent(event)

	def showEvent(self, event):
		return super().showEvent(event)

	def cleanup_exit(self):
		self.system_tray.hide()
		# watchers
		try:
			self.watchers.stop_all()
		except AttributeError:
			pass

		# settings
		settings.set(self.manga_list_view.current_sort, 'General', 'current sort')
		settings.set(app_constants.IGNORE_PATHS, 'Application', 'ignore paths')
		settings.win_save(self, 'AppWindow')

		# temp dir
		try:
			for root, dirs, files in scandir.walk('temp', topdown=False):
				for name in files:
					os.remove(os.path.join(root, name))
				for name in dirs:
					os.rmdir(os.path.join(root, name))
			log_d('Flush temp on exit: OK')
		except:
			log.exception('Flush temp on exit: FAIL')

		if self.tags_treeview:
			self.tags_treeview.close()
		self.download_window.close()

		# check if there is db activity
		if not gallerydb.method_queue.empty():
			class DBActivityChecker(QObject):
				FINISHED = pyqtSignal()
				def __init__(self, **kwargs):
					super().__init__(**kwargs)

				def check(self):
					gallerydb.method_queue.join()
					self.FINISHED.emit()
					self.deleteLater()

			db_activity = DBActivityChecker()
			db_spinner = misc.Spinner(self)
			self.db_activity_checker.connect(db_activity.check)
			db_activity.moveToThread(app_constants.GENERAL_THREAD)
			db_activity.FINISHED.connect(db_spinner.close)
			db_spinner.set_size(50)
			db_spinner.set_text('Activity')
			db_spinner.move(QPoint(self.pos().x()+self.width()-70, self.pos().y()+self.height()-70))
			self.move_listener.connect(lambda: db_spinner.update_move(QPoint(self.pos().x()+self.width()-70,
																	self.pos().y()+self.height()-70)))
			db_spinner.show()
			self.db_activity_checker.emit()
			msg_box = QMessageBox(self)
			msg_box.setText('Database activity detected!')
			msg_box.setInformativeText("Closing now might result in data loss." +
								 " Do you still want to close?\n(Wait for the activity spinner to hide before closing)")
			msg_box.setIcon(QMessageBox.Critical)
			msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
			msg_box.setDefaultButton(QMessageBox.No)
			if msg_box.exec() == QMessageBox.Yes:
				return 1
			else:
				return 2
		else:
			return 0

	def closeEvent(self, event):
		r_code = self.cleanup_exit()
		if r_code == 1:
			log_d('Force Exit App: OK')
			super().closeEvent(event)
		elif r_code == 2:
			log_d('Ignore Exit App')
			event.ignore()
		else:
			log_d('Normal Exit App: OK')
			super().closeEvent(event)
Beispiel #57
0
    def __init__(self, stampManager, parent = None):
        super().__init__(parent)
        
        self.mTileStampManager = stampManager
        self.mTileStampModel = stampManager.tileStampModel()
        self.mProxyModel = QSortFilterProxyModel(self.mTileStampModel)
        self.mFilterEdit = QLineEdit(self)
        self.mNewStamp = QAction(self)
        self.mAddVariation = QAction(self)
        self.mDuplicate = QAction(self)
        self.mDelete = QAction(self)
        self.mChooseFolder = QAction(self)

        self.setObjectName("TileStampsDock")
        self.mProxyModel.setSortLocaleAware(True)
        self.mProxyModel.setSortCaseSensitivity(Qt.CaseInsensitive)
        self.mProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.mProxyModel.setSourceModel(self.mTileStampModel)
        self.mProxyModel.sort(0)
        self.mTileStampView = TileStampView(self)
        self.mTileStampView.setModel(self.mProxyModel)
        self.mTileStampView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
        self.mTileStampView.header().setStretchLastSection(False)
        self.mTileStampView.header().setSectionResizeMode(0, QHeaderView.Stretch)
        self.mTileStampView.header().setSectionResizeMode(1, QHeaderView.ResizeToContents)
        self.mTileStampView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.mTileStampView.customContextMenuRequested.connect(self.showContextMenu)
        self.mNewStamp.setIcon(QIcon(":images/16x16/document-new.png"))
        self.mAddVariation.setIcon(QIcon(":/images/16x16/add.png"))
        self.mDuplicate.setIcon(QIcon(":/images/16x16/stock-duplicate-16.png"))
        self.mDelete.setIcon(QIcon(":images/16x16/edit-delete.png"))
        self.mChooseFolder.setIcon(QIcon(":images/16x16/document-open.png"))
        Utils.setThemeIcon(self.mNewStamp, "document-new")
        Utils.setThemeIcon(self.mAddVariation, "add")
        Utils.setThemeIcon(self.mDelete, "edit-delete")
        Utils.setThemeIcon(self.mChooseFolder, "document-open")

        self.mFilterEdit.setClearButtonEnabled(True)
        self.mFilterEdit.textChanged.connect(self.mProxyModel.setFilterFixedString)
        self.mTileStampModel.stampRenamed.connect(self.ensureStampVisible)
        self.mNewStamp.triggered.connect(self.newStamp)
        self.mAddVariation.triggered.connect(self.addVariation)
        self.mDuplicate.triggered.connect(self.duplicate)
        self.mDelete.triggered.connect(self.delete_)
        self.mChooseFolder.triggered.connect(self.chooseFolder)
        self.mDuplicate.setEnabled(False)
        self.mDelete.setEnabled(False)
        self.mAddVariation.setEnabled(False)
        widget = QWidget(self)
        layout = QVBoxLayout(widget)
        layout.setContentsMargins(5, 5, 5, 5)
        
        buttonContainer = QToolBar()
        buttonContainer.setFloatable(False)
        buttonContainer.setMovable(False)
        buttonContainer.setIconSize(QSize(16, 16))
        buttonContainer.addAction(self.mNewStamp)
        buttonContainer.addAction(self.mAddVariation)
        buttonContainer.addAction(self.mDuplicate)
        buttonContainer.addAction(self.mDelete)
        stretch = QWidget()
        stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        buttonContainer.addWidget(stretch)
        buttonContainer.addAction(self.mChooseFolder)
        listAndToolBar = QVBoxLayout()
        listAndToolBar.setSpacing(0)
        listAndToolBar.addWidget(self.mFilterEdit)
        listAndToolBar.addWidget(self.mTileStampView)
        listAndToolBar.addWidget(buttonContainer)
        layout.addLayout(listAndToolBar)
        selectionModel = self.mTileStampView.selectionModel()
        selectionModel.currentRowChanged.connect(self.currentRowChanged)
        self.setWidget(widget)
        self.retranslateUi()