Пример #1
0
    class LineEdit(QLineEdit):
        def __init__(self, *args, **kwargs):
            super(LineEdit, self).__init__(*args, **kwargs)
            self.clearButton = QToolButton(self)
            icon = complete_icon("fileclose")
            self.clearButton.setIcon(icon)
            self.clearButton.setIconSize(icon.pixmap(QSize(16, 16)).size())
            self.clearButton.setCursor(Qt.ArrowCursor)
            self.clearButton.setStyleSheet("QToolButton { border: none; padding: 0px; }")
            self.clearButton.hide()
            self.clearButton.clicked.connect(self.clear)
            self.textChanged.connect(self.updateCloseButton)
            frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
            self.setStyleSheet("QLineEdit { padding-right: %spx; }" % (self.clearButton.sizeHint().width() + frameWidth + 1,))
            msz = self.minimumSizeHint()
            self.setMinimumSize(max(msz.width(), self.clearButton.sizeHint().height() + frameWidth * 2 + 2),
                       max(msz.height(), self.clearButton.sizeHint().height() + frameWidth * 2 + 2));

        def resizeEvent(self, *args, **kwargs):
            super(LineEdit, self).resizeEvent(*args, **kwargs)
            sz = self.clearButton.sizeHint()
            frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
            self.clearButton.move(self.rect().right() - frameWidth - sz.width(),
                          (self.rect().bottom() + 1 - sz.height())/2)

        def updateCloseButton(self, text):
            self.clearButton.setVisible(text != "")
Пример #2
0
    class LineEdit(QLineEdit):
        def __init__(self, *args, **kwargs):
            super(LineEdit, self).__init__(*args, **kwargs)
            self.clearButton = QToolButton(self)
            icon = complete_icon("fileclose")
            self.clearButton.setIcon(icon)
            self.clearButton.setIconSize(icon.pixmap(QSize(16, 16)).size())
            self.clearButton.setCursor(Qt.ArrowCursor)
            self.clearButton.setStyleSheet(
                "QToolButton { border: none; padding: 0px; }")
            self.clearButton.hide()
            self.clearButton.clicked.connect(self.clear)
            self.textChanged.connect(self.updateCloseButton)
            frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
            self.setStyleSheet(
                "QLineEdit { padding-right: %spx; }" %
                (self.clearButton.sizeHint().width() + frameWidth + 1, ))
            msz = self.minimumSizeHint()
            self.setMinimumSize(
                max(msz.width(),
                    self.clearButton.sizeHint().height() + frameWidth * 2 + 2),
                max(msz.height(),
                    self.clearButton.sizeHint().height() + frameWidth * 2 + 2))

        def resizeEvent(self, *args, **kwargs):
            super(LineEdit, self).resizeEvent(*args, **kwargs)
            sz = self.clearButton.sizeHint()
            frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth)
            self.clearButton.move(
                self.rect().right() - frameWidth - sz.width(),
                (self.rect().bottom() + 1 - sz.height()) / 2)

        def updateCloseButton(self, text):
            self.clearButton.setVisible(text != "")
Пример #3
0
class QToolWindowTabBar ( QTabBar ):

	def __init__ ( self, parent = None ):
		QTabBar.__init__ ( self, parent )
		self.tabSelectionButton = QToolButton ( self )
		self.tabSelectionMenu = QTabSelectionMenu ( self.tabSelectionButton, self )

		self.tabSelectionButton.setEnabled ( True )
		self.tabSelectionButton.setIcon ( QIcon ( "./resources/general_pointer_down_expanded.ico" ) )  # TODO: CryIcon
		self.tabSelectionButton.setMenu ( self.tabSelectionMenu )
		self.tabSelectionButton.setPopupMode ( QToolButton.InstantPopup )

		styleSheet = f"QToolWindowArea > QTabBar::scroller{{ width: {self.tabSelectionButton.sizeHint ().width () / 2}px; }}"
		# print ( "QToolWindowTabBar", styleSheet )
		self.setStyleSheet ( styleSheet )
		self.tabSelectionMenu.aboutToShow.connect ( self.onSelectionMenuClicked )

	def paintEvent ( self, e ):
		QTabBar.paintEvent ( self, e )
		tabbarRect = self.rect ()
		if not tabbarRect.contains ( self.tabRect ( self.count () - 1 ) ) or not tabbarRect.contains (
				self.tabRect ( 0 ) ):
			self.tabSelectionButton.show ()
			self.tabSelectionButton.raise_ ()
			rect = self.contentsRect ()
			size = self.tabSelectionButton.sizeHint ()
			self.tabSelectionButton.move ( QPoint ( rect.width () - self.tabSelectionButton.width (), 0 ) )
		else:
			self.tabSelectionButton.hide ()

	def onSelectionMenuClicked ( self ):
		signalMapper = QSignalMapper ( self )
		acts = self.tabSelectionMenu.actions ()
		activeAction = self.currentIndex ()

		for i in range ( 0, acts.size () ):
			self.tabSelectionMenu.removeAction ( acts[ i ] )

		for i in range ( 0, self.count () ):
			action = self.tabSelectionMenu.addAction ( self.tabText ( i ) )
			action.triggered.connect ( signalMapper.map )
			signalMapper.setMapping ( action, i )

		if activeAction >= 0:
			acts = self.tabSelectionMenu.actions ()
			acts[ activeAction ].setIcon ( QIcon ( "./resources/general_tick.ico" ) )  # TODO: CryIcon

		signalMapper.mapped.connect ( self.setCurrentIndex )
Пример #4
0
class ColourPicker(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.pick_button = QToolButton(self)
        self.pick_button.setText('Pick...')
        self.clear_button = QToolButton(self)
        self.clear_button.setText('Clear')
        self.clear_button.setAutoRaise(True)
        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.pick_button)
        layout.addWidget(self.clear_button)
        self.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.colour_choice = None
        self.clear_button.clicked.connect(self.clearColour)
        self.pick_button.clicked.connect(self.pickNewColour)
        self.updateColourIcon()

    def updateColourIcon(self):
        if self.colour_choice == None:
            self.pick_button.setIcon(QIcon())
            self.clear_button.hide()
        else:
            self.pick_button.setIcon(coloured_square_icon(self.colour_choice))
            self.clear_button.show()

    def setChoice(self, colour):
        self.colour_choice = colour
        self.updateColourIcon()

    def getChoice(self):
        return self.colour_choice

    def pickNewColour(self):
        colour = QColorDialog.getColor(parent=self,
                                       title='Pick radar contact colour',
                                       initial=some(self.colour_choice,
                                                    Qt.white))
        if colour.isValid():
            self.setChoice(colour)

    def clearColour(self):
        self.colour_choice = None
        self.updateColourIcon()
Пример #5
0
class ObjectActionsWidget(QWidget):
    def __init__(self, treeItem, obj, parent=None):
        super().__init__(parent)

        self.sDownload = AsyncSignal()

        self.treeItem = treeItem
        self.obj = obj
        self.ipfsPath = IPFSPath(self.obj.get('path'))

        self.hlayout = QHBoxLayout(self)
        self.setLayout(self.hlayout)

        self.btnOpen = QPushButton(iOpen())
        self.btnOpen.setText(iOpen())
        self.btnOpen.setIcon(getIcon('open.png'))
        self.btnOpen.clicked.connect(partialEnsure(self.onOpen))

        self.btnHashmark = HashmarkThisButton(self.ipfsPath)
        self.btnClipboard = IPFSPathClipboardButton(self.ipfsPath)

        self.btnDownload = QToolButton(self)
        self.btnDownload.setText('Download')
        self.btnDownload.clicked.connect(self.onDl)
        self.btnDownload.hide()

        self.hlayout.addWidget(self.btnClipboard)
        self.hlayout.addWidget(self.btnHashmark)
        self.hlayout.addWidget(self.btnOpen)
        self.hlayout.addWidget(self.btnDownload)

    def fLayout(self):
        self.hlayout.addItem(
            QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum))

    def onDl(self):
        ensure(self.sDownload.emit())

    def showControls(self, download=False):
        self.btnDownload.setVisible(download)

    async def onOpen(self, *a):
        app = QApplication.instance()
        ensure(app.resourceOpener.open(self.obj['path']))
Пример #6
0
class HelpTabWidget(E5TabWidget):
    """
    Class implementing the central widget showing the web pages.
    
    @signal sourceChanged(HelpBrowser, QUrl) emitted after the URL of a browser
        has changed
    @signal titleChanged(HelpBrowser, str) emitted after the title of a browser
        has changed
    @signal showMessage(str) emitted to show a message in the main window
        status bar
    @signal browserClosed(QWidget) emitted after a browser was closed
    @signal browserZoomValueChanged(int) emitted to signal a change of the
        current browser's zoom level
    """
    sourceChanged = pyqtSignal(HelpBrowser, QUrl)
    titleChanged = pyqtSignal(HelpBrowser, str)
    showMessage = pyqtSignal(str)
    browserClosed = pyqtSignal(QWidget)
    browserZoomValueChanged = pyqtSignal(int)
    
    def __init__(self, parent):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        E5TabWidget.__init__(self, parent, dnd=True)
        
        from .HelpTabBar import HelpTabBar
        self.__tabBar = HelpTabBar(self)
        self.setCustomTabBar(True, self.__tabBar)
        
        self.__mainWindow = parent
        
        self.setUsesScrollButtons(True)
        self.setDocumentMode(True)
        self.setElideMode(Qt.ElideNone)
        
        from .ClosedTabsManager import ClosedTabsManager
        self.__closedTabsManager = ClosedTabsManager(self)
        self.__closedTabsManager.closedTabAvailable.connect(
            self.__closedTabAvailable)
        
        from .UrlBar.StackedUrlBar import StackedUrlBar
        self.__stackedUrlBar = StackedUrlBar(self)
        self.__tabBar.tabMoved.connect(self.__stackedUrlBar.moveBar)
        
        self.__tabContextMenuIndex = -1
        self.currentChanged[int].connect(self.__currentChanged)
        self.setTabContextMenuPolicy(Qt.CustomContextMenu)
        self.customTabContextMenuRequested.connect(self.__showContextMenu)
        
        self.__rightCornerWidget = QWidget(self)
        self.__rightCornerWidgetLayout = QHBoxLayout(self.__rightCornerWidget)
        self.__rightCornerWidgetLayout.setContentsMargins(0, 0, 0, 0)
        self.__rightCornerWidgetLayout.setSpacing(0)
        
        self.__navigationMenu = QMenu(self)
        self.__navigationMenu.aboutToShow.connect(self.__showNavigationMenu)
        self.__navigationMenu.triggered.connect(self.__navigationMenuTriggered)
        
        self.__navigationButton = QToolButton(self)
        self.__navigationButton.setIcon(
            UI.PixmapCache.getIcon("1downarrow.png"))
        self.__navigationButton.setToolTip(
            self.tr("Show a navigation menu"))
        self.__navigationButton.setPopupMode(QToolButton.InstantPopup)
        self.__navigationButton.setMenu(self.__navigationMenu)
        self.__navigationButton.setEnabled(False)
        self.__rightCornerWidgetLayout.addWidget(self.__navigationButton)
        
        self.__closedTabsMenu = QMenu(self)
        self.__closedTabsMenu.aboutToShow.connect(
            self.__aboutToShowClosedTabsMenu)
        
        self.__closedTabsButton = QToolButton(self)
        self.__closedTabsButton.setIcon(UI.PixmapCache.getIcon("trash.png"))
        self.__closedTabsButton.setToolTip(
            self.tr("Show a navigation menu for closed tabs"))
        self.__closedTabsButton.setPopupMode(QToolButton.InstantPopup)
        self.__closedTabsButton.setMenu(self.__closedTabsMenu)
        self.__closedTabsButton.setEnabled(False)
        self.__rightCornerWidgetLayout.addWidget(self.__closedTabsButton)
        
        self.__closeButton = QToolButton(self)
        self.__closeButton.setIcon(UI.PixmapCache.getIcon("close.png"))
        self.__closeButton.setToolTip(
            self.tr("Close the current help window"))
        self.__closeButton.setEnabled(False)
        self.__closeButton.clicked[bool].connect(self.closeBrowser)
        self.__rightCornerWidgetLayout.addWidget(self.__closeButton)
        if Preferences.getUI("SingleCloseButton") or \
           not hasattr(self, 'setTabsClosable'):
            self.__closeButton.show()
        else:
            self.setTabsClosable(True)
            self.tabCloseRequested.connect(self.closeBrowserAt)
            self.__closeButton.hide()
        
        self.setCornerWidget(self.__rightCornerWidget, Qt.TopRightCorner)
        
        self.__newTabButton = QToolButton(self)
        self.__newTabButton.setIcon(UI.PixmapCache.getIcon("plus.png"))
        self.__newTabButton.setToolTip(
            self.tr("Open a new help window tab"))
        self.setCornerWidget(self.__newTabButton, Qt.TopLeftCorner)
        self.__newTabButton.clicked[bool].connect(self.newBrowser)
        
        self.__initTabContextMenu()
        
        self.__historyCompleter = None
    
    def __initTabContextMenu(self):
        """
        Private method to create the tab context menu.
        """
        self.__tabContextMenu = QMenu(self)
        self.tabContextNewAct = self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("tabNew.png"),
            self.tr('New Tab'), self.newBrowser)
        self.__tabContextMenu.addSeparator()
        self.leftMenuAct = self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("1leftarrow.png"),
            self.tr('Move Left'), self.__tabContextMenuMoveLeft)
        self.rightMenuAct = self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("1rightarrow.png"),
            self.tr('Move Right'), self.__tabContextMenuMoveRight)
        self.__tabContextMenu.addSeparator()
        self.tabContextCloneAct = self.__tabContextMenu.addAction(
            self.tr("Duplicate Page"), self.__tabContextMenuClone)
        self.__tabContextMenu.addSeparator()
        self.tabContextCloseAct = self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("tabClose.png"),
            self.tr('Close'), self.__tabContextMenuClose)
        self.tabContextCloseOthersAct = self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("tabCloseOther.png"),
            self.tr("Close Others"), self.__tabContextMenuCloseOthers)
        self.__tabContextMenu.addAction(
            self.tr('Close All'), self.closeAllBrowsers)
        self.__tabContextMenu.addSeparator()
        self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("printPreview.png"),
            self.tr('Print Preview'), self.__tabContextMenuPrintPreview)
        self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("print.png"),
            self.tr('Print'), self.__tabContextMenuPrint)
        self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("printPdf.png"),
            self.tr('Print as PDF'), self.__tabContextMenuPrintPdf)
        self.__tabContextMenu.addSeparator()
        self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("reload.png"),
            self.tr('Reload All'), self.reloadAllBrowsers)
        self.__tabContextMenu.addSeparator()
        self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("addBookmark.png"),
            self.tr('Bookmark All Tabs'), self.__mainWindow.bookmarkAll)
        
        self.__tabBackContextMenu = QMenu(self)
        self.__tabBackContextMenu.addAction(
            self.tr('Close All'), self.closeAllBrowsers)
        self.__tabBackContextMenu.addAction(
            UI.PixmapCache.getIcon("reload.png"),
            self.tr('Reload All'), self.reloadAllBrowsers)
        self.__tabBackContextMenu.addAction(
            UI.PixmapCache.getIcon("addBookmark.png"),
            self.tr('Bookmark All Tabs'), self.__mainWindow.bookmarkAll)
        self.__tabBackContextMenu.addSeparator()
        self.__restoreClosedTabAct = self.__tabBackContextMenu.addAction(
            UI.PixmapCache.getIcon("trash.png"),
            self.tr('Restore Closed Tab'), self.restoreClosedTab)
        self.__restoreClosedTabAct.setEnabled(False)
        self.__restoreClosedTabAct.setData(0)
    
    def __showContextMenu(self, coord, index):
        """
        Private slot to show the tab context menu.
        
        @param coord the position of the mouse pointer (QPoint)
        @param index index of the tab the menu is requested for (integer)
        """
        coord = self.mapToGlobal(coord)
        if index == -1:
            self.__tabBackContextMenu.popup(coord)
        else:
            self.__tabContextMenuIndex = index
            self.leftMenuAct.setEnabled(index > 0)
            self.rightMenuAct.setEnabled(index < self.count() - 1)
            
            self.tabContextCloseOthersAct.setEnabled(self.count() > 1)
            
            self.__tabContextMenu.popup(coord)
    
    def __tabContextMenuMoveLeft(self):
        """
        Private method to move a tab one position to the left.
        """
        self.moveTab(self.__tabContextMenuIndex,
                     self.__tabContextMenuIndex - 1)
    
    def __tabContextMenuMoveRight(self):
        """
        Private method to move a tab one position to the right.
        """
        self.moveTab(self.__tabContextMenuIndex,
                     self.__tabContextMenuIndex + 1)
    
    def __tabContextMenuClone(self):
        """
        Private method to clone the selected tab.
        """
        idx = self.__tabContextMenuIndex
        if idx < 0:
            idx = self.currentIndex()
        if idx < 0 or idx > self.count():
            return
        
        req = QNetworkRequest(self.widget(idx).url())
        req.setRawHeader(b"X-Eric6-UserLoadAction", b"1")
        self.newBrowser(None, (req, QNetworkAccessManager.GetOperation, b""))
    
    def __tabContextMenuClose(self):
        """
        Private method to close the selected tab.
        """
        self.closeBrowserAt(self.__tabContextMenuIndex)
    
    def __tabContextMenuCloseOthers(self):
        """
        Private slot to close all other tabs.
        """
        index = self.__tabContextMenuIndex
        for i in list(range(self.count() - 1, index, -1)) + \
                list(range(index - 1, -1, -1)):
            self.closeBrowserAt(i)
    
    def __tabContextMenuPrint(self):
        """
        Private method to print the selected tab.
        """
        browser = self.widget(self.__tabContextMenuIndex)
        self.printBrowser(browser)
    
    def __tabContextMenuPrintPdf(self):
        """
        Private method to print the selected tab as PDF.
        """
        browser = self.widget(self.__tabContextMenuIndex)
        self.printBrowserPdf(browser)
    
    def __tabContextMenuPrintPreview(self):
        """
        Private method to show a print preview of the selected tab.
        """
        browser = self.widget(self.__tabContextMenuIndex)
        self.printPreviewBrowser(browser)
    
    def newBrowser(self, link=None, requestData=None, position=-1):
        """
        Public method to create a new web browser tab.
        
        @param link link to be shown (string or QUrl)
        @param requestData tuple containing the request data (QNetworkRequest,
            QNetworkAccessManager.Operation, QByteArray)
        @keyparam position position to create the new tab at or -1 to add it
            to the end (integer)
        """
        if link is None:
            linkName = ""
        elif isinstance(link, QUrl):
            linkName = link.toString()
        else:
            linkName = link
        
        from .UrlBar.UrlBar import UrlBar
        urlbar = UrlBar(self.__mainWindow, self)
        if self.__historyCompleter is None:
            import Helpviewer.HelpWindow
            from .History.HistoryCompleter import HistoryCompletionModel, \
                HistoryCompleter
            self.__historyCompletionModel = HistoryCompletionModel(self)
            self.__historyCompletionModel.setSourceModel(
                Helpviewer.HelpWindow.HelpWindow.historyManager()
                .historyFilterModel())
            self.__historyCompleter = HistoryCompleter(
                self.__historyCompletionModel, self)
            self.__historyCompleter.activated[str].connect(self.__pathSelected)
        urlbar.setCompleter(self.__historyCompleter)
        urlbar.returnPressed.connect(self.__lineEditReturnPressed)
        if position == -1:
            self.__stackedUrlBar.addWidget(urlbar)
        else:
            self.__stackedUrlBar.insertWidget(position, urlbar)
        
        browser = HelpBrowser(self.__mainWindow, self)
        urlbar.setBrowser(browser)
        
        browser.sourceChanged.connect(self.__sourceChanged)
        browser.titleChanged.connect(self.__titleChanged)
        browser.highlighted.connect(self.showMessage)
        browser.backwardAvailable.connect(
            self.__mainWindow.setBackwardAvailable)
        browser.forwardAvailable.connect(self.__mainWindow.setForwardAvailable)
        browser.loadStarted.connect(self.__loadStarted)
        browser.loadFinished.connect(self.__loadFinished)
        browser.iconChanged.connect(self.__iconChanged)
        browser.search.connect(self.newBrowser)
        browser.page().windowCloseRequested.connect(
            self.__windowCloseRequested)
        browser.page().printRequested.connect(self.__printRequested)
        browser.zoomValueChanged.connect(self.browserZoomValueChanged)
        
        if position == -1:
            index = self.addTab(browser, self.tr("..."))
        else:
            index = self.insertTab(position, browser, self.tr("..."))
        self.setCurrentIndex(index)
        
        self.__mainWindow.closeAct.setEnabled(True)
        self.__mainWindow.closeAllAct.setEnabled(True)
        self.__closeButton.setEnabled(True)
        self.__navigationButton.setEnabled(True)
        
        if not linkName and not requestData:
            if Preferences.getHelp("StartupBehavior") == 0:
                linkName = Preferences.getHelp("HomePage")
            elif Preferences.getHelp("StartupBehavior") == 1:
                linkName = "eric:speeddial"
        
        if linkName:
            browser.setSource(QUrl(linkName))
            if not browser.documentTitle():
                self.setTabText(index, self.__elide(linkName, Qt.ElideMiddle))
                self.setTabToolTip(index, linkName)
            else:
                self.setTabText(
                    index,
                    self.__elide(browser.documentTitle().replace("&", "&&")))
                self.setTabToolTip(index, browser.documentTitle())
        elif requestData:
            browser.load(*requestData)
    
    def newBrowserAfter(self, browser, link=None, requestData=None):
        """
        Public method to create a new web browser tab after a given one.
        
        @param browser reference to the browser to add after (HelpBrowser)
        @param link link to be shown (string or QUrl)
        @param requestData tuple containing the request data (QNetworkRequest,
            QNetworkAccessManager.Operation, QByteArray)
        """
        if browser:
            position = self.indexOf(browser) + 1
        else:
            position = -1
        self.newBrowser(link, requestData, position)
    
    def __showNavigationMenu(self):
        """
        Private slot to show the navigation button menu.
        """
        self.__navigationMenu.clear()
        for index in range(self.count()):
            act = self.__navigationMenu.addAction(
                self.tabIcon(index), self.tabText(index))
            act.setData(index)
    
    def __navigationMenuTriggered(self, act):
        """
        Private slot called to handle the navigation button menu selection.
        
        @param act reference to the selected action (QAction)
        """
        index = act.data()
        if index is not None:
            self.setCurrentIndex(index)
    
    def __windowCloseRequested(self):
        """
        Private slot to handle the windowCloseRequested signal of a browser.
        """
        page = self.sender()
        if page is None:
            return
        
        browser = page.view()
        if browser is None:
            return
        
        index = self.indexOf(browser)
        self.closeBrowserAt(index)
    
    def reloadAllBrowsers(self):
        """
        Public slot to reload all browsers.
        """
        for index in range(self.count()):
            browser = self.widget(index)
            browser and browser.reload()
    
    def closeBrowser(self):
        """
        Public slot called to handle the close action.
        """
        self.closeBrowserAt(self.currentIndex())
    
    def closeAllBrowsers(self):
        """
        Public slot called to handle the close all action.
        """
        for index in range(self.count() - 1, -1, -1):
            self.closeBrowserAt(index)
    
    def closeBrowserAt(self, index):
        """
        Public slot to close a browser based on its index.
        
        @param index index of browser to close (integer)
        """
        browser = self.widget(index)
        if browser is None:
            return
        
        if browser.isModified():
            ok = E5MessageBox.yesNo(
                self,
                self.tr("Do you really want to close this page?"),
                self.tr("""You have modified this page and when closing it"""
                        """ you would lose the modification.\nDo you really"""
                        """ want to close this page?"""))
            if not ok:
                return
        
        urlbar = self.__stackedUrlBar.widget(index)
        self.__stackedUrlBar.removeWidget(urlbar)
        urlbar.deleteLater()
        del urlbar
        
        self.__closedTabsManager.recordBrowser(browser, index)
        
        browser.closeWebInspector()
        browser.home()
        self.removeTab(index)
        self.browserClosed.emit(browser)
        browser.deleteLater()
        del browser
        
        if self.count() == 0:
            self.newBrowser()
        else:
            self.currentChanged[int].emit(self.currentIndex())
    
    def currentBrowser(self):
        """
        Public method to get a reference to the current browser.
        
        @return reference to the current browser (HelpBrowser)
        """
        return self.currentWidget()
    
    def browserAt(self, index):
        """
        Public method to get a reference to the browser with the given index.
        
        @param index index of the browser to get (integer)
        @return reference to the indexed browser (HelpBrowser)
        """
        return self.widget(index)
    
    def browsers(self):
        """
        Public method to get a list of references to all browsers.
        
        @return list of references to browsers (list of HelpBrowser)
        """
        li = []
        for index in range(self.count()):
            li.append(self.widget(index))
        return li
    
    @pyqtSlot()
    def printBrowser(self, browser=None):
        """
        Public slot called to print the displayed page.
        
        @param browser reference to the browser to be printed (HelpBrowser)
        """
        if browser is None:
            browser = self.currentBrowser()
        
        self.__printRequested(browser.page().mainFrame())
    
    def __printRequested(self, frame):
        """
        Private slot to handle a print request.
        
        @param frame reference to the frame to be printed (QWebFrame)
        """
        printer = QPrinter(mode=QPrinter.HighResolution)
        if Preferences.getPrinter("ColorMode"):
            printer.setColorMode(QPrinter.Color)
        else:
            printer.setColorMode(QPrinter.GrayScale)
        if Preferences.getPrinter("FirstPageFirst"):
            printer.setPageOrder(QPrinter.FirstPageFirst)
        else:
            printer.setPageOrder(QPrinter.LastPageFirst)
        printer.setPageMargins(
            Preferences.getPrinter("LeftMargin") * 10,
            Preferences.getPrinter("TopMargin") * 10,
            Preferences.getPrinter("RightMargin") * 10,
            Preferences.getPrinter("BottomMargin") * 10,
            QPrinter.Millimeter
        )
        printerName = Preferences.getPrinter("PrinterName")
        if printerName:
            printer.setPrinterName(printerName)
        
        printDialog = QPrintDialog(printer, self)
        if printDialog.exec_() == QDialog.Accepted:
            try:
                frame.print_(printer)
            except AttributeError:
                E5MessageBox.critical(
                    self,
                    self.tr("eric6 Web Browser"),
                    self.tr(
                        """<p>Printing is not available due to a bug in"""
                        """ PyQt5. Please upgrade.</p>"""))
                return
    
    @pyqtSlot()
    def printBrowserPdf(self, browser=None):
        """
        Public slot called to print the displayed page to PDF.
        
        @param browser reference to the browser to be printed (HelpBrowser)
        """
        if browser is None:
            browser = self.currentBrowser()
        
        self.__printPdfRequested(browser.page().mainFrame())
    
    def __printPdfRequested(self, frame):
        """
        Private slot to handle a print to PDF request.
        
        @param frame reference to the frame to be printed (QWebFrame)
        """
        printer = QPrinter(mode=QPrinter.HighResolution)
        if Preferences.getPrinter("ColorMode"):
            printer.setColorMode(QPrinter.Color)
        else:
            printer.setColorMode(QPrinter.GrayScale)
        printerName = Preferences.getPrinter("PrinterName")
        if printerName:
            printer.setPrinterName(printerName)
        printer.setOutputFormat(QPrinter.PdfFormat)
        name = frame.url().path().rsplit('/', 1)[-1]
        if name:
            name = name.rsplit('.', 1)[0]
            name += '.pdf'
            printer.setOutputFileName(name)
        
        printDialog = QPrintDialog(printer, self)
        if printDialog.exec_() == QDialog.Accepted:
            try:
                frame.print_(printer)
            except AttributeError:
                E5MessageBox.critical(
                    self,
                    self.tr("eric6 Web Browser"),
                    self.tr(
                        """<p>Printing is not available due to a bug in"""
                        """ PyQt5. Please upgrade.</p>"""))
                return
    
    @pyqtSlot()
    def printPreviewBrowser(self, browser=None):
        """
        Public slot called to show a print preview of the displayed file.
        
        @param browser reference to the browser to be printed (HelpBrowserWV)
        """
        from PyQt5.QtPrintSupport import QPrintPreviewDialog
        
        if browser is None:
            browser = self.currentBrowser()
        
        printer = QPrinter(mode=QPrinter.HighResolution)
        if Preferences.getPrinter("ColorMode"):
            printer.setColorMode(QPrinter.Color)
        else:
            printer.setColorMode(QPrinter.GrayScale)
        if Preferences.getPrinter("FirstPageFirst"):
            printer.setPageOrder(QPrinter.FirstPageFirst)
        else:
            printer.setPageOrder(QPrinter.LastPageFirst)
        printer.setPageMargins(
            Preferences.getPrinter("LeftMargin") * 10,
            Preferences.getPrinter("TopMargin") * 10,
            Preferences.getPrinter("RightMargin") * 10,
            Preferences.getPrinter("BottomMargin") * 10,
            QPrinter.Millimeter
        )
        printerName = Preferences.getPrinter("PrinterName")
        if printerName:
            printer.setPrinterName(printerName)
        
        self.__printPreviewBrowser = browser
        preview = QPrintPreviewDialog(printer, self)
        preview.paintRequested.connect(self.__printPreview)
        preview.exec_()
    
    def __printPreview(self, printer):
        """
        Private slot to generate a print preview.
        
        @param printer reference to the printer object (QPrinter)
        """
        try:
            self.__printPreviewBrowser.print_(printer)
        except AttributeError:
            E5MessageBox.critical(
                self,
                self.tr("eric6 Web Browser"),
                self.tr(
                    """<p>Printing is not available due to a bug in PyQt5."""
                    """Please upgrade.</p>"""))
            return
    
    def __sourceChanged(self, url):
        """
        Private slot to handle a change of a browsers source.
        
        @param url URL of the new site (QUrl)
        """
        browser = self.sender()
        
        if browser is not None:
            self.sourceChanged.emit(browser, url)
    
    def __titleChanged(self, title):
        """
        Private slot to handle a change of a browsers title.
        
        @param title new title (string)
        """
        browser = self.sender()
        
        if browser is not None and isinstance(browser, QWidget):
            index = self.indexOf(browser)
            if title == "":
                title = browser.url().toString()
            
            self.setTabText(index, self.__elide(title.replace("&", "&&")))
            self.setTabToolTip(index, title)
        
            self.titleChanged.emit(browser, title)
    
    def __elide(self, txt, mode=Qt.ElideRight, length=40):
        """
        Private method to elide some text.
        
        @param txt text to be elided (string)
        @keyparam mode elide mode (Qt.TextElideMode)
        @keyparam length amount of characters to be used (integer)
        @return the elided text (string)
        """
        if mode == Qt.ElideNone or len(txt) < length:
            return txt
        elif mode == Qt.ElideLeft:
            return "...{0}".format(txt[-length:])
        elif mode == Qt.ElideMiddle:
            return "{0}...{1}".format(txt[:length // 2], txt[-(length // 2):])
        elif mode == Qt.ElideRight:
            return "{0}...".format(txt[:length])
        else:
            # just in case
            return txt
    
    def preferencesChanged(self):
        """
        Public slot to handle a change of preferences.
        """
        for browser in self.browsers():
            browser.preferencesChanged()
        
        for urlbar in self.__stackedUrlBar.urlBars():
            urlbar.preferencesChanged()
        
        if Preferences.getUI("SingleCloseButton") or \
           not hasattr(self, 'setTabsClosable'):
            if hasattr(self, 'setTabsClosable'):
                self.setTabsClosable(False)
                try:
                    self.tabCloseRequested.disconnect(self.closeBrowserAt)
                except TypeError:
                    pass
            self.__closeButton.show()
        else:
            self.setTabsClosable(True)
            self.tabCloseRequested.connect(self.closeBrowserAt)
            self.__closeButton.hide()
    
    def __loadStarted(self):
        """
        Private method to handle the loadStarted signal.
        """
        browser = self.sender()
        
        if browser is not None:
            index = self.indexOf(browser)
            anim = self.animationLabel(
                index, os.path.join(getConfig("ericPixDir"), "loading.gif"),
                100)
            if not anim:
                loading = QIcon(os.path.join(getConfig("ericPixDir"),
                                "loading.gif"))
                self.setTabIcon(index, loading)
            else:
                self.setTabIcon(index, QIcon())
            self.setTabText(index, self.tr("Loading..."))
            self.setTabToolTip(index, self.tr("Loading..."))
            self.showMessage.emit(self.tr("Loading..."))
            
            self.__mainWindow.setLoadingActions(True)
    
    def __loadFinished(self, ok):
        """
        Private method to handle the loadFinished signal.
        
        @param ok flag indicating the result (boolean)
        """
        browser = self.sender()
        if not isinstance(browser, HelpBrowser):
            return
        
        if browser is not None:
            import Helpviewer.HelpWindow
            index = self.indexOf(browser)
            self.resetAnimation(index)
            self.setTabIcon(
                index, Helpviewer.HelpWindow.HelpWindow.icon(browser.url()))
            if ok:
                self.showMessage.emit(self.tr("Finished loading"))
            else:
                self.showMessage.emit(self.tr("Failed to load"))
            
            self.__mainWindow.setLoadingActions(False)
    
    def __iconChanged(self):
        """
        Private slot to handle the icon change.
        """
        browser = self.sender()
        
        if browser is not None and isinstance(browser, QWidget):
            import Helpviewer.HelpWindow
            self.setTabIcon(
                self.indexOf(browser),
                Helpviewer.HelpWindow.HelpWindow.icon(browser.url()))
            Helpviewer.HelpWindow.HelpWindow.bookmarksManager()\
                .iconChanged(browser.url())
    
    def getSourceFileList(self):
        """
        Public method to get a list of all opened source files.
        
        @return dictionary with tab id as key and host/namespace as value
        """
        sourceList = {}
        for i in range(self.count()):
            browser = self.widget(i)
            if browser is not None and \
               browser.source().isValid():
                sourceList[i] = browser.source().host()
        
        return sourceList
    
    def shallShutDown(self):
        """
        Public method to check, if the application should be shut down.
        
        @return flag indicating a shut down (boolean)
        """
        if self.count() > 1 and Preferences.getHelp("WarnOnMultipleClose"):
            mb = E5MessageBox.E5MessageBox(
                E5MessageBox.Information,
                self.tr("Are you sure you want to close the window?"),
                self.tr("""Are you sure you want to close the window?\n"""
                        """You have %n tab(s) open.""", "", self.count()),
                modal=True,
                parent=self)
            if self.__mainWindow.fromEric:
                quitButton = mb.addButton(
                    self.tr("&Close"), E5MessageBox.AcceptRole)
                quitButton.setIcon(UI.PixmapCache.getIcon("close.png"))
            else:
                quitButton = mb.addButton(
                    self.tr("&Quit"), E5MessageBox.AcceptRole)
                quitButton.setIcon(UI.PixmapCache.getIcon("exit.png"))
            closeTabButton = mb.addButton(
                self.tr("C&lose Current Tab"), E5MessageBox.AcceptRole)
            closeTabButton.setIcon(UI.PixmapCache.getIcon("tabClose.png"))
            mb.addButton(E5MessageBox.Cancel)
            mb.exec_()
            if mb.clickedButton() == quitButton:
                return True
            else:
                if mb.clickedButton() == closeTabButton:
                    self.closeBrowser()
                return False
        
        return True
    
    def stackedUrlBar(self):
        """
        Public method to get a reference to the stacked url bar.
        
        @return reference to the stacked url bar (StackedUrlBar)
        """
        return self.__stackedUrlBar
    
    def currentUrlBar(self):
        """
        Public method to get a reference to the current url bar.
        
        @return reference to the current url bar (UrlBar)
        """
        return self.__stackedUrlBar.currentWidget()
    
    def __lineEditReturnPressed(self):
        """
        Private slot to handle the entering of an URL.
        """
        edit = self.sender()
        url = self.__guessUrlFromPath(edit.text())
        request = QNetworkRequest(url)
        request.setRawHeader(b"X-Eric6-UserLoadAction", b"1")
        if e5App().keyboardModifiers() == Qt.AltModifier:
            self.newBrowser(
                None, (request, QNetworkAccessManager.GetOperation, b""))
        else:
            self.currentBrowser().setSource(
                None, (request, QNetworkAccessManager.GetOperation, b""))
            self.currentBrowser().setFocus()
    
    def __pathSelected(self, path):
        """
        Private slot called when a URL is selected from the completer.
        
        @param path path to be shown (string)
        """
        url = self.__guessUrlFromPath(path)
        self.currentBrowser().setSource(url)
    
    def __guessUrlFromPath(self, path):
        """
        Private method to guess an URL given a path string.
        
        @param path path string to guess an URL for (string)
        @return guessed URL (QUrl)
        """
        manager = self.__mainWindow.openSearchManager()
        path = Utilities.fromNativeSeparators(path)
        url = manager.convertKeywordSearchToUrl(path)
        if url.isValid():
            return url
        
        try:
            url = QUrl.fromUserInput(path)
        except AttributeError:
            url = QUrl(path)
        
        if url.scheme() == "about" and \
           url.path() == "home":
            url = QUrl("eric:home")
        
        if url.scheme() in ["s", "search"]:
            url = manager.currentEngine().searchUrl(url.path().strip())
        
        if url.scheme() != "" and \
           (url.host() != "" or url.path() != ""):
            return url
        
        urlString = Preferences.getHelp("DefaultScheme") + path.strip()
        url = QUrl.fromEncoded(urlString.encode("utf-8"), QUrl.TolerantMode)
        
        return url
    
    def __currentChanged(self, index):
        """
        Private slot to handle an index change.
        
        @param index new index (integer)
        """
        self.__stackedUrlBar.setCurrentIndex(index)
        
        browser = self.browserAt(index)
        if browser is not None:
            if browser.url() == "" and browser.hasFocus():
                self.__stackedUrlBar.currentWidget.setFocus()
            elif browser.url() != "":
                browser.setFocus()
    
    def restoreClosedTab(self):
        """
        Public slot to restore the most recently closed tab.
        """
        if not self.canRestoreClosedTab():
            return
        
        act = self.sender()
        tab = self.__closedTabsManager.getClosedTabAt(act.data())
        
        self.newBrowser(tab.url.toString(), position=tab.position)
    
    def canRestoreClosedTab(self):
        """
        Public method to check, if closed tabs can be restored.
        
        @return flag indicating that closed tabs can be restored (boolean)
        """
        return self.__closedTabsManager.isClosedTabAvailable()
    
    def restoreAllClosedTabs(self):
        """
        Public slot to restore all closed tabs.
        """
        if not self.canRestoreClosedTab():
            return
        
        for tab in self.__closedTabsManager.allClosedTabs():
            self.newBrowser(tab.url.toString(), position=tab.position)
        self.__closedTabsManager.clearList()
    
    def clearClosedTabsList(self):
        """
        Public slot to clear the list of closed tabs.
        """
        self.__closedTabsManager.clearList()
    
    def __aboutToShowClosedTabsMenu(self):
        """
        Private slot to populate the closed tabs menu.
        """
        fm = self.__closedTabsMenu.fontMetrics()
        maxWidth = fm.width('m') * 40
        
        self.__closedTabsMenu.clear()
        index = 0
        for tab in self.__closedTabsManager.allClosedTabs():
            title = fm.elidedText(tab.title, Qt.ElideRight, maxWidth)
            self.__closedTabsMenu.addAction(
                self.__mainWindow.icon(tab.url), title,
                self.restoreClosedTab).setData(index)
            index += 1
        self.__closedTabsMenu.addSeparator()
        self.__closedTabsMenu.addAction(
            self.tr("Restore All Closed Tabs"), self.restoreAllClosedTabs)
        self.__closedTabsMenu.addAction(
            self.tr("Clear List"), self.clearClosedTabsList)
    
    def closedTabsManager(self):
        """
        Public slot to get a reference to the closed tabs manager.
        
        @return reference to the closed tabs manager (ClosedTabsManager)
        """
        return self.__closedTabsManager
    
    def __closedTabAvailable(self, avail):
        """
        Private slot to handle changes of the availability of closed tabs.
        
        @param avail flag indicating the availability of closed tabs (boolean)
        """
        self.__closedTabsButton.setEnabled(avail)
        self.__restoreClosedTabAct.setEnabled(avail)
Пример #7
0
class FileManager(QWidget, _HalWidgetBase):
    def __init__(self, parent=None):
        super(FileManager, self).__init__(parent)
        self.title = 'Qtvcp File System View'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self._last = 0

        if INFO.PROGRAM_PREFIX is not None:
            self.user_path = os.path.expanduser(INFO.PROGRAM_PREFIX)
        else:
            self.user_path = (os.path.join(os.path.expanduser('~'),
                                           'linuxcnc/nc_files'))
        user = os.path.split(os.path.expanduser('~'))[-1]
        self.media_path = (os.path.join('/media', user))
        temp = [('User', self.user_path), ('Media', self.media_path)]
        self._jumpList = OrderedDict(temp)
        self.currentPath = None
        self.currentFolder = None
        self.PREFS_ = None
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        pasteBox = QHBoxLayout()
        self.textLine = QLineEdit()
        self.textLine.setToolTip('Current Director/selected File')
        self.pasteButton = QToolButton()
        self.pasteButton.setEnabled(False)
        self.pasteButton.setText('Paste')
        self.pasteButton.setToolTip(
            'Copy file from copy path to current directory/file')
        self.pasteButton.clicked.connect(self.paste)
        self.pasteButton.hide()
        pasteBox.addWidget(self.textLine)
        pasteBox.addWidget(self.pasteButton)

        self.copyBox = QFrame()
        hbox = QHBoxLayout()
        hbox.setContentsMargins(0, 0, 0, 0)
        self.copyLine = QLineEdit()
        self.copyLine.setToolTip('File path to copy from, when pasting')
        self.copyButton = QToolButton()
        self.copyButton.setText('Copy')
        self.copyButton.setToolTip('Record current file as copy path')
        self.copyButton.clicked.connect(self.recordCopyPath)
        hbox.addWidget(self.copyButton)
        hbox.addWidget(self.copyLine)
        self.copyBox.setLayout(hbox)
        self.copyBox.hide()

        self.model = QFileSystemModel()
        self.model.setRootPath(QDir.currentPath())
        self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files)
        self.model.setNameFilterDisables(False)
        self.model.rootPathChanged.connect(self.folderChanged)

        self.list = QListView()
        self.list.setModel(self.model)
        self.list.resize(640, 480)
        self.list.clicked[QModelIndex].connect(self.listClicked)
        self.list.activated.connect(self._getPathActivated)
        self.list.setAlternatingRowColors(True)
        self.list.hide()

        self.table = QTableView()
        self.table.setModel(self.model)
        self.table.resize(640, 480)
        self.table.clicked[QModelIndex].connect(self.listClicked)
        self.table.activated.connect(self._getPathActivated)
        self.table.setAlternatingRowColors(True)

        header = self.table.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.Stretch)
        header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(3, QHeaderView.ResizeToContents)
        header.swapSections(1, 3)
        header.setSortIndicator(1, Qt.AscendingOrder)

        self.table.setSortingEnabled(True)
        self.table.setColumnHidden(2, True)  # type
        self.table.verticalHeader().setVisible(False)  # row count header

        self.cb = QComboBox()
        self.cb.currentIndexChanged.connect(self.filterChanged)
        self.fillCombobox(INFO.PROGRAM_FILTERS_EXTENSIONS)
        self.cb.setMinimumHeight(30)
        self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,
                                          QSizePolicy.Fixed))

        self.button2 = QToolButton()
        self.button2.setText('User')
        self.button2.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button2.setMinimumSize(60, 30)
        self.button2.setToolTip(
            'Jump to User directory.\nLong press for Options.')
        self.button2.clicked.connect(self.onJumpClicked)

        self.button3 = QToolButton()
        self.button3.setText('Add Jump')
        self.button3.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button3.setMinimumSize(60, 30)
        self.button3.setToolTip('Add current directory to jump button list')
        self.button3.clicked.connect(self.onActionClicked)

        self.settingMenu = QMenu(self)
        self.button2.setMenu(self.settingMenu)

        hbox = QHBoxLayout()
        hbox.addWidget(self.button2)
        hbox.addWidget(self.button3)
        hbox.insertStretch(2, stretch=0)
        hbox.addWidget(self.cb)

        windowLayout = QVBoxLayout()
        windowLayout.addLayout(pasteBox)
        windowLayout.addWidget(self.copyBox)
        windowLayout.addWidget(self.list)
        windowLayout.addWidget(self.table)
        windowLayout.addLayout(hbox)
        self.setLayout(windowLayout)
        self.show()

    def _hal_init(self):
        if self.PREFS_:
            last_path = self.PREFS_.getpref('last_loaded_directory',
                                            self.user_path, str,
                                            'BOOK_KEEPING')
            LOG.debug("lAST FILE PATH: {}".format(last_path))
            if not last_path == '':
                self.updateDirectoryView(last_path)
            else:
                self.updateDirectoryView(self.user_path)

            # get all the saved jumplist paths
            temp = self.PREFS_.getall('FILEMANAGER_JUMPLIST')
            self._jumpList.update(temp)

        else:
            LOG.debug("lAST FILE PATH: {}".format(self.user_path))
            self.updateDirectoryView(self.user_path)

        # install jump paths into toolbutton menu
        for i in self._jumpList:
            self.addAction(i)

        # set recorded columns sort settings
        self.SETTINGS_.beginGroup("FileManager-{}".format(self.objectName()))
        sect = self.SETTINGS_.value('sortIndicatorSection', type=int)
        order = self.SETTINGS_.value('sortIndicatorOrder', type=int)
        self.SETTINGS_.endGroup()
        if not None in (sect, order):
            self.table.horizontalHeader().setSortIndicator(sect, order)

    # when qtvcp closes this gets called
    # record jump list paths
    def _hal_cleanup(self):
        if self.PREFS_:
            for i, key in enumerate(self._jumpList):
                if i in (0, 1):
                    continue
                self.PREFS_.putpref(key, self._jumpList.get(key), str,
                                    'FILEMANAGER_JUMPLIST')

        # record sorted columns
        h = self.table.horizontalHeader()
        self.SETTINGS_.beginGroup("FileManager-{}".format(self.objectName()))
        self.SETTINGS_.setValue('sortIndicatorSection',
                                h.sortIndicatorSection())
        self.SETTINGS_.setValue('sortIndicatorOrder', h.sortIndicatorOrder())
        self.SETTINGS_.endGroup()

    #########################
    # callbacks
    #########################

    # add shown text and hidden filter data from the INI
    def fillCombobox(self, data):
        for i in data:
            self.cb.addItem(i[0], i[1])

    def folderChanged(self, data):
        data = os.path.normpath(data)
        self.currentFolder = data
        self.textLine.setText(data)

    def updateDirectoryView(self, path, quiet=False):
        if os.path.exists(path):
            self.list.setRootIndex(self.model.setRootPath(path))
            self.table.setRootIndex(self.model.setRootPath(path))
        else:
            LOG.debug(
                "Set directory view error - no such path {}".format(path))
            if not quiet:
                STATUS.emit(
                    'error', LOW_ERROR,
                    "File Manager error - No such path: {}".format(path))

    # retrieve selected filter (it's held as QT.userData)
    def filterChanged(self, index):
        userdata = self.cb.itemData(index)
        self.model.setNameFilters(userdata)

    def listClicked(self, index):
        # the signal passes the index of the clicked item
        dir_path = os.path.normpath(self.model.filePath(index))
        if self.model.fileInfo(index).isFile():
            self.currentPath = dir_path
            self.textLine.setText(self.currentPath)
            return
        root_index = self.model.setRootPath(dir_path)
        self.list.setRootIndex(root_index)
        self.table.setRootIndex(root_index)

    def onUserClicked(self):
        self.showUserDir()

    def onMediaClicked(self):
        self.showMediaDir()

    # jump directly to a saved path shown on the button
    def onJumpClicked(self):
        data = self.button2.text()
        if data.upper() == 'MEDIA':
            self.showMediaDir()
        elif data.upper() == 'USER':
            self.showUserDir()
        else:
            temp = self._jumpList.get(data)
            if temp is not None:
                self.updateDirectoryView(temp)
            else:
                STATUS.emit('error', linuxcnc.OPERATOR_ERROR,
                            'file jumopath: {} not valid'.format(data))
                log.debug('file jumopath: {} not valid'.format(data))

    # jump directly to a saved path from the menu
    def jumpTriggered(self, data):
        if data.upper() == 'MEDIA':
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip(
                'Jump to Media directory.\nLong press for Options.')
            self.showMediaDir()
        elif data.upper() == 'USER':
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip(
                'Jump to User directory.\nLong press for Options.')
            self.showUserDir()
        else:
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip('Jump to directory:\n{}'.format(
                self._jumpList.get(data)))
            self.updateDirectoryView(self._jumpList.get(data))

    # add a jump list path
    def onActionClicked(self):
        i = self.currentFolder
        try:
            self._jumpList[i] = i
        except Exception as e:
            print(e)
        button = QAction(QIcon.fromTheme('user-home'), i, self)
        # weird lambda i=i to work around 'function closure'
        button.triggered.connect(lambda state, i=i: self.jumpTriggered(i))
        self.settingMenu.addAction(button)

    # get current selection and update the path
    # then if the path is good load it into linuxcnc
    # record it in the preference file if available
    def _getPathActivated(self):
        if self.list.isVisible():
            row = self.list.selectionModel().currentIndex()
        else:
            row = self.table.selectionModel().currentIndex()
            self.listClicked(row)

        fname = self.currentPath
        if fname is None:
            return
        if fname:
            self.load(fname)

    def recordCopyPath(self):
        data, isFile = self.getCurrentSelected()
        if isFile:
            self.copyLine.setText(os.path.normpath(data))
            self.pasteButton.setEnabled(True)
        else:
            self.copyLine.setText('')
            self.pasteButton.setEnabled(False)
            STATUS.emit('error', OPERATOR_ERROR,
                        'Can only copy a file, not a folder')

    def paste(self):
        res = self.copyFile(self.copyLine.text(), self.textLine.text())
        if res:
            self.copyLine.setText('')
            self.pasteButton.setEnabled(False)

    ########################
    # helper functions
    ########################

    def addAction(self, i):
        axisButton = QAction(QIcon.fromTheme('user-home'), i, self)
        # weird lambda i=i to work around 'function closure'
        axisButton.triggered.connect(lambda state, i=i: self.jumpTriggered(i))
        self.settingMenu.addAction(axisButton)

    def showList(self, state=True):
        if state:
            self.table.hide()
            self.list.show()
        else:
            self.table.show()
            self.list.hide()

    def showTable(self, state=True):
        self.showList(not state)

    def showCopyControls(self, state):
        if state:
            self.copyBox.show()
            self.pasteButton.show()
        else:
            self.copyBox.hide()
            self.pasteButton.hide()

    def showMediaDir(self, quiet=False):
        self.updateDirectoryView(self.media_path, quiet)

    def showUserDir(self, quiet=False):
        self.updateDirectoryView(self.user_path, quiet)

    def copyFile(self, s, d):
        try:
            shutil.copy(s, d)
            return True
        except Exception as e:
            LOG.error("Copy file error: {}".format(e))
            STATUS.emit('error', OPERATOR_ERROR,
                        "Copy file error: {}".format(e))
            return False

    @pyqtSlot(float)
    @pyqtSlot(int)
    def scroll(self, data):
        if data > self._last:
            self.up()
        elif data < self._last:
            self.down()
        self._last = data

    # moves the selection up
    # used with MPG scrolling
    def up(self):
        self.select_row('up')

    # moves the selection down
    # used with MPG scrolling
    def down(self):
        self.select_row('down')

    def select_row(self, style='down'):
        style = style.lower()
        if self.list.isVisible():
            i = self.list.rootIndex()
            selectionModel = self.list.selectionModel()
        else:
            i = self.table.rootIndex()
            selectionModel = self.table.selectionModel()

        row = selectionModel.currentIndex().row()
        self.rows = self.model.rowCount(i)

        if style == 'last':
            row = self.rows
        elif style == 'up':
            if row > 0:
                row -= 1
            else:
                row = 0
        elif style == 'down':
            if row < self.rows - 1:
                row += 1
            else:
                row = self.rows - 1
        else:
            return
        top = self.model.index(row, 0, i)
        selectionModel.setCurrentIndex(
            top, QItemSelectionModel.Select | QItemSelectionModel.Rows)
        selection = QItemSelection(top, top)
        selectionModel.clearSelection()
        selectionModel.select(selection, QItemSelectionModel.Select)

    # returns the current highlighted (selected) path as well as
    # whether it's a file or not.
    def getCurrentSelected(self):
        if self.list.isVisible():
            selectionModel = self.list.selectionModel()
        else:
            selectionModel = self.table.selectionModel()
        index = selectionModel.currentIndex()
        dir_path = os.path.normpath(self.model.filePath(index))
        if self.model.fileInfo(index).isFile():
            return (dir_path, True)
        else:
            return (dir_path, False)

    # This can be class patched to do something else
    def load(self, fname=None):
        try:
            if fname is None:
                self._getPathActivated()
                return
            self.recordBookKeeping()
            ACTION.OPEN_PROGRAM(fname)
            STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME')
        except Exception as e:
            LOG.error("Load file error: {}".format(e))
            STATUS.emit('error', NML_ERROR, "Load file error: {}".format(e))

    # This can be class patched to do something else
    def recordBookKeeping(self):
        fname = self.currentPath
        if fname is None:
            return
        if self.PREFS_:
            self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(),
                                str, 'BOOK_KEEPING')
            self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING')
Пример #8
0
class wdgManagerSelector(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.mqtw=myQTableWidget(self)
        self.mqtw.showSearchOptions(True)
        self.mqtw.showSearchCloseButton(False)
        self.mqtwSelected=myQTableWidget(self)
        self.mqtwSelected.showSearchOptions(True)
        self.mqtwSelected.showSearchCloseButton(False)
        
        self.laybuttons = QVBoxLayout()
        self.cmdLeft=QToolButton(self)
        self.cmdLeft.setText("<")
        self.cmdLeftAll=QToolButton(self)
        self.cmdLeftAll.setText("<<")
        self.cmdRight=QToolButton(self)
        self.cmdRight.setText(">")
        self.cmdRightAll=QToolButton(self)
        self.cmdRightAll.setText(">>")
        self.cmdDown=QToolButton(self)
        self.cmdUp=QToolButton(self)
        self.laybuttons.addWidget(self.cmdUp)
        self.laybuttons.addWidget(self.cmdRightAll)
        self.laybuttons.addWidget(self.cmdRight)
        self.laybuttons.addWidget(self.cmdLeft)
        self.laybuttons.addWidget(self.cmdLeftAll)
        self.laybuttons.addWidget(self.cmdDown)
        self.laybuttons.setAlignment(Qt.AlignVCenter)
        
        self.cmdDown.hide()
        self.cmdUp.hide()
        
        self.lay=QHBoxLayout(self)
        self.lay.addWidget(self.mqtw)
        self.lay.addLayout(self.laybuttons)
        self.lay.addWidget(self.mqtwSelected)        
        self._showObjectIcons=True

    ## Hides Up and Down button
    def showUpDown(self):
        self.cmdDown.show()
        self.cmdUp.show()
        
    ## By default is True. Show Icons y tables and combobox 
    def showObjectIcons(self, boolean):
        self._showObjectIcons=boolean

    ## manager needs to have add setConstructorParameters to generate emptyManager
    def setManagers(self, settings, settingsSection,  settingsObject, manager, selected):
        self.settings=settings
        self.settingsSection=settingsSection
        self.settingsObject=settingsObject
        self.mqtw.settings(self.settings, self.settingsSection, "{}_tbl".format(self.settingsObject))
        self.mqtwSelected.settings(self.settings, self.settingsSection, "{}_tblSelected".format(self.settingsObject))

        self.manager=manager.clone()#Clone manager to delete safely objects

        #removes selected objects from manager
        if selected is None:
            self.selected=self.manager.emptyManager()
        else:
            self.selected=selected
            for o in self.selected.arr:
                self.manager.remove(o)

        self._load_tbl()
        self._load_tblSelected()
        self.cmdDown.released.connect(self.on_cmdDown_released)
        self.cmdUp.released.connect(self.on_cmdUp_released)
        self.cmdLeft.released.connect(self.on_cmdLeft_released)
        self.cmdRight.released.connect(self.on_cmdRight_released)
        self.cmdLeftAll.released.connect(self.on_cmdLeftAll_released)
        self.cmdRightAll.released.connect(self.on_cmdRightAll_released)

    def _load_tblSelected(self):       
        self.mqtwSelected.table.setColumnCount(1)
        self.mqtwSelected.table.setHorizontalHeaderItem(0, QTableWidgetItem(self.tr("Object")))
        self.mqtwSelected.applySettings() 
        self.mqtwSelected.table.setRowCount(self.selected.length())
        for i, o in enumerate(self.selected.arr):
            self.mqtwSelected.table.setItem(i, 0, QTableWidgetItem(str(o)))
            if self._showObjectIcons==True:
                self.mqtwSelected.table.item(i, 0).setIcon(o.qicon())
        
    def _load_tbl(self):  
        self.mqtw.table.setColumnCount(1)
        self.mqtw.table.setHorizontalHeaderItem(0, QTableWidgetItem(self.tr("Object")))
        self.mqtw.applySettings()
        self.mqtw.table.setRowCount(self.manager.length())
        for i, o in enumerate(self.manager.arr):
            self.mqtw.table.setItem(i, 0, QTableWidgetItem(str(o)))
            if self._showObjectIcons==True:
                self.mqtw.table.item(i, 0).setIcon(o.qicon())

    def on_cmdLeft_released(self):
        for i in self.mqtwSelected.table.selectedItems():
            selected=self.selected.arr[i.row()]
            self.manager.append(selected)       
            self.selected.remove(selected) 
        self._load_tbl()
        self._load_tblSelected()

    def on_cmdLeftAll_released(self):
        for o in self.selected.arr:
            self.manager.append(o)      
        self.selected.clean()
        self._load_tbl()
        self._load_tblSelected()

    def on_cmdRightAll_released(self):
        for o in self.manager.arr:
            self.selected.append(o)       
        self.manager.clean()
        self._load_tbl()
        self._load_tblSelected()
        
    def on_cmdRight_released(self):
        for i in self.mqtw.table.selectedItems():
            selected=self.manager.arr[i.row()]
            self.selected.append(selected)
            self.manager.remove(selected)
        self._load_tbl()
        self._load_tblSelected()   
        
        
    def on_cmd_released(self):
        print("Selected",  self.selected.arr)
        self.done(0)
        
    def on_cmdUp_released(self):
        pos=None
        for i in self.mqtwSelected.table.selectedItems():
            pos=i.row()
        tmp=self.selected.arr[pos]
        self.selected.arr[pos]=self.selected.arr[pos-1]
        self.selected.arr[pos-1]=tmp
        self._load_tbl()
        self._load_tblSelected()             
        
    def on_cmdDown_released(self):
        pos=None
        for i in self.mqtwSelected.table.selectedItems():
            pos=i.row()
        tmp=self.selected.arr[pos+1]
        self.selected.arr[pos+1]=self.selected.arr[pos]
        self.selected.arr[pos]=tmp
        self._load_tbl()
        self._load_tblSelected()        
        
    def on_tbl_cellDoubleClicked(self, row, column):
        self.on_cmdRight_released()
        
    def on_tblSelected_cellDoubleClicked(self, row, column):
        self.on_cmdLeft_released()
Пример #9
0
class MacroTab(QVBoxLayout):

    changed = pyqtSignal()
    record = pyqtSignal(object, bool)
    record_stop = pyqtSignal()

    def __init__(self, parent, enable_recorder):
        super().__init__()

        self.parent = parent

        self.lines = []

        self.container = QGridLayout()

        menu_record = QMenu()
        menu_record.addAction(tr("MacroRecorder", "Append to current"))\
            .triggered.connect(lambda: self.record.emit(self, True))
        menu_record.addAction(tr("MacroRecorder", "Replace everything"))\
            .triggered.connect(lambda: self.record.emit(self, False))

        self.btn_record = QPushButton(tr("MacroRecorder", "Record macro"))
        self.btn_record.setMenu(menu_record)
        if not enable_recorder:
            self.btn_record.hide()

        self.btn_record_stop = QPushButton(
            tr("MacroRecorder", "Stop recording"))
        self.btn_record_stop.clicked.connect(lambda: self.record_stop.emit())
        self.btn_record_stop.hide()

        self.btn_add = QToolButton()
        self.btn_add.setText(tr("MacroRecorder", "Add action"))
        self.btn_add.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_add.clicked.connect(self.on_add)

        self.btn_tap_enter = QToolButton()
        self.btn_tap_enter.setText(tr("MacroRecorder", "Tap Enter"))
        self.btn_tap_enter.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_tap_enter.clicked.connect(self.on_tap_enter)

        self.btn_text_window = QToolButton()
        self.btn_text_window.setText(tr("MacroRecorder",
                                        "Open Text Editor..."))
        self.btn_text_window.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_text_window.clicked.connect(self.on_text_window)

        layout_buttons = QHBoxLayout()
        layout_buttons.addWidget(self.btn_text_window)
        layout_buttons.addStretch()
        layout_buttons.addWidget(self.btn_add)
        layout_buttons.addWidget(self.btn_tap_enter)
        layout_buttons.addWidget(self.btn_record)
        layout_buttons.addWidget(self.btn_record_stop)

        vbox = QVBoxLayout()
        vbox.addLayout(self.container)
        vbox.addStretch()

        w = QWidget()
        w.setLayout(vbox)
        w.setObjectName("w")
        scroll = QScrollArea()
        scroll.setFrameShape(QFrame.NoFrame)
        scroll.setStyleSheet("QScrollArea { background-color:transparent; }")
        w.setStyleSheet("#w { background-color:transparent; }")
        scroll.setWidgetResizable(True)
        scroll.setWidget(w)

        self.addWidget(scroll)
        self.addLayout(layout_buttons)

    def add_action(self, act):
        line = MacroLine(self, act)
        line.changed.connect(self.on_change)
        self.lines.append(line)
        line.insert(len(self.lines) - 1)
        self.changed.emit()

    def on_add(self):
        self.add_action(ActionTextUI(self.container))

    def on_remove(self, obj):
        for line in self.lines:
            if line == obj:
                line.remove()
                line.delete()
        self.lines.remove(obj)
        for line in self.lines:
            line.remove()
        for x, line in enumerate(self.lines):
            line.insert(x)
        self.changed.emit()

    def clear(self):
        for line in self.lines[:]:
            self.on_remove(line)

    def on_move(self, obj, offset):
        if offset == 0:
            return
        index = self.lines.index(obj)
        if index + offset < 0 or index + offset >= len(self.lines):
            return
        other = self.lines.index(self.lines[index + offset])
        self.lines[index].remove()
        self.lines[other].remove()
        self.lines[index], self.lines[other] = self.lines[other], self.lines[
            index]
        self.lines[index].insert(index)
        self.lines[other].insert(other)
        self.changed.emit()

    def on_text_window(self):

        # serialize all actions in this tab to a json
        macro_text = []
        macro_text.append([act.save() for act in self.actions()])
        macro_text = json.dumps(macro_text[0])

        textbox = TextboxWindow(macro_text, "vim", "Vial macro")

        if textbox.exec():
            macro_text = textbox.getText()
            if len(macro_text) < 6:
                macro_text = "[]"
            macro_load = json.loads(macro_text)

            # ensure a list exists
            if not isinstance(macro_load, list):
                return

            # clear the actions from this tab
            self.clear()

            # add each action from the json to this tab
            for act in macro_load:
                if act[0] in tag_to_action:
                    obj = tag_to_action[act[0]]()
                    actionUI = ui_action[type(obj)]
                    obj.restore(act)
                    self.add_action(actionUI(self.container, obj))

    def on_change(self):
        self.changed.emit()

    def on_tap_enter(self):
        self.add_action(
            ActionTapUI(self.container,
                        ActionTap([Keycode.find_by_qmk_id("KC_ENTER")])))

    def pre_record(self):
        self.btn_record.hide()
        self.btn_add.hide()
        self.btn_tap_enter.hide()
        self.btn_text_window.hide()
        self.btn_record_stop.show()

    def post_record(self):
        self.btn_record.show()
        self.btn_add.show()
        self.btn_tap_enter.show()
        self.btn_text_window.show()
        self.btn_record_stop.hide()

    def actions(self):
        return [line.action.act for line in self.lines]
Пример #10
0
class HomeRecommendedItem(QWidget, fc_home_recommended_item):
    """
    This class represents a HomeRecommendedItem widget which is shown on the home page. This widget can either show
    a channel or a torrent.
    """
    def __init__(self, parent):
        QWidget.__init__(self, parent)
        fc_home_recommended_item.__init__(self)

        self.setupUi(self)

        self.show_torrent = True
        self.torrent_info = None
        self.channel_info = None
        self.download_uri = None
        self.dialog = None

        # Create the category label, shown on cells that display a torrent on the home page
        self.category_label = QLabel(self)
        self.category_label.setFixedHeight(24)
        self.category_label.setSizePolicy(
            QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed))
        self.category_label.setStyleSheet("""
        border: 2px solid white;
        border-radius: 12px;
        background-color: transparent;
        color: white;
        padding-left: 4px;
        padding-right: 4px;
        font-weight: bold;
        """)
        self.category_label.move(QPoint(6, 6))
        self.category_label.show()

        # Create the dark overlay and download button over the thumbnail on hover
        self.dark_overlay = QWidget(self)
        self.dark_overlay.setStyleSheet(
            "background-color: rgba(0, 0, 0, 0.65);")
        self.dark_overlay.hide()

        self.download_button = QToolButton(self)
        self.download_button.setFixedSize(QSize(40, 40))
        self.download_button.setStyleSheet("""
        QToolButton {
            background-color: transparent;
            border: 2px solid white;
            border-radius: 20px;
        }

        QToolButton::hover {
            border: 2px solid #B5B5B5;
        }
        """)
        self.download_button.setIcon(QIcon(get_image_path('downloads.png')))
        self.download_button.setIconSize(QSize(18, 18))
        self.download_button.clicked.connect(self.on_download_button_clicked)
        self.download_button.hide()

    def on_download_button_clicked(self):
        if not self.torrent_info:
            return
        self.download_uri = (u"magnet:?xt=urn:btih:%s&dn=%s" %
                             (self.torrent_info["infohash"],
                              self.torrent_info['name'])).encode('utf-8')
        self.window().start_download_from_uri(self.download_uri)

    def update_with_torrent(self, torrent):
        if not torrent:
            return
        self.show_torrent = True
        self.torrent_info = torrent
        self.thumbnail_widget.initialize(torrent["name"], HOME_ITEM_FONT_SIZE)
        self.main_label.setText(torrent["name"])
        self.category_label.setText(torrent["category"].lower() if (
            "category" in torrent and torrent["category"]) else 'other')
        self.category_label.adjustSize()
        self.category_label.setHidden(False)
        self.setCursor(Qt.ArrowCursor)
        self.detail_label.setText("Size: " +
                                  format_size(torrent.get("size", 0)))

    def update_with_channel(self, channel):
        if not channel:
            return
        self.show_torrent = False
        self.channel_info = channel
        self.thumbnail_widget.initialize(channel["name"], HOME_ITEM_FONT_SIZE)

        self.main_label.setText(channel["name"])
        self.detail_label.setText("%d torrents" % channel["torrents"])
        self.category_label.setHidden(True)
        self.setCursor(Qt.PointingHandCursor)

    def enterEvent(self, _):
        if self.show_torrent:
            self.dark_overlay.resize(self.thumbnail_widget.size())
            self.dark_overlay.show()
            self.download_button.move(
                (self.thumbnail_widget.width() - self.download_button.width())
                / 2, (self.thumbnail_widget.height() -
                      self.download_button.height()) / 2)
            self.download_button.show()

    def leaveEvent(self, _):
        self.dark_overlay.hide()
        self.download_button.hide()
Пример #11
0
class ShareWidget(QDialog):
    done = pyqtSignal(QWidget)
    closed = pyqtSignal(QWidget)

    def __init__(self,
                 gateway,
                 gui,
                 folder_names=None):  # noqa: max-complexity=11 XXX
        super(ShareWidget, self).__init__()
        self.gateway = gateway
        self.gui = gui
        self.folder_names = folder_names
        self.folder_names_humanized = humanized_list(folder_names, 'folders')
        self.settings = {}
        self.wormhole = None
        self.pending_invites = []
        self.use_tor = self.gateway.use_tor

        # XXX Temporary(?) workaround for font-scaling inconsistencies observed
        # during user-testing (wherein fonts on Windows on one laptop were
        # rendering especially large for some reason but were fine elsewhere)
        if sys.platform == 'win32':
            self.setMinimumSize(600, 400)
        else:
            self.setMinimumSize(500, 300)

        header_icon = QLabel(self)
        if self.folder_names:
            icon = QFileIconProvider().icon(
                QFileInfo(
                    self.gateway.get_magic_folder_directory(
                        self.folder_names[0])))
        else:
            icon = QIcon(os.path.join(gateway.nodedir, 'icon'))
            if not icon.availableSizes():
                icon = QIcon(resource('tahoe-lafs.png'))
        header_icon.setPixmap(icon.pixmap(50, 50))

        header_text = QLabel(self)
        if self.folder_names:
            header_text.setText(self.folder_names_humanized)
        else:
            header_text.setText(self.gateway.name)
        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(22)
        else:
            font.setPointSize(18)
        header_text.setFont(font)
        header_text.setAlignment(Qt.AlignCenter)

        header_layout = QGridLayout()
        header_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1,
                              1)
        header_layout.addWidget(header_icon, 1, 2)
        header_layout.addWidget(header_text, 1, 3)
        header_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1,
                              4)

        self.subtext_label = QLabel(self)
        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(13)
        else:
            font.setPointSize(10)
        self.subtext_label.setFont(font)
        self.subtext_label.setStyleSheet("color: grey")
        self.subtext_label.setWordWrap(True)
        self.subtext_label.setAlignment(Qt.AlignCenter)

        self.noise_label = QLabel()
        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(20)
        else:
            font.setPointSize(16)
        font.setFamily("Courier")
        font.setStyleHint(QFont.Monospace)
        self.noise_label.setFont(font)
        self.noise_label.setStyleSheet("color: grey")

        self.noise_timer = QTimer()
        self.noise_timer.timeout.connect(
            lambda: self.noise_label.setText(b58encode(os.urandom(16))))
        self.noise_timer.start(75)

        self.code_label = QLabel()
        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(22)
        else:
            font.setPointSize(18)
        self.code_label.setFont(font)
        self.code_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.code_label.hide()

        self.box_title = QLabel(self)
        self.box_title.setAlignment(Qt.AlignCenter)
        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(20)
        else:
            font.setPointSize(16)
        self.box_title.setFont(font)

        self.box = QGroupBox()
        self.box.setAlignment(Qt.AlignCenter)
        self.box.setStyleSheet('QGroupBox {font-size: 16px}')

        self.copy_button = QToolButton()
        self.copy_button.setIcon(QIcon(resource('copy.png')))
        self.copy_button.setToolTip("Copy to clipboard")
        self.copy_button.setStyleSheet('border: 0px; padding: 0px;')
        self.copy_button.hide()

        box_layout = QGridLayout(self.box)
        box_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 1)
        box_layout.addWidget(self.noise_label, 1, 2)
        box_layout.addWidget(self.code_label, 1, 3)
        box_layout.addWidget(self.copy_button, 1, 4)
        box_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 5)

        self.close_button = QPushButton("Close and cancel invite")
        self.close_button.setAutoDefault(False)

        self.checkmark = QLabel()
        self.checkmark.setPixmap(
            QPixmap(resource('green_checkmark.png')).scaled(32, 32))
        self.checkmark.setAlignment(Qt.AlignCenter)
        self.checkmark.hide()

        self.tor_label = QLabel()
        self.tor_label.setToolTip(
            "This connection is being routed through the Tor network.")
        self.tor_label.setPixmap(
            QPixmap(resource('tor-onion.png')).scaled(32, 32))
        self.tor_label.hide()

        self.progress_bar = QProgressBar()
        self.progress_bar.setMaximum(2)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.hide()

        layout = QGridLayout(self)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 0, 0)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 1)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 2)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 3)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 4)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 5)
        layout.addLayout(header_layout, 1, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 2, 1)
        layout.addWidget(self.box_title, 3, 2, 1, 3)
        layout.addWidget(self.checkmark, 3, 3)
        layout.addWidget(self.tor_label, 4, 1, 1, 1,
                         Qt.AlignRight | Qt.AlignVCenter)
        layout.addWidget(self.box, 4, 2, 1, 3)
        layout.addWidget(self.progress_bar, 4, 2, 1, 3)
        layout.addWidget(self.subtext_label, 5, 2, 1, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 6, 1)
        layout.addWidget(self.close_button, 7, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 8, 1)

        self.copy_button.clicked.connect(self.on_copy_button_clicked)
        self.close_button.clicked.connect(self.close)

        self.set_box_title("Generating invite code...")

        if self.use_tor:
            self.tor_label.show()
            self.progress_bar.setStyleSheet(
                'QProgressBar::chunk {{ background-color: {}; }}'.format(
                    TOR_PURPLE))

        self.go()  # XXX

    def set_box_title(self, text):
        if sys.platform == 'darwin':
            self.box_title.setText(text)
            self.box_title.show()
        else:
            self.box.setTitle(text)

    def on_copy_button_clicked(self):
        code = self.code_label.text()
        for mode in get_clipboard_modes():
            set_clipboard_text(code, mode)
        self.subtext_label.setText(
            "Copied '{}' to clipboard!\n\n".format(code))

    def on_got_code(self, code):
        self.noise_timer.stop()
        self.noise_label.hide()
        self.set_box_title("Your invite code is:")
        self.code_label.setText(code)
        self.code_label.show()
        self.copy_button.show()
        if self.folder_names:
            if len(self.folder_names) == 1:
                abilities = 'download "{}" and modify its contents'.format(
                    self.folder_names[0])
            else:
                abilities = 'download {} and modify their contents'.format(
                    self.folder_names_humanized)
        else:
            abilities = 'connect to "{}" and upload new folders'.format(
                self.gateway.name)
        self.subtext_label.setText(
            "Entering this code on another device will allow it to {}.\n"
            "This code can only be used once.".format(abilities))

    def on_got_introduction(self):
        if sys.platform == 'darwin':
            self.box_title.hide()
        self.box.hide()
        self.progress_bar.show()
        self.progress_bar.setValue(1)
        self.subtext_label.setText("Connection established; sending invite...")

    def on_send_completed(self):
        self.box.hide()
        self.progress_bar.show()
        self.progress_bar.setValue(2)
        self.checkmark.show()
        self.close_button.setText("Finish")
        if self.folder_names:
            target = self.folder_names_humanized
        else:
            target = self.gateway.name
        text = "Your invitation to {} was accepted".format(target)
        self.subtext_label.setText("Invite successful!\n {} at {}".format(
            text,
            datetime.now().strftime('%H:%M')))
        if get_preference('notifications', 'invite') != 'false':
            self.gui.show_message("Invite successful", text)

        # XXX FIXME Quick and dirty hack for user-testing
        if self.folder_names:
            for view in self.gui.main_window.central_widget.views:
                if view.gateway.name == self.gateway.name:
                    for folder in self.folder_names:
                        # Add two members for now, in case the original folder
                        # was empty (in which case the original "syncing"
                        # operation would not have occured and thus "admin"'s
                        # membership would not have been detected).
                        # FIXME Force call a Monitor.do_remote_scan() instead?
                        view.model().add_member(folder, None)
                        view.model().add_member(folder, None)
                        view.model().set_status_shared(folder)

    def handle_failure(self, failure):
        if failure.type == wormhole.errors.LonelyError:
            return
        logging.error(str(failure))
        show_failure(failure, self)
        self.wormhole.close()
        self.close()

    @inlineCallbacks
    def get_folder_invite(self, folder):
        member_id = b58encode(os.urandom(8))
        try:
            code = yield self.gateway.magic_folder_invite(folder, member_id)
        except TahoeError as err:
            code = None
            self.wormhole.close()
            error(self, "Invite Error", str(err))
            self.close()
        return folder, member_id, code

    @inlineCallbacks
    def get_folder_invites(self):
        self.subtext_label.setText("Creating folder invite(s)...\n\n")
        folders_data = {}
        tasks = []
        for folder in self.folder_names:
            tasks.append(self.get_folder_invite(folder))
        results = yield gatherResults(tasks)
        for folder, member_id, code in results:
            folders_data[folder] = {'code': code}
            self.pending_invites.append((folder, member_id))
        return folders_data

    @inlineCallbacks
    def go(self):
        self.wormhole = Wormhole(self.use_tor)
        self.wormhole.got_code.connect(self.on_got_code)
        self.wormhole.got_introduction.connect(self.on_got_introduction)
        self.wormhole.send_completed.connect(self.on_send_completed)
        self.settings = self.gateway.get_settings()
        if self.folder_names:
            folders_data = yield self.get_folder_invites()
            self.settings['magic-folders'] = folders_data
        self.subtext_label.setText("Opening wormhole...\n\n")
        self.wormhole.send(self.settings).addErrback(self.handle_failure)

    def closeEvent(self, event):
        if self.code_label.text() and self.progress_bar.value() < 2:
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Question)
            msg.setWindowTitle("Cancel invitation?")
            msg.setText(
                'Are you sure you wish to cancel the invitation to "{}"?'.
                format(self.gateway.name))
            msg.setInformativeText(
                'The invite code "{}" will no longer be valid.'.format(
                    self.code_label.text()))
            msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            msg.setDefaultButton(QMessageBox.No)
            if msg.exec_() == QMessageBox.Yes:
                self.wormhole.close()
                if self.folder_names:
                    for folder, member_id in self.pending_invites:
                        self.gateway.magic_folder_uninvite(folder, member_id)
                event.accept()
                self.closed.emit(self)
            else:
                event.ignore()
        else:
            event.accept()
            if self.noise_timer.isActive():
                self.noise_timer.stop()
            self.closed.emit(self)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()
Пример #12
0
class wdgProductSelector(QWidget):
    """Para usarlo promocionar un qwidget en designer y darle los comportamientos de tamaña que neceseite
    incluso añadirlo a un layout."""
    selectionChanged=pyqtSignal()
    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.selected=None
    
    def setupUi(self, mem, investment=None):
        """Investement is used to set investment pointer. It's usefull to see investment data in product report"""
        self.mem=mem
        self.investment=investment#Optional
        
        self.horizontalLayout_2 = QHBoxLayout(self)
        self.horizontalLayout = QHBoxLayout()
        self.label = QLabel(self)
        self.label.setText(self.tr("Select a product"))
        self.horizontalLayout.addWidget(self.label)                                                                                                                                 
        self.txt = QLineEdit(self)                                                                                                                                       
        self.txt.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)                                                                             
        self.txt.setReadOnly(True)      
        self.txt.setToolTip(self.tr("Press the search button"))           
        self.horizontalLayout.addWidget(self.txt)                                                                                                                                 
        self.cmd= QToolButton(self)               
        icon = QIcon()
        icon.addPixmap(QPixmap(":/xulpymoney/document-preview-archive.png"), QIcon.Normal, QIcon.Off)
        self.cmd.setIcon(icon)                                                                                                                                   
        self.horizontalLayout.addWidget(self.cmd)                                                                                                                            
        self.horizontalLayout_2.addLayout(self.horizontalLayout)                
        self.cmd.released.connect(self.on_cmd_released)
        self.cmd.setToolTip(self.tr("Press to select a product"))
                                                                                                          
        self.cmdProduct= QToolButton(self)    
        icon2 = QIcon()
        icon2.addPixmap(QPixmap(":/xulpymoney/books.png"), QIcon.Normal, QIcon.Off)
        self.cmdProduct.setIcon(icon2)                                                                                                       
        self.horizontalLayout.addWidget(self.cmdProduct)  
        self.cmdProduct.setToolTip(self.tr("Press to see selected product information"))                    
        self.cmdProduct.released.connect(self.on_cmdProduct_released)
        self.cmdProduct.setEnabled(False)

    def on_cmd_released(self):
        d=frmProductSelector(self, self.mem)
        d.exec_()
        self.setSelected(d.mqtwProducts.selected)
        
    def on_cmdProduct_released(self):
        from xulpymoney.ui.frmProductReport import frmProductReport
        w=frmProductReport(self.mem, self.selected, self.investment,  self)
        w.exec_()
        
    def setLabel(self, s):
        self.label.setText(s)
            
    def setSelected(self, product):
        """Recibe un objeto Product. No se usará posteriormente, por lo que puede no estar completo con get_basic.:."""
        self.selected=product
        if self.selected==None:
            self.txt.setText(self.tr("Not selected"))
            self.cmdProduct.setEnabled(False)     
            self.txt.setToolTip(self.tr("Press the search button"))                                                                                                                                                           
        else:      
            self.txt.setText("{0} ({1})".format(self.selected.name, self.selected.id))
            self.cmdProduct.setEnabled(True)
            self.txt.setToolTip(self.tr("Selected product"))    
            self.selectionChanged.emit()
        
    def showProductButton(self, boolean):
        if boolean==True:#Default
            self.cmdProduct.show()
        else:
            self.cmdProduct.hide()
Пример #13
0
class InviteSenderDialog(QDialog):
    done = pyqtSignal(QWidget)
    closed = pyqtSignal(QWidget)

    def __init__(self, gateway, gui, folder_names=None):
        super(InviteSenderDialog, self).__init__()
        self.gateway = gateway
        self.gui = gui
        self.folder_names = folder_names
        self.folder_names_humanized = humanized_list(folder_names, 'folders')
        self.settings = {}
        self.pending_invites = []
        self.use_tor = self.gateway.use_tor

        self.setMinimumSize(500, 300)

        header_icon = QLabel(self)
        if self.folder_names:
            icon = QFileIconProvider().icon(
                QFileInfo(
                    self.gateway.get_magic_folder_directory(
                        self.folder_names[0])))
        else:
            icon = QIcon(os.path.join(gateway.nodedir, 'icon'))
            if not icon.availableSizes():
                icon = QIcon(resource('tahoe-lafs.png'))
        header_icon.setPixmap(icon.pixmap(50, 50))

        header_text = QLabel(self)
        if self.folder_names:
            header_text.setText(self.folder_names_humanized)
        else:
            header_text.setText(self.gateway.name)
        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(22)
        else:
            font.setPointSize(18)
        header_text.setFont(font)
        header_text.setAlignment(Qt.AlignCenter)

        header_layout = QGridLayout()
        header_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1,
                              1)
        header_layout.addWidget(header_icon, 1, 2)
        header_layout.addWidget(header_text, 1, 3)
        header_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1,
                              4)

        self.subtext_label = QLabel(self)
        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(13)
        else:
            font.setPointSize(10)
        self.subtext_label.setFont(font)
        self.subtext_label.setStyleSheet("color: grey")
        self.subtext_label.setWordWrap(True)
        self.subtext_label.setAlignment(Qt.AlignCenter)

        self.noise_label = QLabel()
        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(20)
        else:
            font.setPointSize(16)
        font.setFamily("Courier")
        font.setStyleHint(QFont.Monospace)
        self.noise_label.setFont(font)
        self.noise_label.setStyleSheet("color: grey")

        self.noise_timer = QTimer()
        self.noise_timer.timeout.connect(
            lambda: self.noise_label.setText(b58encode(os.urandom(16))))
        self.noise_timer.start(75)

        self.code_label = QLabel()
        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(22)
        else:
            font.setPointSize(18)
        self.code_label.setFont(font)
        self.code_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.code_label.hide()

        self.box_title = QLabel(self)
        self.box_title.setAlignment(Qt.AlignCenter)
        font = QFont()
        if sys.platform == 'darwin':
            font.setPointSize(20)
        else:
            font.setPointSize(16)
        self.box_title.setFont(font)

        self.box = QGroupBox()
        self.box.setAlignment(Qt.AlignCenter)
        self.box.setStyleSheet('QGroupBox {font-size: 16px}')

        self.copy_button = QToolButton()
        self.copy_button.setIcon(QIcon(resource('copy.png')))
        self.copy_button.setToolTip("Copy to clipboard")
        self.copy_button.setStyleSheet('border: 0px; padding: 0px;')
        self.copy_button.hide()

        box_layout = QGridLayout(self.box)
        box_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 1)
        box_layout.addWidget(self.noise_label, 1, 2)
        box_layout.addWidget(self.code_label, 1, 3)
        box_layout.addWidget(self.copy_button, 1, 4)
        box_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 5)

        self.close_button = QPushButton("Close and cancel invite")
        self.close_button.setAutoDefault(False)

        self.checkmark = QLabel()
        self.checkmark.setPixmap(
            QPixmap(resource('green_checkmark.png')).scaled(32, 32))
        self.checkmark.setAlignment(Qt.AlignCenter)
        self.checkmark.hide()

        self.tor_label = QLabel()
        self.tor_label.setToolTip(
            "This connection is being routed through the Tor network.")
        self.tor_label.setPixmap(
            QPixmap(resource('tor-onion.png')).scaled(24, 24,
                                                      Qt.KeepAspectRatio,
                                                      Qt.SmoothTransformation))
        self.tor_label.hide()

        self.progress_bar = QProgressBar()
        self.progress_bar.setMaximum(2)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.hide()

        layout = QGridLayout(self)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 0, 0)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 1)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 2)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 3)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 4)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 5)
        layout.addLayout(header_layout, 1, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 2, 1)
        layout.addWidget(self.box_title, 3, 2, 1, 3)
        layout.addWidget(self.checkmark, 3, 3)
        layout.addWidget(self.tor_label, 4, 1, 1, 1,
                         Qt.AlignRight | Qt.AlignVCenter)
        layout.addWidget(self.box, 4, 2, 1, 3)
        layout.addWidget(self.progress_bar, 4, 2, 1, 3)
        layout.addWidget(self.subtext_label, 5, 2, 1, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 6, 1)
        layout.addWidget(self.close_button, 7, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 8, 1)

        self.copy_button.clicked.connect(self.on_copy_button_clicked)
        self.close_button.clicked.connect(self.close)

        self.set_box_title("Generating invite code...")
        self.subtext_label.setText("Creating folder invite(s)...\n\n")

        if self.use_tor:
            self.tor_label.show()
            self.progress_bar.setStyleSheet(
                'QProgressBar::chunk {{ background-color: {}; }}'.format(
                    TOR_PURPLE))

        self.go()  # XXX

    def set_box_title(self, text):
        if sys.platform == 'darwin':
            self.box_title.setText(text)
            self.box_title.show()
        else:
            self.box.setTitle(text)

    def on_copy_button_clicked(self):
        code = self.code_label.text()
        for mode in get_clipboard_modes():
            set_clipboard_text(code, mode)
        self.subtext_label.setText(
            "Copied '{}' to clipboard!\n\n".format(code))

    def on_got_code(self, code):
        self.noise_timer.stop()
        self.noise_label.hide()
        self.set_box_title("Your invite code is:")
        self.code_label.setText(code)
        self.code_label.show()
        self.copy_button.show()
        if self.folder_names:
            if len(self.folder_names) == 1:
                abilities = 'download "{}" and modify its contents'.format(
                    self.folder_names[0])
            else:
                abilities = 'download {} and modify their contents'.format(
                    self.folder_names_humanized)
        else:
            abilities = 'connect to "{}" and upload new folders'.format(
                self.gateway.name)
        self.subtext_label.setText(
            "Entering this code on another device will allow it to {}.\n"
            "This code can only be used once.".format(abilities))

    def on_got_introduction(self):
        if sys.platform == 'darwin':
            self.box_title.hide()
        self.box.hide()
        self.progress_bar.show()
        self.progress_bar.setValue(1)
        self.subtext_label.setText("Connection established; sending invite...")

    def on_send_completed(self):
        self.box.hide()
        self.progress_bar.show()
        self.progress_bar.setValue(2)
        self.checkmark.show()
        self.close_button.setText("Finish")
        if self.folder_names:
            target = self.folder_names_humanized
        else:
            target = self.gateway.name
        text = "Your invitation to {} was accepted".format(target)
        self.subtext_label.setText("Invite successful!\n {} at {}".format(
            text,
            datetime.now().strftime('%H:%M')))
        if get_preference('notifications', 'invite') != 'false':
            self.gui.show_message("Invite successful", text)

        if self.folder_names:
            for view in self.gui.main_window.central_widget.views:
                if view.gateway.name == self.gateway.name:
                    for folder in self.folder_names:
                        # Immediately tell the Model that there are at least 2
                        # members for this folder, i.e., that it is now shared
                        view.model().on_members_updated(folder, [None, None])

    def handle_failure(self, failure):
        if failure.type == wormhole.errors.LonelyError:
            return
        logging.error(str(failure))
        show_failure(failure, self)
        self.invite_sender.cancel()
        self.close()

    def on_created_invite(self):
        self.subtext_label.setText("Opening wormhole...\n\n")

    def go(self):
        self.invite_sender = InviteSender(self.use_tor)
        self.invite_sender.created_invite.connect(self.on_created_invite)
        self.invite_sender.got_code.connect(self.on_got_code)
        self.invite_sender.got_introduction.connect(self.on_got_introduction)
        self.invite_sender.send_completed.connect(self.on_send_completed)
        self.invite_sender.send(self.gateway, self.folder_names).addErrback(
            self.handle_failure)

    def closeEvent(self, event):
        if self.code_label.text() and self.progress_bar.value() < 2:
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Question)
            msg.setWindowTitle("Cancel invitation?")
            msg.setText(
                'Are you sure you wish to cancel the invitation to "{}"?'.
                format(self.gateway.name))
            msg.setInformativeText(
                'The invite code "{}" will no longer be valid.'.format(
                    self.code_label.text()))
            msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            msg.setDefaultButton(QMessageBox.No)
            if msg.exec_() == QMessageBox.Yes:
                self.invite_sender.cancel()
                event.accept()
                self.closed.emit(self)
            else:
                event.ignore()
        else:
            event.accept()
            if self.noise_timer.isActive():
                self.noise_timer.stop()
            self.closed.emit(self)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()
Пример #14
0
class HelpTabWidget(E5TabWidget):
    """
    Class implementing the central widget showing the web pages.
    
    @signal sourceChanged(HelpBrowser, QUrl) emitted after the URL of a browser
        has changed
    @signal titleChanged(HelpBrowser, str) emitted after the title of a browser
        has changed
    @signal showMessage(str) emitted to show a message in the main window
        status bar
    @signal browserClosed(QWidget) emitted after a browser was closed
    @signal browserZoomValueChanged(int) emitted to signal a change of the
        current browser's zoom level
    """
    sourceChanged = pyqtSignal(HelpBrowser, QUrl)
    titleChanged = pyqtSignal(HelpBrowser, str)
    showMessage = pyqtSignal(str)
    browserClosed = pyqtSignal(QWidget)
    browserZoomValueChanged = pyqtSignal(int)

    def __init__(self, parent):
        """
        Constructor
        
        @param parent reference to the parent widget (QWidget)
        """
        E5TabWidget.__init__(self, parent, dnd=True)

        from .HelpTabBar import HelpTabBar
        self.__tabBar = HelpTabBar(self)
        self.setCustomTabBar(True, self.__tabBar)

        self.__mainWindow = parent

        self.setUsesScrollButtons(True)
        self.setDocumentMode(True)
        self.setElideMode(Qt.ElideNone)

        from .ClosedTabsManager import ClosedTabsManager
        self.__closedTabsManager = ClosedTabsManager(self)
        self.__closedTabsManager.closedTabAvailable.connect(
            self.__closedTabAvailable)

        from .UrlBar.StackedUrlBar import StackedUrlBar
        self.__stackedUrlBar = StackedUrlBar(self)
        self.__tabBar.tabMoved.connect(self.__stackedUrlBar.moveBar)

        self.__tabContextMenuIndex = -1
        self.currentChanged[int].connect(self.__currentChanged)
        self.setTabContextMenuPolicy(Qt.CustomContextMenu)
        self.customTabContextMenuRequested.connect(self.__showContextMenu)

        self.__rightCornerWidget = QWidget(self)
        self.__rightCornerWidgetLayout = QHBoxLayout(self.__rightCornerWidget)
        self.__rightCornerWidgetLayout.setContentsMargins(0, 0, 0, 0)
        self.__rightCornerWidgetLayout.setSpacing(0)

        self.__navigationMenu = QMenu(self)
        self.__navigationMenu.aboutToShow.connect(self.__showNavigationMenu)
        self.__navigationMenu.triggered.connect(self.__navigationMenuTriggered)

        self.__navigationButton = QToolButton(self)
        self.__navigationButton.setIcon(
            UI.PixmapCache.getIcon("1downarrow.png"))
        self.__navigationButton.setToolTip(self.tr("Show a navigation menu"))
        self.__navigationButton.setPopupMode(QToolButton.InstantPopup)
        self.__navigationButton.setMenu(self.__navigationMenu)
        self.__navigationButton.setEnabled(False)
        self.__rightCornerWidgetLayout.addWidget(self.__navigationButton)

        self.__closedTabsMenu = QMenu(self)
        self.__closedTabsMenu.aboutToShow.connect(
            self.__aboutToShowClosedTabsMenu)

        self.__closedTabsButton = QToolButton(self)
        self.__closedTabsButton.setIcon(UI.PixmapCache.getIcon("trash.png"))
        self.__closedTabsButton.setToolTip(
            self.tr("Show a navigation menu for closed tabs"))
        self.__closedTabsButton.setPopupMode(QToolButton.InstantPopup)
        self.__closedTabsButton.setMenu(self.__closedTabsMenu)
        self.__closedTabsButton.setEnabled(False)
        self.__rightCornerWidgetLayout.addWidget(self.__closedTabsButton)

        self.__closeButton = QToolButton(self)
        self.__closeButton.setIcon(UI.PixmapCache.getIcon("close.png"))
        self.__closeButton.setToolTip(self.tr("Close the current help window"))
        self.__closeButton.setEnabled(False)
        self.__closeButton.clicked.connect(self.closeBrowser)
        self.__rightCornerWidgetLayout.addWidget(self.__closeButton)
        if Preferences.getUI("SingleCloseButton") or \
           not hasattr(self, 'setTabsClosable'):
            self.__closeButton.show()
        else:
            self.setTabsClosable(True)
            self.tabCloseRequested.connect(self.closeBrowserAt)
            self.__closeButton.hide()

        self.setCornerWidget(self.__rightCornerWidget, Qt.TopRightCorner)

        self.__newTabButton = QToolButton(self)
        self.__newTabButton.setIcon(UI.PixmapCache.getIcon("plus.png"))
        self.__newTabButton.setToolTip(self.tr("Open a new help window tab"))
        self.setCornerWidget(self.__newTabButton, Qt.TopLeftCorner)
        self.__newTabButton.clicked.connect(self.__newBrowser)

        self.__initTabContextMenu()

        self.__historyCompleter = None

    def __initTabContextMenu(self):
        """
        Private method to create the tab context menu.
        """
        self.__tabContextMenu = QMenu(self)
        self.tabContextNewAct = self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("tabNew.png"), self.tr('New Tab'),
            self.newBrowser)
        self.__tabContextMenu.addSeparator()
        self.leftMenuAct = self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("1leftarrow.png"), self.tr('Move Left'),
            self.__tabContextMenuMoveLeft)
        self.rightMenuAct = self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("1rightarrow.png"), self.tr('Move Right'),
            self.__tabContextMenuMoveRight)
        self.__tabContextMenu.addSeparator()
        self.tabContextCloneAct = self.__tabContextMenu.addAction(
            self.tr("Duplicate Page"), self.__tabContextMenuClone)
        self.__tabContextMenu.addSeparator()
        self.tabContextCloseAct = self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("tabClose.png"), self.tr('Close'),
            self.__tabContextMenuClose)
        self.tabContextCloseOthersAct = self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("tabCloseOther.png"),
            self.tr("Close Others"), self.__tabContextMenuCloseOthers)
        self.__tabContextMenu.addAction(self.tr('Close All'),
                                        self.closeAllBrowsers)
        self.__tabContextMenu.addSeparator()
        self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("printPreview.png"),
            self.tr('Print Preview'), self.__tabContextMenuPrintPreview)
        self.__tabContextMenu.addAction(UI.PixmapCache.getIcon("print.png"),
                                        self.tr('Print'),
                                        self.__tabContextMenuPrint)
        if Globals.isLinuxPlatform():
            self.__tabContextMenu.addAction(
                UI.PixmapCache.getIcon("printPdf.png"),
                self.tr('Print as PDF'), self.__tabContextMenuPrintPdf)
        self.__tabContextMenu.addSeparator()
        self.__tabContextMenu.addAction(UI.PixmapCache.getIcon("reload.png"),
                                        self.tr('Reload All'),
                                        self.reloadAllBrowsers)
        self.__tabContextMenu.addSeparator()
        self.__tabContextMenu.addAction(
            UI.PixmapCache.getIcon("addBookmark.png"),
            self.tr('Bookmark All Tabs'), self.__mainWindow.bookmarkAll)

        self.__tabBackContextMenu = QMenu(self)
        self.__tabBackContextMenu.addAction(self.tr('Close All'),
                                            self.closeAllBrowsers)
        self.__tabBackContextMenu.addAction(
            UI.PixmapCache.getIcon("reload.png"), self.tr('Reload All'),
            self.reloadAllBrowsers)
        self.__tabBackContextMenu.addAction(
            UI.PixmapCache.getIcon("addBookmark.png"),
            self.tr('Bookmark All Tabs'), self.__mainWindow.bookmarkAll)
        self.__tabBackContextMenu.addSeparator()
        self.__restoreClosedTabAct = self.__tabBackContextMenu.addAction(
            UI.PixmapCache.getIcon("trash.png"), self.tr('Restore Closed Tab'),
            self.restoreClosedTab)
        self.__restoreClosedTabAct.setEnabled(False)
        self.__restoreClosedTabAct.setData(0)

    def __showContextMenu(self, coord, index):
        """
        Private slot to show the tab context menu.
        
        @param coord the position of the mouse pointer (QPoint)
        @param index index of the tab the menu is requested for (integer)
        """
        coord = self.mapToGlobal(coord)
        if index == -1:
            self.__tabBackContextMenu.popup(coord)
        else:
            self.__tabContextMenuIndex = index
            self.leftMenuAct.setEnabled(index > 0)
            self.rightMenuAct.setEnabled(index < self.count() - 1)

            self.tabContextCloseOthersAct.setEnabled(self.count() > 1)

            self.__tabContextMenu.popup(coord)

    def __tabContextMenuMoveLeft(self):
        """
        Private method to move a tab one position to the left.
        """
        self.moveTab(self.__tabContextMenuIndex,
                     self.__tabContextMenuIndex - 1)

    def __tabContextMenuMoveRight(self):
        """
        Private method to move a tab one position to the right.
        """
        self.moveTab(self.__tabContextMenuIndex,
                     self.__tabContextMenuIndex + 1)

    def __tabContextMenuClone(self):
        """
        Private method to clone the selected tab.
        """
        idx = self.__tabContextMenuIndex
        if idx < 0:
            idx = self.currentIndex()
        if idx < 0 or idx > self.count():
            return

        req = QNetworkRequest(self.widget(idx).url())
        req.setRawHeader(b"X-Eric6-UserLoadAction", b"1")
        self.newBrowser(None, (req, QNetworkAccessManager.GetOperation, b""))

    def __tabContextMenuClose(self):
        """
        Private method to close the selected tab.
        """
        self.closeBrowserAt(self.__tabContextMenuIndex)

    def __tabContextMenuCloseOthers(self):
        """
        Private slot to close all other tabs.
        """
        index = self.__tabContextMenuIndex
        for i in list(range(self.count() - 1, index, -1)) + \
                list(range(index - 1, -1, -1)):
            self.closeBrowserAt(i)

    def __tabContextMenuPrint(self):
        """
        Private method to print the selected tab.
        """
        browser = self.widget(self.__tabContextMenuIndex)
        self.printBrowser(browser)

    def __tabContextMenuPrintPdf(self):
        """
        Private method to print the selected tab as PDF.
        """
        browser = self.widget(self.__tabContextMenuIndex)
        self.printBrowserPdf(browser)

    def __tabContextMenuPrintPreview(self):
        """
        Private method to show a print preview of the selected tab.
        """
        browser = self.widget(self.__tabContextMenuIndex)
        self.printPreviewBrowser(browser)

    @pyqtSlot()
    def __newBrowser(self):
        """
        Private slot to open a new browser tab.
        """
        self.newBrowser()

    def newBrowser(self, link=None, requestData=None, position=-1):
        """
        Public method to create a new web browser tab.
        
        @param link link to be shown (string or QUrl)
        @param requestData tuple containing the request data (QNetworkRequest,
            QNetworkAccessManager.Operation, QByteArray)
        @keyparam position position to create the new tab at or -1 to add it
            to the end (integer)
        """
        if link is None:
            linkName = ""
        elif isinstance(link, QUrl):
            linkName = link.toString()
        else:
            linkName = link

        from .UrlBar.UrlBar import UrlBar
        urlbar = UrlBar(self.__mainWindow, self)
        if self.__historyCompleter is None:
            import Helpviewer.HelpWindow
            from .History.HistoryCompleter import HistoryCompletionModel, \
                HistoryCompleter
            self.__historyCompletionModel = HistoryCompletionModel(self)
            self.__historyCompletionModel.setSourceModel(
                Helpviewer.HelpWindow.HelpWindow.historyManager(
                ).historyFilterModel())
            self.__historyCompleter = HistoryCompleter(
                self.__historyCompletionModel, self)
            self.__historyCompleter.activated[str].connect(self.__pathSelected)
        urlbar.setCompleter(self.__historyCompleter)
        urlbar.returnPressed.connect(self.__lineEditReturnPressed)
        if position == -1:
            self.__stackedUrlBar.addWidget(urlbar)
        else:
            self.__stackedUrlBar.insertWidget(position, urlbar)

        browser = HelpBrowser(self.__mainWindow, self)
        urlbar.setBrowser(browser)

        browser.sourceChanged.connect(self.__sourceChanged)
        browser.titleChanged.connect(self.__titleChanged)
        browser.highlighted.connect(self.showMessage)
        browser.backwardAvailable.connect(
            self.__mainWindow.setBackwardAvailable)
        browser.forwardAvailable.connect(self.__mainWindow.setForwardAvailable)
        browser.loadStarted.connect(self.__loadStarted)
        browser.loadFinished.connect(self.__loadFinished)
        browser.iconChanged.connect(self.__iconChanged)
        browser.search.connect(self.newBrowser)
        browser.page().windowCloseRequested.connect(
            self.__windowCloseRequested)
        browser.page().printRequested.connect(self.__printRequested)
        browser.zoomValueChanged.connect(self.browserZoomValueChanged)

        if position == -1:
            index = self.addTab(browser, self.tr("..."))
        else:
            index = self.insertTab(position, browser, self.tr("..."))
        self.setCurrentIndex(index)

        self.__mainWindow.closeAct.setEnabled(True)
        self.__mainWindow.closeAllAct.setEnabled(True)
        self.__closeButton.setEnabled(True)
        self.__navigationButton.setEnabled(True)

        if not linkName and not requestData:
            if Preferences.getHelp("StartupBehavior") == 0:
                linkName = Preferences.getHelp("HomePage")
            elif Preferences.getHelp("StartupBehavior") == 1:
                linkName = "eric:speeddial"

        if linkName:
            browser.setSource(QUrl(linkName))
            if not browser.documentTitle():
                self.setTabText(index, self.__elide(linkName, Qt.ElideMiddle))
                self.setTabToolTip(index, linkName)
            else:
                self.setTabText(
                    index,
                    self.__elide(browser.documentTitle().replace("&", "&&")))
                self.setTabToolTip(index, browser.documentTitle())
        elif requestData:
            browser.load(*requestData)

    def newBrowserAfter(self, browser, link=None, requestData=None):
        """
        Public method to create a new web browser tab after a given one.
        
        @param browser reference to the browser to add after (HelpBrowser)
        @param link link to be shown (string or QUrl)
        @param requestData tuple containing the request data (QNetworkRequest,
            QNetworkAccessManager.Operation, QByteArray)
        """
        if browser:
            position = self.indexOf(browser) + 1
        else:
            position = -1
        self.newBrowser(link, requestData, position)

    def __showNavigationMenu(self):
        """
        Private slot to show the navigation button menu.
        """
        self.__navigationMenu.clear()
        for index in range(self.count()):
            act = self.__navigationMenu.addAction(self.tabIcon(index),
                                                  self.tabText(index))
            act.setData(index)

    def __navigationMenuTriggered(self, act):
        """
        Private slot called to handle the navigation button menu selection.
        
        @param act reference to the selected action (QAction)
        """
        index = act.data()
        if index is not None:
            self.setCurrentIndex(index)

    def __windowCloseRequested(self):
        """
        Private slot to handle the windowCloseRequested signal of a browser.
        """
        page = self.sender()
        if page is None:
            return

        browser = page.view()
        if browser is None:
            return

        index = self.indexOf(browser)
        self.closeBrowserAt(index)

    def reloadAllBrowsers(self):
        """
        Public slot to reload all browsers.
        """
        for index in range(self.count()):
            browser = self.widget(index)
            browser and browser.reload()

    @pyqtSlot()
    def closeBrowser(self):
        """
        Public slot called to handle the close action.
        """
        self.closeBrowserAt(self.currentIndex())

    def closeAllBrowsers(self):
        """
        Public slot called to handle the close all action.
        """
        for index in range(self.count() - 1, -1, -1):
            self.closeBrowserAt(index)

    def closeBrowserAt(self, index):
        """
        Public slot to close a browser based on its index.
        
        @param index index of browser to close (integer)
        """
        browser = self.widget(index)
        if browser is None:
            return

        if browser.isModified():
            ok = E5MessageBox.yesNo(
                self, self.tr("Do you really want to close this page?"),
                self.tr("""You have modified this page and when closing it"""
                        """ you would lose the modification.\nDo you really"""
                        """ want to close this page?"""))
            if not ok:
                return

        urlbar = self.__stackedUrlBar.widget(index)
        self.__stackedUrlBar.removeWidget(urlbar)
        urlbar.deleteLater()
        del urlbar

        self.__closedTabsManager.recordBrowser(browser, index)

        browser.closeWebInspector()
        browser.home()
        self.removeTab(index)
        self.browserClosed.emit(browser)
        browser.deleteLater()
        del browser

        if self.count() == 0:
            self.newBrowser()
        else:
            self.currentChanged[int].emit(self.currentIndex())

    def currentBrowser(self):
        """
        Public method to get a reference to the current browser.
        
        @return reference to the current browser (HelpBrowser)
        """
        return self.currentWidget()

    def browserAt(self, index):
        """
        Public method to get a reference to the browser with the given index.
        
        @param index index of the browser to get (integer)
        @return reference to the indexed browser (HelpBrowser)
        """
        return self.widget(index)

    def browsers(self):
        """
        Public method to get a list of references to all browsers.
        
        @return list of references to browsers (list of HelpBrowser)
        """
        li = []
        for index in range(self.count()):
            li.append(self.widget(index))
        return li

    @pyqtSlot()
    def printBrowser(self, browser=None):
        """
        Public slot called to print the displayed page.
        
        @param browser reference to the browser to be printed (HelpBrowser)
        """
        if browser is None:
            browser = self.currentBrowser()

        self.__printRequested(browser.page().mainFrame())

    def __printRequested(self, frame):
        """
        Private slot to handle a print request.
        
        @param frame reference to the frame to be printed (QWebFrame)
        """
        printer = QPrinter(mode=QPrinter.HighResolution)
        if Preferences.getPrinter("ColorMode"):
            printer.setColorMode(QPrinter.Color)
        else:
            printer.setColorMode(QPrinter.GrayScale)
        if Preferences.getPrinter("FirstPageFirst"):
            printer.setPageOrder(QPrinter.FirstPageFirst)
        else:
            printer.setPageOrder(QPrinter.LastPageFirst)
        printer.setPageMargins(
            Preferences.getPrinter("LeftMargin") * 10,
            Preferences.getPrinter("TopMargin") * 10,
            Preferences.getPrinter("RightMargin") * 10,
            Preferences.getPrinter("BottomMargin") * 10, QPrinter.Millimeter)
        printerName = Preferences.getPrinter("PrinterName")
        if printerName:
            printer.setPrinterName(printerName)

        printDialog = QPrintDialog(printer, self)
        if printDialog.exec_() == QDialog.Accepted:
            try:
                frame.print_(printer)
            except AttributeError:
                E5MessageBox.critical(
                    self, self.tr("Pymakr Web Browser"),
                    self.tr("""<p>Printing is not available due to a bug in"""
                            """ PyQt5. Please upgrade.</p>"""))
                return

    @pyqtSlot()
    def printBrowserPdf(self, browser=None):
        """
        Public slot called to print the displayed page to PDF.
        
        @param browser reference to the browser to be printed (HelpBrowser)
        """
        if browser is None:
            browser = self.currentBrowser()

        self.__printPdfRequested(browser.page().mainFrame())

    def __printPdfRequested(self, frame):
        """
        Private slot to handle a print to PDF request.
        
        @param frame reference to the frame to be printed (QWebFrame)
        """
        printer = QPrinter(mode=QPrinter.HighResolution)
        if Preferences.getPrinter("ColorMode"):
            printer.setColorMode(QPrinter.Color)
        else:
            printer.setColorMode(QPrinter.GrayScale)
        printerName = Preferences.getPrinter("PrinterName")
        if printerName:
            printer.setPrinterName(printerName)
        printer.setOutputFormat(QPrinter.PdfFormat)
        name = frame.url().path().rsplit('/', 1)[-1]
        if name:
            name = name.rsplit('.', 1)[0]
            name += '.pdf'
            printer.setOutputFileName(name)

        printDialog = QPrintDialog(printer, self)
        if printDialog.exec_() == QDialog.Accepted:
            try:
                frame.print_(printer)
            except AttributeError:
                E5MessageBox.critical(
                    self, self.tr("Pymakr Web Browser"),
                    self.tr("""<p>Printing is not available due to a bug in"""
                            """ PyQt5. Please upgrade.</p>"""))
                return

    @pyqtSlot()
    def printPreviewBrowser(self, browser=None):
        """
        Public slot called to show a print preview of the displayed file.
        
        @param browser reference to the browser to be printed (HelpBrowserWV)
        """
        from PyQt5.QtPrintSupport import QPrintPreviewDialog

        if browser is None:
            browser = self.currentBrowser()

        printer = QPrinter(mode=QPrinter.HighResolution)
        if Preferences.getPrinter("ColorMode"):
            printer.setColorMode(QPrinter.Color)
        else:
            printer.setColorMode(QPrinter.GrayScale)
        if Preferences.getPrinter("FirstPageFirst"):
            printer.setPageOrder(QPrinter.FirstPageFirst)
        else:
            printer.setPageOrder(QPrinter.LastPageFirst)
        printer.setPageMargins(
            Preferences.getPrinter("LeftMargin") * 10,
            Preferences.getPrinter("TopMargin") * 10,
            Preferences.getPrinter("RightMargin") * 10,
            Preferences.getPrinter("BottomMargin") * 10, QPrinter.Millimeter)
        printerName = Preferences.getPrinter("PrinterName")
        if printerName:
            printer.setPrinterName(printerName)

        self.__printPreviewBrowser = browser
        preview = QPrintPreviewDialog(printer, self)
        preview.paintRequested.connect(self.__printPreview)
        preview.exec_()

    def __printPreview(self, printer):
        """
        Private slot to generate a print preview.
        
        @param printer reference to the printer object (QPrinter)
        """
        try:
            self.__printPreviewBrowser.print_(printer)
        except AttributeError:
            E5MessageBox.critical(
                self, self.tr("Pymakr Web Browser"),
                self.tr(
                    """<p>Printing is not available due to a bug in PyQt5."""
                    """Please upgrade.</p>"""))
            return

    def __sourceChanged(self, url):
        """
        Private slot to handle a change of a browsers source.
        
        @param url URL of the new site (QUrl)
        """
        browser = self.sender()

        if browser is not None:
            self.sourceChanged.emit(browser, url)

    def __titleChanged(self, title):
        """
        Private slot to handle a change of a browsers title.
        
        @param title new title (string)
        """
        browser = self.sender()

        if browser is not None and isinstance(browser, QWidget):
            index = self.indexOf(browser)
            if title == "":
                title = browser.url().toString()

            self.setTabText(index, self.__elide(title.replace("&", "&&")))
            self.setTabToolTip(index, title)

            self.titleChanged.emit(browser, title)

    def __elide(self, txt, mode=Qt.ElideRight, length=40):
        """
        Private method to elide some text.
        
        @param txt text to be elided (string)
        @keyparam mode elide mode (Qt.TextElideMode)
        @keyparam length amount of characters to be used (integer)
        @return the elided text (string)
        """
        if mode == Qt.ElideNone or len(txt) < length:
            return txt
        elif mode == Qt.ElideLeft:
            return "...{0}".format(txt[-length:])
        elif mode == Qt.ElideMiddle:
            return "{0}...{1}".format(txt[:length // 2], txt[-(length // 2):])
        elif mode == Qt.ElideRight:
            return "{0}...".format(txt[:length])
        else:
            # just in case
            return txt

    def preferencesChanged(self):
        """
        Public slot to handle a change of preferences.
        """
        for browser in self.browsers():
            browser.preferencesChanged()

        for urlbar in self.__stackedUrlBar.urlBars():
            urlbar.preferencesChanged()

        if Preferences.getUI("SingleCloseButton") or \
           not hasattr(self, 'setTabsClosable'):
            if hasattr(self, 'setTabsClosable'):
                self.setTabsClosable(False)
                try:
                    self.tabCloseRequested.disconnect(self.closeBrowserAt)
                except TypeError:
                    pass
            self.__closeButton.show()
        else:
            self.setTabsClosable(True)
            self.tabCloseRequested.connect(self.closeBrowserAt)
            self.__closeButton.hide()

    def __loadStarted(self):
        """
        Private method to handle the loadStarted signal.
        """
        browser = self.sender()

        if browser is not None:
            index = self.indexOf(browser)
            anim = self.animationLabel(
                index, os.path.join(getConfig("ericPixDir"), "loading.gif"),
                100)
            if not anim:
                loading = QIcon(
                    os.path.join(getConfig("ericPixDir"), "loading.gif"))
                self.setTabIcon(index, loading)
            else:
                self.setTabIcon(index, QIcon())
            self.setTabText(index, self.tr("Loading..."))
            self.setTabToolTip(index, self.tr("Loading..."))
            self.showMessage.emit(self.tr("Loading..."))

            self.__mainWindow.setLoadingActions(True)

    def __loadFinished(self, ok):
        """
        Private method to handle the loadFinished signal.
        
        @param ok flag indicating the result (boolean)
        """
        browser = self.sender()
        if not isinstance(browser, HelpBrowser):
            return

        if browser is not None:
            import Helpviewer.HelpWindow
            index = self.indexOf(browser)
            self.resetAnimation(index)
            self.setTabIcon(
                index, Helpviewer.HelpWindow.HelpWindow.icon(browser.url()))
            if ok:
                self.showMessage.emit(self.tr("Finished loading"))
            else:
                self.showMessage.emit(self.tr("Failed to load"))

            self.__mainWindow.setLoadingActions(False)

    def __iconChanged(self):
        """
        Private slot to handle the icon change.
        """
        browser = self.sender()

        if browser is not None and isinstance(browser, QWidget):
            import Helpviewer.HelpWindow
            self.setTabIcon(
                self.indexOf(browser),
                Helpviewer.HelpWindow.HelpWindow.icon(browser.url()))
            Helpviewer.HelpWindow.HelpWindow.bookmarksManager()\
                .iconChanged(browser.url())

    def getSourceFileList(self):
        """
        Public method to get a list of all opened source files.
        
        @return dictionary with tab id as key and host/namespace as value
        """
        sourceList = {}
        for i in range(self.count()):
            browser = self.widget(i)
            if browser is not None and \
               browser.source().isValid():
                sourceList[i] = browser.source().host()

        return sourceList

    def shallShutDown(self):
        """
        Public method to check, if the application should be shut down.
        
        @return flag indicating a shut down (boolean)
        """
        if self.count() > 1 and Preferences.getHelp("WarnOnMultipleClose"):
            mb = E5MessageBox.E5MessageBox(
                E5MessageBox.Information,
                self.tr("Are you sure you want to close the window?"),
                self.tr(
                    """Are you sure you want to close the window?\n"""
                    """You have %n tab(s) open.""", "", self.count()),
                modal=True,
                parent=self)
            if self.__mainWindow.fromEric:
                quitButton = mb.addButton(self.tr("&Close"),
                                          E5MessageBox.AcceptRole)
                quitButton.setIcon(UI.PixmapCache.getIcon("close.png"))
            else:
                quitButton = mb.addButton(self.tr("&Quit"),
                                          E5MessageBox.AcceptRole)
                quitButton.setIcon(UI.PixmapCache.getIcon("exit.png"))
            closeTabButton = mb.addButton(self.tr("C&lose Current Tab"),
                                          E5MessageBox.AcceptRole)
            closeTabButton.setIcon(UI.PixmapCache.getIcon("tabClose.png"))
            mb.addButton(E5MessageBox.Cancel)
            mb.exec_()
            if mb.clickedButton() == quitButton:
                return True
            else:
                if mb.clickedButton() == closeTabButton:
                    self.closeBrowser()
                return False

        return True

    def stackedUrlBar(self):
        """
        Public method to get a reference to the stacked url bar.
        
        @return reference to the stacked url bar (StackedUrlBar)
        """
        return self.__stackedUrlBar

    def currentUrlBar(self):
        """
        Public method to get a reference to the current url bar.
        
        @return reference to the current url bar (UrlBar)
        """
        return self.__stackedUrlBar.currentWidget()

    def __lineEditReturnPressed(self):
        """
        Private slot to handle the entering of an URL.
        """
        edit = self.sender()
        url = self.__guessUrlFromPath(edit.text())
        request = QNetworkRequest(url)
        request.setRawHeader(b"X-Eric6-UserLoadAction", b"1")
        if e5App().keyboardModifiers() == Qt.AltModifier:
            self.newBrowser(None,
                            (request, QNetworkAccessManager.GetOperation, b""))
        else:
            self.currentBrowser().setSource(
                None, (request, QNetworkAccessManager.GetOperation, b""))
            self.currentBrowser().setFocus()

    def __pathSelected(self, path):
        """
        Private slot called when a URL is selected from the completer.
        
        @param path path to be shown (string)
        """
        url = self.__guessUrlFromPath(path)
        self.currentBrowser().setSource(url)

    def __guessUrlFromPath(self, path):
        """
        Private method to guess an URL given a path string.
        
        @param path path string to guess an URL for (string)
        @return guessed URL (QUrl)
        """
        manager = self.__mainWindow.openSearchManager()
        path = Utilities.fromNativeSeparators(path)
        url = manager.convertKeywordSearchToUrl(path)
        if url.isValid():
            return url

        try:
            url = QUrl.fromUserInput(path)
        except AttributeError:
            url = QUrl(path)

        if url.scheme() == "about" and \
           url.path() == "home":
            url = QUrl("eric:home")

        if url.scheme() in ["s", "search"]:
            url = manager.currentEngine().searchUrl(url.path().strip())

        if url.scheme() != "" and \
           (url.host() != "" or url.path() != ""):
            return url

        urlString = Preferences.getHelp("DefaultScheme") + path.strip()
        url = QUrl.fromEncoded(urlString.encode("utf-8"), QUrl.TolerantMode)

        return url

    def __currentChanged(self, index):
        """
        Private slot to handle an index change.
        
        @param index new index (integer)
        """
        self.__stackedUrlBar.setCurrentIndex(index)

        browser = self.browserAt(index)
        if browser is not None:
            if browser.url() == "" and browser.hasFocus():
                self.__stackedUrlBar.currentWidget.setFocus()
            elif browser.url() != "":
                browser.setFocus()

    def restoreClosedTab(self):
        """
        Public slot to restore the most recently closed tab.
        """
        if not self.canRestoreClosedTab():
            return

        act = self.sender()
        tab = self.__closedTabsManager.getClosedTabAt(act.data())

        self.newBrowser(tab.url.toString(), position=tab.position)

    def canRestoreClosedTab(self):
        """
        Public method to check, if closed tabs can be restored.
        
        @return flag indicating that closed tabs can be restored (boolean)
        """
        return self.__closedTabsManager.isClosedTabAvailable()

    def restoreAllClosedTabs(self):
        """
        Public slot to restore all closed tabs.
        """
        if not self.canRestoreClosedTab():
            return

        for tab in self.__closedTabsManager.allClosedTabs():
            self.newBrowser(tab.url.toString(), position=tab.position)
        self.__closedTabsManager.clearList()

    def clearClosedTabsList(self):
        """
        Public slot to clear the list of closed tabs.
        """
        self.__closedTabsManager.clearList()

    def __aboutToShowClosedTabsMenu(self):
        """
        Private slot to populate the closed tabs menu.
        """
        fm = self.__closedTabsMenu.fontMetrics()
        maxWidth = fm.width('m') * 40

        self.__closedTabsMenu.clear()
        index = 0
        for tab in self.__closedTabsManager.allClosedTabs():
            title = fm.elidedText(tab.title, Qt.ElideRight, maxWidth)
            self.__closedTabsMenu.addAction(self.__mainWindow.icon(
                tab.url), title, self.restoreClosedTab).setData(index)
            index += 1
        self.__closedTabsMenu.addSeparator()
        self.__closedTabsMenu.addAction(self.tr("Restore All Closed Tabs"),
                                        self.restoreAllClosedTabs)
        self.__closedTabsMenu.addAction(self.tr("Clear List"),
                                        self.clearClosedTabsList)

    def closedTabsManager(self):
        """
        Public slot to get a reference to the closed tabs manager.
        
        @return reference to the closed tabs manager (ClosedTabsManager)
        """
        return self.__closedTabsManager

    def __closedTabAvailable(self, avail):
        """
        Private slot to handle changes of the availability of closed tabs.
        
        @param avail flag indicating the availability of closed tabs (boolean)
        """
        self.__closedTabsButton.setEnabled(avail)
        self.__restoreClosedTabAct.setEnabled(avail)
Пример #15
0
class MacroTab(QVBoxLayout):

    changed = pyqtSignal()
    record = pyqtSignal(object, bool)
    record_stop = pyqtSignal()

    def __init__(self, enable_recorder):
        super().__init__()

        self.lines = []

        self.container = QGridLayout()

        menu_record = QMenu()
        menu_record.addAction(tr("MacroRecorder", "Append to current"))\
            .triggered.connect(lambda: self.record.emit(self, True))
        menu_record.addAction(tr("MacroRecorder", "Replace everything"))\
            .triggered.connect(lambda: self.record.emit(self, False))

        self.btn_record = QPushButton(tr("MacroRecorder", "Record macro"))
        self.btn_record.setMenu(menu_record)
        if not enable_recorder:
            self.btn_record.hide()

        self.btn_record_stop = QPushButton(
            tr("MacroRecorder", "Stop recording"))
        self.btn_record_stop.clicked.connect(lambda: self.record_stop.emit())
        self.btn_record_stop.hide()

        self.btn_add = QToolButton()
        self.btn_add.setText(tr("MacroRecorder", "Add action"))
        self.btn_add.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_add.clicked.connect(self.on_add)

        self.btn_tap_enter = QToolButton()
        self.btn_tap_enter.setText(tr("MacroRecorder", "Tap Enter"))
        self.btn_tap_enter.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_tap_enter.clicked.connect(self.on_tap_enter)

        layout_buttons = QHBoxLayout()
        layout_buttons.addStretch()
        layout_buttons.addWidget(self.btn_add)
        layout_buttons.addWidget(self.btn_tap_enter)
        layout_buttons.addWidget(self.btn_record)
        layout_buttons.addWidget(self.btn_record_stop)

        vbox = QVBoxLayout()
        vbox.addLayout(self.container)
        vbox.addStretch()

        w = QWidget()
        w.setLayout(vbox)
        w.setObjectName("w")
        scroll = QScrollArea()
        scroll.setFrameShape(QFrame.NoFrame)
        scroll.setStyleSheet("QScrollArea { background-color:transparent; }")
        w.setStyleSheet("#w { background-color:transparent; }")
        scroll.setWidgetResizable(True)
        scroll.setWidget(w)

        self.addWidget(scroll)
        self.addLayout(layout_buttons)

    def add_action(self, act):
        line = MacroLine(self, act)
        line.changed.connect(self.on_change)
        self.lines.append(line)
        line.insert(len(self.lines) - 1)
        self.changed.emit()

    def on_add(self):
        self.add_action(ActionText(self.container))

    def on_remove(self, obj):
        for line in self.lines:
            if line == obj:
                line.remove()
                line.delete()
        self.lines.remove(obj)
        for line in self.lines:
            line.remove()
        for x, line in enumerate(self.lines):
            line.insert(x)
        self.changed.emit()

    def clear(self):
        for line in self.lines[:]:
            self.on_remove(line)

    def on_move(self, obj, offset):
        if offset == 0:
            return
        index = self.lines.index(obj)
        if index + offset < 0 or index + offset >= len(self.lines):
            return
        other = self.lines.index(self.lines[index + offset])
        self.lines[index].remove()
        self.lines[other].remove()
        self.lines[index], self.lines[other] = self.lines[other], self.lines[
            index]
        self.lines[index].insert(index)
        self.lines[other].insert(other)
        self.changed.emit()

    def serialize(self):
        out = b""
        for line in self.lines:
            out += line.serialize()
        return out

    def deserialize(self, data):
        self.clear()

        sequence = []
        data = bytearray(data)
        while len(data) > 0:
            if data[0] in [SS_TAP_CODE, SS_DOWN_CODE, SS_UP_CODE]:
                # append to previous *_CODE if it's the same type, otherwise create a new entry
                if len(sequence) > 0 and isinstance(
                        sequence[-1], list) and sequence[-1][0] == data[0]:
                    sequence[-1][1].append(data[1])
                else:
                    sequence.append([data[0], [data[1]]])

                data.pop(0)
                data.pop(0)
            else:
                # append to previous string if it is a string, otherwise create a new entry
                ch = chr(data[0])
                if len(sequence) > 0 and isinstance(sequence[-1], str):
                    sequence[-1] += ch
                else:
                    sequence.append(ch)
                data.pop(0)
        for s in sequence:
            if isinstance(s, str):
                self.add_action(ActionText(self.container, s))
            else:
                # map integer values to qmk keycodes
                keycodes = []
                for code in s[1]:
                    keycode = find_keycode(code)
                    if keycode:
                        keycodes.append(keycode)
                cls = {
                    SS_TAP_CODE: ActionTap,
                    SS_DOWN_CODE: ActionDown,
                    SS_UP_CODE: ActionUp
                }[s[0]]
                self.add_action(cls(self.container, keycodes))

    def on_change(self):
        self.changed.emit()

    def on_tap_enter(self):
        self.add_action(ActionTap(self.container, [find_keycode(0x28)]))

    def pre_record(self):
        self.btn_record.hide()
        self.btn_add.hide()
        self.btn_tap_enter.hide()
        self.btn_record_stop.show()

    def post_record(self):
        self.btn_record.show()
        self.btn_add.show()
        self.btn_tap_enter.show()
        self.btn_record_stop.hide()
Пример #16
0
class mqtw(QWidget):
    setDataFinished = pyqtSignal()
    tableSelectionChanged = pyqtSignal()

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.parent = parent
        self.lay = QVBoxLayout()
        self.laySearch = QHBoxLayout()
        self.lbl = QLabel()

        self.table = QTableWidget()
        self.table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.table.verticalScrollBar().valueChanged.connect(
            self.on_table_verticalscrollbar_value_changed)
        self.table.horizontalHeader().sectionClicked.connect(
            self.on_table_horizontalHeader_sectionClicked)
        self.table.itemSelectionChanged.connect(self.on_itemSelectionChanged)
        self.table.verticalHeader().hide()
        self.setSelectionMode(QAbstractItemView.SelectRows,
                              QAbstractItemView.SingleSelection)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setAlternatingRowColors(True)

        self.lbl.setText(self.tr("Add a string to filter rows"))
        self.txtSearch = QLineEdit()
        self.txtSearch.textChanged.connect(self.on_txt_textChanged)
        self.cmdCloseSearch = QToolButton()
        self.cmdCloseSearch.setIcon(QIcon(":/reusingcode/button_cancel.png"))
        self.showSearchOptions(False)
        self.cmdCloseSearch.released.connect(self.on_cmdCloseSearch_released)
        self.laySearch.addWidget(self.lbl)
        self.laySearch.addWidget(self.txtSearch)
        self.laySearch.addWidget(self.cmdCloseSearch)
        self.lay.addWidget(self.table)
        self.table.verticalScrollBar().valueChanged.connect(
            self.on_table_verticalscrollbar_value_changed)
        self.lay.addLayout(self.laySearch)
        self.setLayout(self.lay)

        self.actionExport = QAction(self.tr("Export to Libreoffice Calc"))
        self.actionExport.setIcon(QIcon(":/reusingcode/libreoffice_calc.png"))
        self.actionExport.triggered.connect(self.on_actionExport_triggered)

        self.actionSizeMinimum = QAction(self.tr("Minimum column size"))
        self.actionSizeMinimum.triggered.connect(
            self.on_actionSizeMinimum_triggered)
        self.actionSizeNeeded = QAction(self.tr("Needed column size"))
        self.actionSizeNeeded.triggered.connect(
            self.on_actionSizeNeeded_triggered)

        self.actionSearch = QAction(self.tr("Search in table"))
        self.actionSearch.setIcon(QIcon(":/reusingcode/search.png"))
        self.actionSearch.triggered.connect(self.on_actionSearch_triggered)
        self.actionSearch.setShortcut(Qt.CTRL + Qt.Key_F)

        self._last_height = None
        self._none_at_top = True
        self._sort_action_reverse = None  #Needed for first setData
        self._ordering_enabled = False
        self.selected = None  #Must be initializated
        self.selected_items = None
        self.auxiliar = None  #Auxiliar value, sometimes I need to pass some value between mqtw and myqtw_additional (For example, active), this attribute helps to do it

    ## Sets if ordering must be enabled
    ## In mqtw id False by default. In mqtwManager and mqtwObjects is True by default
    ## @param boolean Booleano to set if ordering is enabled
    def setOrderingEnabled(self, boolean):
        self._ordering_enabled = boolean

    @pyqtSlot()
    ## This is for mqtw only object
    def on_itemSelectionChanged(self):
        self.selected_items = None
        self.selected = None
        if hasattr(self, "data"):  #Data is set
            if self.table.selectionBehavior(
            ) == QAbstractItemView.SelectRows and self.table.selectionMode(
            ) == QAbstractItemView.SingleSelection:
                # In this case returns a list with all items of the row
                self.selected_items = []
                self.selected = []
                for i in self.table.selectedItems():
                    if i.row() >= len(
                            self.data
                    ):  ## Se pulsa un row fuera del data, por ejemplo un total
                        self.selected_items == None
                        self.selected == None
                        break
                    self.selected_items.append(i)
                    self.selected.append(self.itemData(i))
            elif self.table.selectionBehavior(
            ) == QAbstractItemView.SelectRows and self.table.selectionMode(
            ) == QAbstractItemView.MultiSelection:
                # In this case returns a list or rows
                error(
                    "This method fails if there is a wdgBool due to selecteditems only shows QTableWidgetItem"
                )
                self.selected_items = []
                self.selected = []
                lastrow = []
                lastrowitems = []
                for i in self.table.selectedItems():
                    if i.row() >= len(
                            self.data
                    ):  ## Se pulsa un row fuera del data, por ejemplo un total
                        self.selected_items == None
                        self.selected == None
                        break
                    lastrowitems.append(i)
                    lastrow.append(self.itemData(i))
                    if len(lastrow) == self.lengthRow(
                    ):  #Create a new row if len lastrow == leng. Minus 1 because it adds the last
                        self.selected.append(lastrow)
                        self.selected_items.append(lastrowitems)
                        lastrow = []
                        lastrowitems = []
            elif self.table.selectionBehavior(
            ) == QAbstractItemView.SelectItems and self.table.selectionMode(
            ) == QAbstractItemView.SingleSelection:
                # Returns the item selected
                for i in self.table.selectedItems():
                    if i.row() >= len(
                            self.data
                    ):  ## Se pulsa un row fuera del data, por ejemplo un total
                        self.selected_items == None
                        self.selected == None
                        break
                    self.selected_items = i
                    self.selected = self.itemData(i)
            debug("{} data selection: {}".format(self.__class__.__name__,
                                                 self.selected))
            self.tableSelectionChanged.emit()
        else:
            debug("ItemSectionChanged without self.setData")

    ## You can obtain data value from an item
    def itemData(self, item):
        return self.data[item.row()][item.column()]

    def on_generic_customContextMenuRequested(self, pos):
        self.qmenu().exec_(self.table.mapToGlobal(pos))

    def setGenericContextMenu(self):
        self.table.customContextMenuRequested.connect(
            self.on_generic_customContextMenuRequested)

    ## Strikes out all qtablewidgetitem in a row
    ## @param row int Row index
    def setRowStrikeOut(self, row):
        for i in range(self.table.horizontalHeader().count()):
            qtwiSetStrikeOut(self.table.item(row, i))

    ## @param selectionBehavior are tags from Qt QAbstractItemView (SelectRows, SelectItems...)
    ## @param selectionMode are tags from Qt QAbstractItemView (SingleSelection, MultiSelection)
    def setSelectionMode(self, selectionBehavior, selectionMode):
        self.table.setSelectionBehavior(selectionBehavior)
        self.table.setSelectionMode(selectionMode)

    def setVerticalHeaderHeight(self, height):
        """height, if null default.
        Must be after settings"""
        if height == None:
            self.table.verticalHeader().setSectionResizeMode(
                QHeaderView.ResizeToContents)
            self._last_height = None
        else:
            self.table.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
            self.table.verticalHeader().setDefaultSectionSize(height)
            self._last_height = height

    def sectionResized(self, logicalIndex, oldSize, newSize):
        self.table.horizontalHeader().setStretchLastSection(False)
        modifiers = QApplication.keyboardModifiers()
        if modifiers == Qt.ShiftModifier:
            for i in range(self.table.columnCount()):
                self.table.setColumnWidth(i, newSize)
            self._settings.setValue(
                "{}/{}_horizontalheader_state".format(self._settingsSection,
                                                      self._settingsObject),
                self.table.horizontalHeader().saveState())
            debug("Saved {}/{}_horizontalheader_state to equal sizes".format(
                self._settingsSection, self._settingsObject))
            self._settings.sync()
        elif modifiers == Qt.ControlModifier:
            self.on_actionSizeMinimum_triggered()
        else:
            self._settings.setValue(
                "{}/{}_horizontalheader_state".format(self._settingsSection,
                                                      self._settingsObject),
                self.table.horizontalHeader().saveState())
            debug("Saved {}/{}_horizontalheader_state manually".format(
                self._settingsSection, self._settingsObject))
            self._settings.sync()

    @pyqtSlot(int)
    def on_table_verticalscrollbar_value_changed(self, value):
        if value % 3 == 1:
            self.on_actionSizeNeeded_triggered()

    def setSettings(self, settings, settingsSection, objectname):
        self._settings = settings  #Made private due it had the same name of the method
        #For all myQTableWidget in settings app
        self.setVerticalHeaderHeight(
            int(self._settings.value("myQTableWidget/rowheight", 24)))
        self._settingsSection = settingsSection
        self._settingsObject = objectname
        self.setObjectName(self._settingsObject)

    def settings(self):
        return self._settings

    def clear(self):
        """Clear table"""
        self.table.setRowCount(0)
        self.table.clearContents()

    ## Resizes columns if column width is less than table hin
    def wheelEvent(self, event):
        self.on_actionSizeNeeded_triggered()
        event.accept()

    @pyqtSlot()
    def keyPressEvent(self, event):
        if event.matches(QKeySequence.ZoomIn) and self._last_height != None:
            height = int(self._settings.value("myQTableWidget/rowheight", 24))
            self._settings.setValue("myQTableWidget/rowheight", height + 1)
            info("Setting myQTableWidget/rowheight set to {}".format(
                self._settings.value("myQTableWidget/rowheight", 24)))
            self.table.setVerticalHeaderHeight(
                int(self._settings.value("myQTableWidget/rowheight", 24)))
        elif event.matches(QKeySequence.ZoomOut) and self._last_height != None:
            height = int(self._settings.value("myQTableWidget/rowheight", 24))
            self._settings.setValue("myQTableWidget/rowheight", height - 1)
            ("Setting myQTableWidget/rowheight set to {}".format(
                self._settings.value("myQTableWidget/rowheight", 24)))
            self.table.setVerticalHeaderHeight(
                int(self._settings.value("myQTableWidget/rowheight", 24)))
        elif event.matches(QKeySequence.Print):
            filename = QFileDialog.getSaveFileName(
                self, self.tr("Save File"), "table.ods",
                self.tr("Libreoffice calc (*.ods)"))[0]
            if filename:
                ods = ODS_Write(filename)
                self.officegeneratorModel("My table").ods_sheet(ods)
                ods.save()

    ## Used to order using clicks in headers
    def on_table_horizontalHeader_sectionClicked(self, index):
        if hasattr(self, "data") == True and self._ordering_enabled == True:
            self.actionListOrderBy[index].triggered.emit()

    ## Used to order table progamatically
    def setOrderBy(self, index, reverse):
        if self._ordering_enabled == True:
            action = self.actionListOrderBy[index]
            if reverse == True:  #Sort is made with action text, so I have to emulate. Text is changed from droawOrder By. It's how I will find in menu
                action.setText(action.text() + " (desc)")
            else:  #No encontrado
                action.setText(action.text().replace(self.tr(" (desc)"), ""))
            action.triggered.emit()

    ## When data is loaded, usually it's from an ordered manager of an ordered sql, to avoid displaying and ordering data twice, you can only draw Order by in widget
    def drawOrderBy(self, index, reverse):
        if self._ordering_enabled == True:
            action = self.actionListOrderBy[index]
            # Sets if its reverse or not and renames action
            if reverse == True:
                action.setText(action.text().replace(self.tr(" (desc)"), ""))
                action.setIcon(QIcon(":/reusingcode/sort_up.png"))
                self.table.horizontalHeaderItem(index).setIcon(
                    QIcon(":reusingcode/sort_down.png"))
            else:  #No encontrado
                action.setText(action.text() + " (desc)")
                action.setIcon(QIcon(":/reusingcode/sort_down.png"))
                self.table.horizontalHeaderItem(index).setIcon(
                    QIcon(":reusingcode/sort_up.png"))

            # Remover others (desc), to the rest of actions
            for i, other_action in enumerate(self.actionListOrderBy):
                if i != index:  # Different to selected action index
                    other_action.setText(other_action.text().replace(
                        self.tr(" (desc)"), ""))

    ## Order data columns. None values are set at the beginning
    def on_orderby_action_triggered(self):
        action = QObject.sender(
            self
        )  #Busca el objeto que ha hecho la signal en el slot en el que está conectado
        self._sort_action_index = self.hh.index(action.text().replace(
            " (desc)",
            ""))  #Search the position in the headers of the action Text
        if action.text().find(self.tr(" (desc)")) > 0:
            self._sort_action_reverse = True
        else:  #No encontrado
            self._sort_action_reverse = False
        output = "Order {}/{} by '{}'".format(
            self._settingsSection, self._settingsObject,
            self.actionListOrderBy[self._sort_action_index].text()
        )  #Must be set before changing direction        # -----------------------------------------------------------------------------
        start = datetime.now()
        nonull = []
        null = []
        for row in self.data:
            if row[self._sort_action_index] is None:
                null.append(row)
            else:
                nonull.append(row)
        try:
            nonull = sorted(nonull,
                            key=lambda c: c[self._sort_action_index],
                            reverse=self._sort_action_reverse)
        except:
            debug(
                "I couldn't order column due to there are different types on it."
            )
        if self._none_at_top == True:  #Set None at top of the list
            if self._sort_action_reverse == False:  # Desc must put None on the other side
                self.data = null + nonull
            else:
                self.data = nonull + null
        else:
            if self._sort_action_reverse == False:
                self.data = nonull + null
            else:
                self.data = null + nonull
        debug("{} took {}".format(output, datetime.now() - start))
        self.update()
        self.drawOrderBy(self._sort_action_index, self._sort_action_reverse)

    def update(self):
        self.setData(self.hh, self.hv, self.data, self.data_decimals,
                     self.data_zonename)

    def applySettings(self):
        """settings must be defined before"""
        self.table.horizontalHeader().setSectionResizeMode(
            QHeaderView.Interactive)
        self.table.horizontalHeader().sectionResized.connect(
            self.sectionResized)
        self.table.horizontalHeader().setStretchLastSection(False)
        state = self._settings.value("{}/{}_horizontalheader_state".format(
            self._settingsSection, self._settingsObject))
        if state:
            self.table.horizontalHeader().restoreState(state)

    ## Adds a horizontal header array , a vertical header array and a data array
    ##
    ## Automatically set alignment
    ## @param decimals int or list with the columns decimals
    def setData(self,
                header_horizontal,
                header_vertical,
                data,
                decimals=2,
                zonename='UTC'):
        ## Affeter selection an action of the OrderByAction list, returns its information, to be used in several classes

        start = datetime.now()
        if decimals.__class__.__name__ == "int":
            decimals = [decimals] * len(header_horizontal)
        self.data_decimals = decimals
        self.data_zonename = zonename

        # Creates order actions here after creating data
        if hasattr(self, "actionListOrderBy"
                   ) == False and self._ordering_enabled == True:
            self.actionListOrderBy = []
            for header in header_horizontal:
                action = QAction("{}".format(header))
                self.actionListOrderBy.append(action)
                action.triggered.connect(self.on_orderby_action_triggered)
                action.setIcon(QIcon(":/reusingcode/sort_up.png"))

        # Headers
        self.hh = header_horizontal
        self.hv = header_vertical
        self.data = data

        self.table.setColumnCount(len(self.hh))
        if self.hh is not None:
            for i in range(len(self.hh)):
                self.table.setHorizontalHeaderItem(
                    i, QTableWidgetItem(self.hh[i]))
        if self.hv is not None:
            self.table.verticalHeader().show()
            self.table.setRowCount(len(self.data))  # To do not lose data
            for i in range(len(self.hv)):
                self.table.setVerticalHeaderItem(i,
                                                 QTableWidgetItem(self.hv[i]))

        # Data
        self.applySettings()
        self.table.clearContents()
        self.table.setRowCount(len(self.data))
        for row in range(len(self.data)):
            for column in range(len(self.hh)):
                wdg = self.object2qtablewidgetitem(self.data[row][column],
                                                   decimals[column], zonename)
                if wdg.__class__.__name__ == "QWidget":  #wdgBool
                    self.table.setCellWidget(row, column, wdg)
                else:  #qtablewidgetitem
                    self.table.setItem(row, column, wdg)
        self.setDataFinished.emit()
        debug("Set data to {}/{} took {}".format(self._settingsSection,
                                                 self._settingsObject,
                                                 datetime.now() - start))

    def print(self, hh, hv, data):
        print(hh)
        for i, row in enumerate(data):
            print(hv[i], row)

        print("Len hh:", len(hh))
        print("Len hv:", len(hv))
        print("Len data:", len(data[0]), "x", len(data))

    ## If true None values are set at the top of the list after sorting. If not at the bottom of the list
    def setNoneAtTop(self, boolean):
        self._none_at_top = boolean

    ## Converts a objecct class to a qtablewidgetitem
    def object2qtablewidgetitem(self, o, decimals=2, zonename="UTC"):
        if o.__class__.__name__ in ["int"]:
            return qright(o)
        elif o.__class__.__name__ in ["datetime"]:
            return qdatetime(o, zonename)
        elif o.__class__.__name__ in ["date"]:
            return qdate(o)
        elif o.__class__.__name__ in ["time"]:
            return qtime(o)
        elif o.__class__.__name__ in ["float", "Decimal"]:
            return qnumber(o, decimals)
        elif o.__class__.__name__ in [
                "Percentage",
        ]:
            return qpercentage(o, decimals)
        elif o.__class__.__name__ in ["Money", "Currency"]:
            return qcurrency(o, decimals)
        elif o.__class__.__name__ in [
                "bool",
        ]:
            return wdgBool(o)
        elif o is None:
            return qnone()
        elif o == "":
            return qempty()
        elif o == "#crossedout":
            return qcrossedout()
        else:
            return qleft(o)

    ## Adds a row in a table, with values
    ## @param row integer with the row to add
    def addRow(self, row, value_list, decimals=2, zonename="UTC"):
        for column, value in enumerate(value_list):
            wdg = self.object2qtablewidgetitem(value, decimals, zonename)
            if wdg.__class__.__name__ == "QWidget":  # For example wdgBool
                self.table.setCellWidget(row, column, wdg)
            else:  #QTablewidgetitem
                self.table.setItem(row, column, wdg)

    ## Returns a list of strings with the horizontal headers
    def listHorizontalHeaders(self):
        if self.hh is None:
            return None
        header = []
        for i in range(self.table.horizontalHeader().count()):
            header.append(self.table.horizontalHeaderItem(i).text())
        return header

    ## Returns a list of strings with the horizontal headers
    def listVerticalHeaders(self):
        if self.hv is None:
            return None
        header = []
        for i in range(self.table.verticalHeader().count()):
            if self.table.verticalHeaderItem(i) is not None:
                header.append(self.table.verticalHeaderItem(i).text())
        return header

    ## Returns a lisf of rows with the text of the
    def listText(self):
        data = []
        for i in range(self.table.rowCount()):
            row = []
            for column in range(self.table.columnCount()):
                data.append(self.table.item(row, column).text())
        return data

    def on_cmdCloseSearch_released(self):
        self.txtSearch.setText("")
        self.showSearchOptions(False)

    def showSearchOptions(self, boolean):
        if boolean == True:
            self.lbl.show()
            self.txtSearch.show()
            self.cmdCloseSearch.show()
        else:
            self.lbl.hide()
            self.txtSearch.hide()
            self.cmdCloseSearch.hide()

    def showSearchCloseButton(self, boolean):
        if boolean == True:
            self.cmdCloseSearch.show()
        else:
            self.cmdCloseSearch.hide()

    def on_actionExport_triggered(self):
        filename = QFileDialog.getSaveFileName(
            self, self.tr("Save File"), "table.ods",
            self.tr("Libreoffice calc (*.ods)"))[0]
        if filename:
            ods = ODS_Write(filename)
            self.officegeneratorModel("My table").ods_sheet(ods)
            ods.save()

    def on_actionSizeMinimum_triggered(self):
        self.table.resizeRowsToContents()
        self.table.resizeColumnsToContents()
        self._settings.setValue(
            "{}/{}_horizontalheader_state".format(self._settingsSection,
                                                  self._settingsObject),
            self.table.horizontalHeader().saveState())
        self._settings.sync()
        debug("Saved {}/{}_horizontalheader_state to minimum".format(
            self._settingsSection, self._settingsObject))

    def on_actionSizeNeeded_triggered(self):
        for i in range(self.table.columnCount()):
            if self.table.sizeHintForColumn(i) > self.table.columnWidth(i):
                self.table.setColumnWidth(i, self.table.sizeHintForColumn(i))
        self._settings.setValue(
            "{}/{}_horizontalheader_state".format(self._settingsSection,
                                                  self._settingsObject),
            self.table.horizontalHeader().saveState())
        self._settings.sync()
        debug("Saved {}/{}_horizontalheader_state to needed".format(
            self._settingsSection, self._settingsObject))

    def on_actionSearch_triggered(self):
        self.lbl.show()
        self.txtSearch.show()
        self.cmdCloseSearch.show()
        self.txtSearch.setFocus()

    ## Returns a qmenu to be used in other qmenus
    def qmenu(self, title="Table options"):
        menu = QMenu(self.parent)
        menu.setTitle(self.tr(title))
        menu.addAction(self.actionExport)
        menu.addSeparator()
        menu.addAction(self.actionSearch)
        menu.addSeparator()
        if hasattr(self, "actionListOrderBy"
                   ) == True and self._ordering_enabled == True:
            order = QMenu(menu)
            order.setTitle(self.tr("Order by"))
            for action in self.actionListOrderBy:
                order.addAction(action)
            menu.addMenu(order)
        size = QMenu(menu)
        size.setTitle(self.tr("Columns size"))
        size.addAction(self.actionSizeMinimum)
        size.addAction(self.actionSizeNeeded)
        menu.addMenu(size)
        return menu

    def on_txt_textChanged(self, text):
        for row in range(self.table.rowCount()):
            found = False
            for column in range(self.table.columnCount()):
                item = self.table.item(row, column)
                if item is not None and item.text().lower().find(
                        text.lower()) >= 0:
                    found = True
                    break
            if found == False:
                self.table.hideRow(row)
            else:
                self.table.showRow(row)

    def officegeneratorModel(self, title="sheet"):
        def pixel2cm(pixels):
            #Converts size in pixels to cm
            PixelWidthDimension = self.logicalDpiX()  # width dots per inch
            inch = pixels / PixelWidthDimension
            cm = inch * 2.54 * (1 + 0.05)
            return cm

        # # # # # # # # # #
        widths = []
        vwidth = pixel2cm(self.table.verticalHeader().width())
        for i in range(self.table.columnCount()):
            widths.append(pixel2cm(self.table.columnWidth(i)))

        from officegenerator.standard_sheets import Model
        m = Model()
        m.setTitle(title)
        m.setHorizontalHeaders(self.listHorizontalHeaders(), widths)
        m.setVerticalHeaders(self.listVerticalHeaders(), vwidth)
        if len(
                self.data
        ) > 0 and self.__class__ == mqtwObjects:  #Need to remove last column (object column)
            data = lor_remove_columns(self.data, [
                len(self.data[0]) - 1,
            ])
        else:
            data = self.data
        m.setData(data)
        return m

    ## Returns the length of self.data. Additional functions doesn't affect this result
    ## If we are using a mqtwObjects, self.data has the same length as self.objects(), so it's fine
    def length(self):
        return len(self.data)

    ## REturns the len of a row using len of hh. If not uses len of self.data[0], if no returns 0
    def lengthRow(self):
        if self.hh is not None:
            return len(self.hh)
        elif self.length() > 0:
            return len(self.data[0])
        else:
            return 0
Пример #17
0
class FileManager(QWidget, _HalWidgetBase):
    def __init__(self, parent=None):
        super(FileManager, self).__init__(parent)
        self.title = 'Qtvcp File System View'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.media_path = (os.path.join(os.path.expanduser('~'),
                                        'linuxcnc/nc_files'))
        user = os.path.split(os.path.expanduser('~'))[-1]
        self.user_path = (os.path.join('/media', user))
        self.currentPath = None
        self.currentFolder = None
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        pasteBox = QHBoxLayout()
        self.textLine = QLineEdit()
        self.textLine.setToolTip('Current Director/selected File')
        self.pasteButton = QToolButton()
        self.pasteButton.setEnabled(False)
        self.pasteButton.setText('Paste')
        self.pasteButton.setToolTip(
            'Copy file from copy path to current directory/file')
        self.pasteButton.clicked.connect(self.paste)
        self.pasteButton.hide()
        pasteBox.addWidget(self.textLine)
        pasteBox.addWidget(self.pasteButton)

        self.copyBox = QFrame()
        hbox = QHBoxLayout()
        hbox.setContentsMargins(0, 0, 0, 0)
        self.copyLine = QLineEdit()
        self.copyLine.setToolTip('File path to copy from, when pasting')
        self.copyButton = QToolButton()
        self.copyButton.setText('Copy')
        self.copyButton.setToolTip('Record current file as copy path')
        self.copyButton.clicked.connect(self.recordCopyPath)
        hbox.addWidget(self.copyButton)
        hbox.addWidget(self.copyLine)
        self.copyBox.setLayout(hbox)
        self.copyBox.hide()

        self.model = QFileSystemModel()
        self.model.setRootPath(QDir.currentPath())
        self.model.setFilter(QDir.AllDirs | QDir.NoDot | QDir.Files)
        self.model.setNameFilterDisables(False)
        self.model.rootPathChanged.connect(self.folderChanged)

        self.list = QListView()
        self.list.setModel(self.model)
        self.updateDirectoryView(self.media_path)
        self.list.resize(640, 480)
        self.list.clicked[QModelIndex].connect(self.listClicked)
        self.list.activated.connect(self._getPathActivated)
        self.list.setAlternatingRowColors(True)

        self.cb = QComboBox()
        self.cb.currentIndexChanged.connect(self.filterChanged)
        self.fillCombobox(INFO.PROGRAM_FILTERS_EXTENSIONS)
        self.cb.setMinimumHeight(30)
        self.cb.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,
                                          QSizePolicy.Fixed))

        self.button2 = QToolButton()
        self.button2.setText('Media')
        self.button2.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button2.setMinimumSize(60, 30)
        self.button2.setToolTip('Jump to Media directory')
        self.button2.clicked.connect(self.onJumpClicked)

        SettingMenu = QMenu(self)
        self.settingMenu = SettingMenu
        for i in ('Media', 'User'):
            axisButton = QAction(QIcon.fromTheme('user-home'), i, self)
            # weird lambda i=i to work around 'function closure'
            axisButton.triggered.connect(
                lambda state, i=i: self.jumpTriggered(i))
            SettingMenu.addAction(axisButton)
        self.button2.setMenu(SettingMenu)

        self.button3 = QToolButton()
        self.button3.setText('Add Jump')
        self.button3.setSizePolicy(
            QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.button3.setMinimumSize(60, 30)
        self.button3.setToolTip('Add current directory to jump button list')
        self.button3.clicked.connect(self.onActionClicked)

        hbox = QHBoxLayout()
        hbox.addWidget(self.button2)
        hbox.addWidget(self.button3)
        hbox.insertStretch(2, stretch=0)
        hbox.addWidget(self.cb)

        windowLayout = QVBoxLayout()
        windowLayout.addLayout(pasteBox)
        windowLayout.addWidget(self.copyBox)
        windowLayout.addWidget(self.list)
        windowLayout.addLayout(hbox)
        self.setLayout(windowLayout)
        self.show()

    def _hal_init(self):
        if self.PREFS_:
            last_path = self.PREFS_.getpref('last_loaded_directory',
                                            self.media_path, str,
                                            'BOOK_KEEPING')
            self.updateDirectoryView(last_path)
            LOG.debug("lAST FILE PATH: {}".format(last_path))
        else:
            LOG.debug("lAST FILE PATH: {}".format(self.media_path))
            self.updateDirectoryView(self.media_path)

    #########################
    # callbacks
    #########################

    # add shown text and hidden filter data from the INI
    def fillCombobox(self, data):
        for i in data:
            self.cb.addItem(i[0], i[1])

    def folderChanged(self, data):
        self.currentFolder = data
        self.textLine.setText(data)

    def updateDirectoryView(self, path):
        self.list.setRootIndex(self.model.setRootPath(path))

    # retrieve selected filter (it's held as QT.userData)
    def filterChanged(self, index):
        userdata = self.cb.itemData(index)
        self.model.setNameFilters(userdata)

    def listClicked(self, index):
        # the signal passes the index of the clicked item
        dir_path = self.model.filePath(index)
        if self.model.fileInfo(index).isFile():
            self.currentPath = dir_path
            self.textLine.setText(self.currentPath)
            return
        root_index = self.model.setRootPath(dir_path)
        self.list.setRootIndex(root_index)

    def onUserClicked(self):
        self.showUserDir()

    def onMediaClicked(self):
        self.showMediaDir()

    def onJumpClicked(self):
        data = self.button2.text()
        if data == 'Media':
            self.showMediaDir()
        elif data == 'User':
            self.showUserDir()
        else:
            self.updateDirectoryView(self.button2.text())

    def jumpTriggered(self, data):
        if data == 'Media':
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip('Jump to Media directory')
            self.showMediaDir()
        elif data == 'User':
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip('Jump to User directory')
            self.showUserDir()
        else:
            self.button2.setText('{}'.format(data))
            self.button2.setToolTip('Jump to directory: {}'.format(data))
            self.updateDirectoryView(self.button2.text())

    def onActionClicked(self):
        i = self.currentFolder
        button = QAction(QIcon.fromTheme('user-home'), i, self)
        # weird lambda i=i to work around 'function closure'
        button.triggered.connect(lambda state, i=i: self.jumpTriggered(i))
        self.settingMenu.addAction(button)

    # get current selection and update the path
    # then if the path is good load it into linuxcnc
    # record it in the preference file if available
    def _getPathActivated(self):
        row = self.list.selectionModel().currentIndex()
        self.listClicked(row)

        fname = self.currentPath
        if fname is None:
            return
        if fname:
            self.load(fname)

    def recordCopyPath(self):
        data, isFile = self.getCurrentSelected()
        if isFile:
            self.copyLine.setText(os.path.normpath(data))
            self.pasteButton.setEnabled(True)
        else:
            self.copyLine.setText('')
            self.pasteButton.setEnabled(False)
            STATUS.emit('error', OPERATOR_ERROR,
                        'Can only copy a file, not a folder')

    def paste(self):
        res = self.copyFile(self.copyLine.text(), self.textLine.text())
        if res:
            self.copyLine.setText('')
            self.pasteButton.setEnabled(False)

    ########################
    # helper functions
    ########################

    def showCopyControls(self, state):
        if state:
            self.copyBox.show()
            self.pasteButton.show()
        else:
            self.copyBox.hide()
            self.pasteButton.hide()

    def showMediaDir(self):
        self.updateDirectoryView(self.user_path)

    def showUserDir(self):
        self.updateDirectoryView(self.media_path)

    def copyFile(self, s, d):
        try:
            shutil.copy(s, d)
            return True
        except Exception as e:
            LOG.error("Copy file error: {}".format(e))
            STATUS.emit('error', OPERATOR_ERROR,
                        "Copy file error: {}".format(e))
            return False

    # moves the selection up
    # used with MPG scrolling
    def up(self):
        self.select_row('up')

    # moves the selection down
    # used with MPG scrolling
    def down(self):
        self.select_row('down')

    def select_row(self, style='down'):
        style = style.lower()
        selectionModel = self.list.selectionModel()
        row = selectionModel.currentIndex().row()
        self.rows = self.model.rowCount(self.list.rootIndex())

        if style == 'last':
            row = self.rows
        elif style == 'up':
            if row > 0:
                row -= 1
            else:
                row = 0
        elif style == 'down':
            if row < self.rows:
                row += 1
            else:
                row = self.rows
        else:
            return
        top = self.model.index(row, 0, self.list.rootIndex())
        selectionModel.setCurrentIndex(
            top, QItemSelectionModel.Select | QItemSelectionModel.Rows)
        selection = QItemSelection(top, top)
        selectionModel.clearSelection()
        selectionModel.select(selection, QItemSelectionModel.Select)

    # returns the current highlighted (selected) path as well as
    # whether it's a file or not.
    def getCurrentSelected(self):
        selectionModel = self.list.selectionModel()
        index = selectionModel.currentIndex()
        dir_path = self.model.filePath(index)
        if self.model.fileInfo(index).isFile():
            return (dir_path, True)
        else:
            return (dir_path, False)

    # This can be class patched to do something else
    def load(self, fname=None):
        if fname is None:
            self._getPathActivated()
            return
        self.recordBookKeeping()
        ACTION.OPEN_PROGRAM(fname)
        STATUS.emit('update-machine-log', 'Loaded: ' + fname, 'TIME')

    # This can be class patched to do something else
    def recordBookKeeping(self):
        fname = self.currentPath
        if fname is None:
            return
        if self.PREFS_:
            self.PREFS_.putpref('last_loaded_directory', self.model.rootPath(),
                                str, 'BOOK_KEEPING')
            self.PREFS_.putpref('RecentPath_0', fname, str, 'BOOK_KEEPING')
Пример #18
0
class StatusPanel(QWidget):
    def __init__(self, gateway):
        super(StatusPanel, self).__init__()
        self.gateway = gateway

        self.num_connected = 0
        self.num_known = 0
        self.available_space = 0

        self.checkmark_icon = QLabel()
        self.checkmark_icon.setPixmap(
            QPixmap(resource('checkmark.png')).scaled(20, 20))

        self.syncing_icon = QLabel()

        self.sync_movie = QMovie(resource('sync.gif'))
        self.sync_movie.setCacheMode(True)
        self.sync_movie.updated.connect(lambda: self.syncing_icon.setPixmap(
            self.sync_movie.currentPixmap().scaled(20, 20)))

        self.status_label = QLabel()
        self.status_label.setStyleSheet("color: dimgrey")

        self.on_sync_state_updated(0)

        self.setStyleSheet('QToolButton { color: dimgrey; border: none; }')
        #self.setStyleSheet("""
        #    QToolButton { color: dimgrey; border: none; }
        #    QToolButton:hover {
        #        background-color: #FAFAFA;
        #        border: 1px solid grey;
        #        border-radius: 2px;
        #    }
        #""")

        self.tor_button = QToolButton()
        self.tor_button.setIconSize(QSize(20, 20))
        self.tor_action = QAction(
            QIcon(resource('tor-onion.png')),
            "This connection is being routed through the Tor network")
        self.tor_button.setDefaultAction(self.tor_action)
        if not self.gateway.use_tor:
            self.tor_button.hide()

        self.globe_button = QToolButton()
        self.globe_button.setIconSize(QSize(20, 20))
        self.globe_action = QAction(QIcon(resource('globe.png')), '')
        self.globe_button.setDefaultAction(self.globe_action)

        layout = QGridLayout(self)
        left, _, right, bottom = layout.getContentsMargins()
        layout.setContentsMargins(left, 0, right, bottom - 2)
        layout.addWidget(self.checkmark_icon, 1, 1)
        layout.addWidget(self.syncing_icon, 1, 1)
        layout.addWidget(self.status_label, 1, 2)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 3)
        layout.addWidget(self.tor_button, 1, 4)
        layout.addWidget(self.globe_button, 1, 5)

        self.gateway.monitor.total_sync_state_updated.connect(
            self.on_sync_state_updated)
        self.gateway.monitor.space_updated.connect(self.on_space_updated)
        self.gateway.monitor.nodes_updated.connect(self.on_nodes_updated)

    def on_sync_state_updated(self, state):
        if state == 0:
            self.status_label.setText("Connecting...")
            self.sync_movie.setPaused(True)
            self.syncing_icon.hide()
            self.checkmark_icon.hide()
        elif state == 1:
            self.status_label.setText("Syncing")
            self.checkmark_icon.hide()
            self.syncing_icon.show()
            self.sync_movie.setPaused(False)
        elif state == 2:
            self.status_label.setText("Up to date")
            self.sync_movie.setPaused(True)
            self.syncing_icon.hide()
            self.checkmark_icon.show()

    def _update_grid_info_tooltip(self):
        if self.available_space:
            self.globe_action.setToolTip(
                "Connected to {} of {} storage nodes\n{} available".format(
                    self.num_connected, self.num_known, self.available_space))
        else:
            self.globe_action.setToolTip(
                "Connected to {} of {} storage nodes".format(
                    self.num_connected, self.num_known))

    def on_space_updated(self, space):
        self.available_space = naturalsize(space)
        self._update_grid_info_tooltip()

    def on_nodes_updated(self, connected, known):
        self.status_label.setText("Connected to {} of {} storage nodes".format(
            connected, known))
        self.num_connected = connected
        self.num_known = known
        self._update_grid_info_tooltip()
Пример #19
0
class HomeRecommendedItem(QWidget, fc_home_recommended_item):
    """
    This class represents a HomeRecommendedItem widget which is shown on the home page. This widget can either show
    a channel or a torrent.
    """

    def __init__(self, parent):
        QWidget.__init__(self, parent)
        fc_home_recommended_item.__init__(self)

        self.setupUi(self)

        self.show_torrent = True
        self.torrent_info = None
        self.channel_info = None
        self.download_uri = None
        self.dialog = None

        # Create the category label, shown on cells that display a torrent on the home page
        self.category_label = QLabel(self)
        self.category_label.setFixedHeight(24)
        self.category_label.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed))
        self.category_label.setStyleSheet("""
        border: 2px solid white;
        border-radius: 12px;
        background-color: transparent;
        color: white;
        padding-left: 4px;
        padding-right: 4px;
        font-weight: bold;
        """)
        self.category_label.move(QPoint(6, 6))
        self.category_label.show()

        # Create the dark overlay and download button over the thumbnail on hover
        self.dark_overlay = QWidget(self)
        self.dark_overlay.setStyleSheet("background-color: rgba(0, 0, 0, 0.65);")
        self.dark_overlay.hide()

        self.download_button = QToolButton(self)
        self.download_button.setFixedSize(QSize(40, 40))
        self.download_button.setStyleSheet("""
        QToolButton {
            background-color: transparent;
            border: 2px solid white;
            border-radius: 20px;
        }

        QToolButton::hover {
            border: 2px solid #B5B5B5;
        }
        """)
        self.download_button.setIcon(QIcon(get_image_path('downloads.png')))
        self.download_button.setIconSize(QSize(18, 18))
        self.download_button.clicked.connect(self.on_download_button_clicked)
        self.download_button.hide()

    def on_download_button_clicked(self):
        gui_settings = self.window().gui_settings
        self.download_uri = quote_plus((u"magnet:?xt=urn:btih:%s&dn=%s" %
                                        (self.torrent_info["infohash"], self.torrent_info['name'])).encode('utf-8'))

        if get_gui_setting(gui_settings, "ask_download_settings", True, is_bool=True):
            self.dialog = StartDownloadDialog(self.window().stackedWidget, self.download_uri, self.torrent_info["name"])
            self.dialog.button_clicked.connect(self.on_start_download_action)
            self.dialog.show()
        else:
            self.window().perform_start_download_request(self.download_uri,
                                                         get_gui_setting(gui_settings, "default_anonymity_enabled",
                                                                         True, is_bool=True),
                                                         get_gui_setting(gui_settings, "default_safeseeding_enabled",
                                                                         True, is_bool=True),
                                                         self.window().tribler_settings['downloadconfig']['saveas'],
                                                         [], 0)

    def on_start_download_action(self, action):
        if action == 1:
            self.window().perform_start_download_request(self.download_uri,
                                                         self.dialog.dialog_widget.anon_download_checkbox.isChecked(),
                                                         self.dialog.dialog_widget.safe_seed_checkbox.isChecked(),
                                                         self.dialog.dialog_widget.destination_input.text(),
                                                         self.dialog.get_selected_files(),
                                                         self.dialog.dialog_widget.files_list_view.topLevelItemCount())

        self.dialog.request_mgr.cancel_request()
        self.dialog.setParent(None)
        self.dialog = None

    def update_with_torrent(self, torrent):
        self.show_torrent = True
        self.torrent_info = torrent
        self.thumbnail_widget.initialize(torrent["name"], HOME_ITEM_FONT_SIZE)
        self.main_label.setText(torrent["name"])
        self.category_label.setText(torrent["category"])
        self.category_label.adjustSize()
        self.category_label.setHidden(False)
        self.setCursor(Qt.ArrowCursor)
        self.detail_label.setText("Size: " + format_size(torrent["size"]))

    def update_with_channel(self, channel):
        self.show_torrent = False
        self.channel_info = channel
        self.thumbnail_widget.initialize(channel["name"], HOME_ITEM_FONT_SIZE)

        self.main_label.setText(channel["name"])
        self.detail_label.setText("Updated " + pretty_date(channel["modified"]))
        self.category_label.setHidden(True)
        self.setCursor(Qt.PointingHandCursor)

    def enterEvent(self, _):
        if self.show_torrent:
            self.dark_overlay.resize(self.thumbnail_widget.size())
            self.dark_overlay.show()
            self.download_button.move((self.thumbnail_widget.width() - self.download_button.width()) / 2,
                                      (self.thumbnail_widget.height() - self.download_button.height()) / 2)
            self.download_button.show()

    def leaveEvent(self, _):
        self.dark_overlay.hide()
        self.download_button.hide()
Пример #20
0
class MacroTab(QVBoxLayout):

    changed = pyqtSignal()
    record = pyqtSignal(object, bool)
    record_stop = pyqtSignal()

    def __init__(self, parent, enable_recorder):
        super().__init__()

        self.parent = parent

        self.lines = []

        self.container = QGridLayout()

        menu_record = QMenu()
        menu_record.addAction(tr("MacroRecorder", "Append to current"))\
            .triggered.connect(lambda: self.record.emit(self, True))
        menu_record.addAction(tr("MacroRecorder", "Replace everything"))\
            .triggered.connect(lambda: self.record.emit(self, False))

        self.btn_record = QPushButton(tr("MacroRecorder", "Record macro"))
        self.btn_record.setMenu(menu_record)
        if not enable_recorder:
            self.btn_record.hide()

        self.btn_record_stop = QPushButton(tr("MacroRecorder", "Stop recording"))
        self.btn_record_stop.clicked.connect(lambda: self.record_stop.emit())
        self.btn_record_stop.hide()

        self.btn_add = QToolButton()
        self.btn_add.setText(tr("MacroRecorder", "Add action"))
        self.btn_add.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_add.clicked.connect(self.on_add)

        self.btn_tap_enter = QToolButton()
        self.btn_tap_enter.setText(tr("MacroRecorder", "Tap Enter"))
        self.btn_tap_enter.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.btn_tap_enter.clicked.connect(self.on_tap_enter)

        layout_buttons = QHBoxLayout()
        layout_buttons.addStretch()
        layout_buttons.addWidget(self.btn_add)
        layout_buttons.addWidget(self.btn_tap_enter)
        layout_buttons.addWidget(self.btn_record)
        layout_buttons.addWidget(self.btn_record_stop)

        vbox = QVBoxLayout()
        vbox.addLayout(self.container)
        vbox.addStretch()

        w = QWidget()
        w.setLayout(vbox)
        w.setObjectName("w")
        scroll = QScrollArea()
        scroll.setFrameShape(QFrame.NoFrame)
        scroll.setStyleSheet("QScrollArea { background-color:transparent; }")
        w.setStyleSheet("#w { background-color:transparent; }")
        scroll.setWidgetResizable(True)
        scroll.setWidget(w)

        self.addWidget(scroll)
        self.addLayout(layout_buttons)

    def add_action(self, act):
        line = MacroLine(self, act)
        line.changed.connect(self.on_change)
        self.lines.append(line)
        line.insert(len(self.lines) - 1)
        self.changed.emit()

    def on_add(self):
        self.add_action(ActionTextUI(self.container))

    def on_remove(self, obj):
        for line in self.lines:
            if line == obj:
                line.remove()
                line.delete()
        self.lines.remove(obj)
        for line in self.lines:
            line.remove()
        for x, line in enumerate(self.lines):
            line.insert(x)
        self.changed.emit()

    def clear(self):
        for line in self.lines[:]:
            self.on_remove(line)

    def on_move(self, obj, offset):
        if offset == 0:
            return
        index = self.lines.index(obj)
        if index + offset < 0 or index + offset >= len(self.lines):
            return
        other = self.lines.index(self.lines[index + offset])
        self.lines[index].remove()
        self.lines[other].remove()
        self.lines[index], self.lines[other] = self.lines[other], self.lines[index]
        self.lines[index].insert(index)
        self.lines[other].insert(other)
        self.changed.emit()

    def on_change(self):
        self.changed.emit()

    def on_tap_enter(self):
        self.add_action(ActionTapUI(self.container, ActionTap([Keycode.find_by_qmk_id("KC_ENTER")])))

    def pre_record(self):
        self.btn_record.hide()
        self.btn_add.hide()
        self.btn_tap_enter.hide()
        self.btn_record_stop.show()

    def post_record(self):
        self.btn_record.show()
        self.btn_add.show()
        self.btn_tap_enter.show()
        self.btn_record_stop.hide()

    def actions(self):
        return [line.action.act for line in self.lines]
Пример #21
0
    def __init__(self, gateway, gui):
        super(StatusPanel, self).__init__()
        self.gateway = gateway
        self.gui = gui

        self.num_connected = 0
        self.num_known = 0
        self.available_space = 0

        self.checkmark_icon = QLabel()
        self.checkmark_icon.setPixmap(
            QPixmap(resource('checkmark.png')).scaled(20, 20))

        self.syncing_icon = QLabel()

        self.sync_movie = QMovie(resource('sync.gif'))
        self.sync_movie.setCacheMode(True)
        self.sync_movie.updated.connect(lambda: self.syncing_icon.setPixmap(
            self.sync_movie.currentPixmap().scaled(20, 20)))

        self.status_label = QLabel()
        self.status_label.setStyleSheet("color: dimgrey")

        self.on_sync_state_updated(0)

        self.setStyleSheet('QToolButton { color: dimgrey; border: none; }')
        #self.setStyleSheet("""
        #    QToolButton { color: dimgrey; border: none; }
        #    QToolButton:hover {
        #        background-color: #FAFAFA;
        #        border: 1px solid grey;
        #        border-radius: 2px;
        #    }
        #""")

        self.tor_button = QToolButton()
        self.tor_button.setIconSize(QSize(20, 20))
        self.tor_action = QAction(
            QIcon(resource('tor-onion.png')),
            "This connection is being routed through the Tor network")
        self.tor_button.setDefaultAction(self.tor_action)
        if not self.gateway.use_tor:
            self.tor_button.hide()

        self.globe_button = QToolButton()
        self.globe_button.setIconSize(QSize(20, 20))
        self.globe_action = QAction(QIcon(resource('globe.png')), '')
        self.globe_button.setDefaultAction(self.globe_action)

        preferences_button = QToolButton(self)
        preferences_button.setIcon(QIcon(resource('preferences.png')))
        preferences_button.setIconSize(QSize(20, 20))
        preferences_button.setMenu(Menu(self.gui, show_open_action=False))
        preferences_button.setPopupMode(2)
        preferences_button.setStyleSheet(
            'QToolButton::menu-indicator { image: none }')

        if QSystemTrayIcon.isSystemTrayAvailable():
            preferences_button.hide()

        layout = QGridLayout(self)
        left, _, right, bottom = layout.getContentsMargins()
        layout.setContentsMargins(left, 0, right, bottom - 2)
        layout.addWidget(self.checkmark_icon, 1, 1)
        layout.addWidget(self.syncing_icon, 1, 1)
        layout.addWidget(self.status_label, 1, 2)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 3)
        layout.addWidget(self.tor_button, 1, 4)
        layout.addWidget(self.globe_button, 1, 5)
        layout.addWidget(preferences_button, 1, 6)

        self.gateway.monitor.total_sync_state_updated.connect(
            self.on_sync_state_updated)
        self.gateway.monitor.space_updated.connect(self.on_space_updated)
        self.gateway.monitor.nodes_updated.connect(self.on_nodes_updated)
Пример #22
0
class PlayerUi(QDialog):
    def __init__(self, parent=None):
        super(PlayerUi, self).__init__(parent)
        self.create_actions()
        self.setup_ui()
        self.managePage.ui_initial()
        self.load_style_sheet(Configures.QssFileDefault, Configures.IconsDir)

    def load_style_sheet(self, sheetName, iconsDir):
        """load qss file"""
        print('Using qss file: %s' % sheetName)
        qss = QFile(sheetName)
        qss.open(QFile.ReadOnly)
        styleSheet = str(qss.readAll(),
                         encoding='utf8').replace(':PathPrefix', iconsDir)
        QApplication.instance().setStyleSheet(styleSheet)
        qss.close()

    def create_connections(self):
        self.searchBox.search_musics_signal.connect(self.search_musics_online)
        self.searchBox.searchtype_changed_signal.connect(
            self.managePage.searchFrame.searchtype_changed)
        self.aboutButton.clicked.connect(self.show_about_page)
        self.preferenceButton.clicked.connect(self.show_settings_frame)
        self.minButton.clicked.connect(self.show_minimized)
        self.closeButton.clicked.connect(self.close_button_acted)
        self.playbackPanel.show_artist_info_signal.connect(
            self.show_artist_info)
        self.playbackPanel.dont_hide_main_window_signal.connect(
            self.dont_hide_mainwindow)
        self.managePage.playlistWidget.show_artist_info_signal.connect(
            self.show_artist_info)
        self.managePage.playlistWidget.show_song_info_signal.connect(
            self.show_song_info)
        self.managePage.playlistWidget.musics_added_signal.connect(
            self.hide_song_info_page)
        self.managePage.playlistWidget.musics_removed_signal.connect(
            self.hide_song_info_page)
        self.managePage.playlistWidget.musics_cleared_signal.connect(
            self.hide_song_info_page)
        self.managePage.playlist_removed_signal.connect(
            self.hide_song_info_page)
        self.managePage.playlist_renamed_signal.connect(
            self.hide_song_info_page)
        self.managePage.playlistWidget.playlist_changed_signal.connect(
            self.hide_song_info_page)

    def setup_ui(self):
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setWindowIcon(QIcon(IconsHub.Xyplayer))
        self.setFocusPolicy(Qt.NoFocus)
        self.setObjectName(app_name)
        self.setWindowFlags(Qt.MSWindowsFixedSizeDialogHint
                            | Qt.FramelessWindowHint)
        self.setMaximumSize(
            QSize(Configures.WindowWidth, Configures.WindowHeight))
        self.setGeometry(
            (Configures.DesktopSize.width() - Configures.WindowWidth) // 2,
            (Configures.DesktopSize.height() - Configures.WindowHeight) // 2,
            Configures.WindowWidth, Configures.WindowHeight)
        self.setAttribute(Qt.WA_QuitOnClose, True)
        self.dragPosition = QPoint(0, 0)
        self.mousePressedFlag = False

        #title_widgets
        self.titleIconLabel = QLabel()
        pixmap = QPixmap(IconsHub.Xyplayer)
        self.titleIconLabel.setFixedSize(18, 18)
        self.titleIconLabel.setScaledContents(True)
        self.titleIconLabel.setPixmap(pixmap)
        self.titleLabel = QLabel("XYPLAYER")
        self.titleLabel.setObjectName('titleLabel')
        self.titleLabel.setFixedHeight(30)
        self.titleLabel.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        self.titleLabel.setObjectName('titleLabel')
        self.minButton = PushButton()
        self.minButton.setToolTip(self.tr('最小化'))
        self.minButton.setFocusPolicy(Qt.NoFocus)
        self.closeButton = PushButton()
        self.closeButton.setToolTip(self.tr('关闭主面板'))
        self.closeButton.setFocusPolicy(Qt.NoFocus)
        self.aboutButton = PushButton()
        self.aboutButton.setToolTip(self.tr('关于'))
        self.aboutButton.setFocusPolicy(Qt.NoFocus)
        self.preferenceButton = PushButton()
        self.preferenceButton.setToolTip(self.tr('选项'))
        self.preferenceButton.setFocusPolicy(Qt.NoFocus)
        self.minButton.loadPixmap(IconsHub.MinButton)
        self.closeButton.loadPixmap(IconsHub.CloseButton)
        self.aboutButton.loadPixmap(IconsHub.AboutButton)
        self.preferenceButton.loadPixmap(IconsHub.PreferenceButton)

        #管理页面
        self.managePage = manage_page.ManagePage()

        #播放器
        self.playbackPanel = playback_panel.PlaybackPanel()

        self.mainPageButton = QToolButton(self, clicked=self.show_lyric_text)
        self.mainPageButton.setToolTip('返回歌词页面')
        self.mainPageButton.hide()
        self.mainPageButton.setGeometry(625, 5, 30, 30)
        self.mainPageButton.setObjectName('homeButton')
        self.mainPageButton.setFocusPolicy(Qt.NoFocus)
        self.mainPageButton.setIcon(QIcon(IconsHub.Home))
        self.mainPageButton.setIconSize(QSize(20, 20))
        self.pageLabel = QLabel(self)
        self.pageLabel.setObjectName('pageLabel')
        self.pageLabel.hide()
        self.pageLabel.setGeometry(660, 5, 100, 30)
        self.searchBox = search_page.SearchBox(self)
        self.searchBox.setGeometry(180, 6, 280, 28)

        #综合布局
        titleLayout = QHBoxLayout()
        titleLayout.setContentsMargins(3, 0, 0, 0)
        titleLayout.setSpacing(0)
        titleLayout.addWidget(self.titleIconLabel)
        titleLayout.addSpacing(2)
        titleLayout.addWidget(self.titleLabel)
        titleLayout.addStretch()
        titleLayout.addWidget(self.aboutButton)
        titleLayout.addWidget(self.preferenceButton)
        titleLayout.addWidget(self.minButton)
        titleLayout.addWidget(self.closeButton)

        #主堆栈框
        self.mainStack = QStackedWidget()

        mainLayout = QVBoxLayout(self)
        mainLayout.setSpacing(2)
        mainLayout.setContentsMargins(3, 0, 3, 0)
        mainLayout.addLayout(titleLayout)
        mainLayout.addWidget(self.managePage)
        mainLayout.addWidget(self.playbackPanel)

        #创建托盘图标
        self.trayIcon = QSystemTrayIcon(self)
        self.trayIcon.setIcon(QIcon(IconsHub.Xyplayer))
        self.showDesktopLyricAction = QAction(
            QIcon(IconsHub.DesktopLyric),
            "开启桌面歌词",
            self,
            triggered=self.playbackPanel.show_desktop_lyric)
        trayMenu = QMenu()
        trayMenu.addAction(self.showMainWindowAction)
        trayMenu.addAction(self.showDesktopLyricAction)
        trayMenu.addSeparator()
        trayMenu.addAction(self.playbackPanel.get_previous_button_action())
        trayMenu.addAction(self.playbackPanel.get_play_button_action())
        trayMenu.addAction(self.playbackPanel.get_next_button_action())
        trayMenu.addAction(self.playbackPanel.get_stop_button_action())
        trayMenu.addSeparator()
        trayMenu.addAction(self.playmodeRandomAction)
        trayMenu.addAction(self.playmodeOrderAction)
        trayMenu.addAction(self.playmodeSingleAction)
        trayMenu.addSeparator()
        trayMenu.addAction(self.exitNowAction)
        self.trayIcon.setContextMenu(trayMenu)
        self.trayIcon.show()

    def create_actions(self):
        self.showMainWindowAction = QAction(QIcon(IconsHub.Home),
                                            "隐藏主界面",
                                            self,
                                            triggered=self.show_mainwindow)

        self.playmodeOrderAction = QAction(QIcon(IconsHub.PlaymodeSelectedNo),
                                           Configures.PlaymodeOrderText,
                                           self,
                                           triggered=self.playmode_order_seted)

        self.playmodeRandomAction = QAction(
            QIcon(IconsHub.PlaymodeSelected),
            Configures.PlaymodeRandomText,
            self,
            triggered=self.playmode_random_seted)

        self.playmodeSingleAction = QAction(
            QIcon(IconsHub.PlaymodeSelectedNo),
            Configures.PlaymodeSingleText,
            self,
            triggered=self.playmode_single_seted)

        self.exitNowAction = QAction(QIcon(IconsHub.Close),
                                     "立即退出",
                                     self,
                                     triggered=self.close)

        self.playmodeActions = [
            self.playmodeRandomAction, self.playmodeOrderAction,
            self.playmodeSingleAction
        ]

    def mousePressEvent(self, event):
        self.mousePressedFlag = True
        self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()
        event.accept()

    def mouseReleaseEvent(self, event):
        self.mousePressedFlag = False

    def mouseMoveEvent(self, event):
        if self.mousePressedFlag:
            self.move(event.globalPos() - self.dragPosition)
            event.accept()

    def force_close(self):
        """用于程序成功更新之后跳过确认窗口强制关闭。"""
        self.forceCloseFlag = True
        self.close()

    def check_if_can_close(self):
        closeChecked = False
        if self.managePage.exitmodePanel.mountoutDialog.countoutMode and not self.managePage.exitmodePanel.mountoutDialog.remainMount or self.managePage.exitmodePanel.timeoutDialog.timeoutFlag or self.forceCloseFlag:
            closeChecked = True
        else:
            if threading.active_count() == 1:
                closeChecked = True
            else:
                self.show()
                ok = QMessageBox.question(self, '退出',
                                          '当前有下载任务正在进行,您是否要挂起全部下载任务并退出?',
                                          QMessageBox.Cancel | QMessageBox.Ok,
                                          QMessageBox.Cancel)
                if ok == QMessageBox.Ok:
                    closeChecked = True
                else:
                    closeChecked = False
        return closeChecked

    def closeEvent(self, event):
        if self.check_if_can_close():
            self.handle_before_close()
            event.accept()
        else:
            event.ignore()

    def handle_before_close(self):
        self.playbackPanel.stop_music()
        self.hide()
        self.trayIcon.hide()
        self.managePage.handle_before_app_exit()
        for t in threading.enumerate():
            if t.name == 'downloadLrc':
                t.stop()
            elif t != threading.main_thread():
                t.pause()
                t.join()

    def playmode_changed(self, oldPlaymode, newPlaymode):
        self.playmodeActions[oldPlaymode].setIcon(
            QIcon(IconsHub.PlaymodeSelectedNo))
        self.playmodeActions[newPlaymode].setIcon(
            QIcon(IconsHub.PlaymodeSelected))

    def playmode_order_seted(self):
        if self.playbackPanel.playmode != Configures.PlaymodeOrder:
            self.playmode_changed(self.playbackPanel.playmode,
                                  Configures.PlaymodeOrder)
            self.playbackPanel.set_new_playmode(Configures.PlaymodeOrder)

    def playmode_random_seted(self):
        if self.playbackPanel.playmode != Configures.PlaymodeRandom:
            self.playmode_changed(self.playbackPanel.playmode,
                                  Configures.PlaymodeRandom)
            self.playbackPanel.set_new_playmode(Configures.PlaymodeRandom)

    def playmode_single_seted(self):
        if self.playbackPanel.playmode != Configures.PlaymodeSingle:
            self.playmode_changed(self.playbackPanel.playmode,
                                  Configures.PlaymodeSingle)
            self.playbackPanel.set_new_playmode(Configures.PlaymodeSingle)

    def show_minimized(self):
        self.showMinimized()

    def show_mainwindow(self):
        if self.isHidden():
            self.showMainWindowAction.setText('隐藏主界面')
            self.show()
        else:
            self.showMainWindowAction.setText('显示主界面')
            self.hide()

    def dont_hide_mainwindow(self):
        if self.isHidden():
            self.showMainWindowAction.setText('隐藏主界面')
            self.show()

    def ui_initial(self):
        self.playbackPanel.ui_initial()
        self.managePage.ui_initial()

    def show_lyric_text(self):
        self.pageLabel.hide()
        self.mainPageButton.hide()
        self.managePage.show_main_stack_window()

    def show_about_page(self):
        self.show_page_label_and_button(self.tr('关于'))
        self.managePage.show_about_page()

    def show_settings_frame(self):
        self.show_page_label_and_button(self.tr('选项'))
        self.managePage.show_settings_frame()

    def search_musics_online(self, keyword):
        if self.managePage.searchFrame.search_musics(keyword):
            self.show_page_label_and_button(self.tr('搜索'))
            self.managePage.show_search_frame()

    def show_artist_info(self, name):
        self.show_page_label_and_button(self.tr('歌手'))
        self.managePage.show_artist_info(name)

    def show_song_info(self, row):
        self.show_page_label_and_button(self.tr('歌曲'))
        self.managePage.show_song_info(row)

    def hide_song_info_page(self, arg1=None, arg2=None):
        if self.managePage.get_page_description() == '歌曲':
            self.show_lyric_text()

    def show_page_label_and_button(self, pageName):
        self.pageLabel.setText(self.tr(pageName))
        self.mainPageButton.show()
        self.pageLabel.show()

    def close_button_acted(self):
        if self.closeButtonAct == Configures.SettingsHide:
            self.show_mainwindow()
        else:
            self.close()
Пример #23
0
class PlayerUi(QDialog):
    def __init__(self, parent = None):
        super(PlayerUi, self).__init__(parent)
        self.create_actions()
        self.setup_ui()
        self.managePage.ui_initial()
        self.load_style_sheet(Configures.QssFileDefault, Configures.IconsDir)
    
    def load_style_sheet(self, sheetName, iconsDir):
        """load qss file"""
        print('Using qss file: %s'%sheetName)
        qss = QFile(sheetName)
        qss.open(QFile.ReadOnly)
        styleSheet = str(qss.readAll(), encoding='utf8').replace(':PathPrefix', iconsDir)
        QApplication.instance().setStyleSheet(styleSheet)
        qss.close()
    
    def create_connections(self):
        self.searchBox.search_musics_signal.connect(self.search_musics_online)
        self.searchBox.searchtype_changed_signal.connect(self.managePage.searchFrame.searchtype_changed)
        self.aboutButton.clicked.connect(self.show_about_page)
        self.preferenceButton.clicked.connect(self.show_settings_frame)
        self.minButton.clicked.connect(self.show_minimized)
        self.closeButton.clicked.connect(self.close_button_acted)
        self.playbackPanel.show_artist_info_signal.connect(self.show_artist_info)
        self.playbackPanel.dont_hide_main_window_signal.connect(self.dont_hide_mainwindow)
        self.managePage.playlistWidget.show_artist_info_signal.connect(self.show_artist_info)
        self.managePage.playlistWidget.show_song_info_signal.connect(self.show_song_info)
        self.managePage.playlistWidget.musics_added_signal.connect(self.hide_song_info_page)
        self.managePage.playlistWidget.musics_removed_signal.connect(self.hide_song_info_page)
        self.managePage.playlistWidget.musics_cleared_signal.connect(self.hide_song_info_page)
        self.managePage.playlist_removed_signal.connect(self.hide_song_info_page)
        self.managePage.playlist_renamed_signal.connect(self.hide_song_info_page)
        self.managePage.playlistWidget.playlist_changed_signal.connect(self.hide_song_info_page)

    def setup_ui(self):        
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setWindowIcon(QIcon(IconsHub.Xyplayer))
        self.setFocusPolicy(Qt.NoFocus)
        self.setObjectName(app_name)
        self.setWindowFlags(Qt.MSWindowsFixedSizeDialogHint | Qt.FramelessWindowHint)
        self.setMaximumSize(QSize(Configures.WindowWidth, Configures.WindowHeight))
        self.setGeometry((Configures.DesktopSize.width() - Configures.WindowWidth)//2, (Configures.DesktopSize.height() - Configures.WindowHeight)//2, Configures.WindowWidth, Configures.WindowHeight)
        self.setAttribute(Qt.WA_QuitOnClose,True)
        self.dragPosition = QPoint(0, 0)
        self.mousePressedFlag = False

#title_widgets
        self.titleIconLabel = QLabel()
        pixmap = QPixmap(IconsHub.Xyplayer)
        self.titleIconLabel.setFixedSize(18, 18)
        self.titleIconLabel.setScaledContents(True)
        self.titleIconLabel.setPixmap(pixmap)
        self.titleLabel = QLabel("XYPLAYER")
        self.titleLabel.setObjectName('titleLabel')
        self.titleLabel.setFixedHeight(30)
        self.titleLabel.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        self.titleLabel.setObjectName('titleLabel')
        self.minButton = PushButton()
        self.minButton.setToolTip(self.tr('最小化'))
        self.minButton.setFocusPolicy(Qt.NoFocus)
        self.closeButton = PushButton()
        self.closeButton.setToolTip(self.tr('关闭主面板'))
        self.closeButton.setFocusPolicy(Qt.NoFocus)
        self.aboutButton = PushButton()
        self.aboutButton.setToolTip(self.tr('关于'))
        self.aboutButton.setFocusPolicy(Qt.NoFocus)
        self.preferenceButton = PushButton()
        self.preferenceButton.setToolTip(self.tr('选项'))
        self.preferenceButton.setFocusPolicy(Qt.NoFocus)
        self.minButton.loadPixmap(IconsHub.MinButton)
        self.closeButton.loadPixmap(IconsHub.CloseButton)
        self.aboutButton.loadPixmap(IconsHub.AboutButton)
        self.preferenceButton.loadPixmap(IconsHub.PreferenceButton)
        
#管理页面
        self.managePage = manage_page.ManagePage()

#播放器
        self.playbackPanel = playback_panel.PlaybackPanel()

        self.mainPageButton = QToolButton(self, clicked = self.show_lyric_text)
        self.mainPageButton.setToolTip('返回歌词页面')
        self.mainPageButton.hide()
        self.mainPageButton.setGeometry(625, 5, 30, 30)
        self.mainPageButton.setObjectName('homeButton')
        self.mainPageButton.setFocusPolicy(Qt.NoFocus)
        self.mainPageButton.setIcon(QIcon(IconsHub.Home))
        self.mainPageButton.setIconSize(QSize(20, 20))
        self.pageLabel = QLabel(self)
        self.pageLabel.setObjectName('pageLabel')
        self.pageLabel.hide()
        self.pageLabel.setGeometry(660, 5, 100, 30)
        self.searchBox = search_page.SearchBox(self)
        self.searchBox.setGeometry(180, 6, 280, 28)

#综合布局 
        titleLayout = QHBoxLayout()
        titleLayout.setContentsMargins(3, 0, 0, 0)
        titleLayout.setSpacing(0)
        titleLayout.addWidget(self.titleIconLabel)
        titleLayout.addSpacing(2)
        titleLayout.addWidget(self.titleLabel)
        titleLayout.addStretch()
        titleLayout.addWidget(self.aboutButton)
        titleLayout.addWidget(self.preferenceButton)
        titleLayout.addWidget(self.minButton)
        titleLayout.addWidget(self.closeButton)

#主堆栈框
        self.mainStack = QStackedWidget()
        
        mainLayout = QVBoxLayout(self)
        mainLayout.setSpacing(2)
        mainLayout.setContentsMargins(3, 0, 3, 0)
        mainLayout.addLayout(titleLayout)
        mainLayout.addWidget(self.managePage)
        mainLayout.addWidget(self.playbackPanel)

#创建托盘图标
        self.trayIcon = QSystemTrayIcon(self)
        self.trayIcon.setIcon(QIcon(IconsHub.Xyplayer))
        self.showDesktopLyricAction = QAction(
             QIcon(IconsHub.DesktopLyric), "开启桌面歌词", 
                self,  triggered = self.playbackPanel.show_desktop_lyric )
        trayMenu = QMenu()
        trayMenu.addAction(self.showMainWindowAction)
        trayMenu.addAction(self.showDesktopLyricAction)
        trayMenu.addSeparator()
        trayMenu.addAction(self.playbackPanel.get_previous_button_action())
        trayMenu.addAction(self.playbackPanel.get_play_button_action())
        trayMenu.addAction(self.playbackPanel.get_next_button_action())
        trayMenu.addAction(self.playbackPanel.get_stop_button_action())
        trayMenu.addSeparator()
        trayMenu.addAction(self.playmodeRandomAction)
        trayMenu.addAction(self.playmodeOrderAction)
        trayMenu.addAction(self.playmodeSingleAction)
        trayMenu.addSeparator()
        trayMenu.addAction(self.exitNowAction)
        self.trayIcon.setContextMenu(trayMenu)
        self.trayIcon.show()

    def create_actions(self):
        self.showMainWindowAction = QAction(
             QIcon(IconsHub.Home), "隐藏主界面", 
                self,  triggered = self.show_mainwindow )
        
        self.playmodeOrderAction = QAction(
            QIcon(IconsHub.PlaymodeSelectedNo),  Configures.PlaymodeOrderText, 
                self, triggered = self.playmode_order_seted)
                
        self.playmodeRandomAction = QAction(
            QIcon(IconsHub.PlaymodeSelected),  Configures.PlaymodeRandomText, 
                self, triggered = self.playmode_random_seted)
        
        self.playmodeSingleAction = QAction(
            QIcon(IconsHub.PlaymodeSelectedNo),  Configures.PlaymodeSingleText, 
                self, triggered = self.playmode_single_seted)
        
        self.exitNowAction = QAction(
            QIcon(IconsHub.Close),  "立即退出", 
                self, triggered = self.close)
                
        self.playmodeActions = [self.playmodeRandomAction, self.playmodeOrderAction, self.playmodeSingleAction]
    
    def mousePressEvent(self, event):
        self.mousePressedFlag = True
        self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()
        event.accept()
 
    def mouseReleaseEvent(self, event):
        self.mousePressedFlag = False
    
    def mouseMoveEvent(self, event):
        if self.mousePressedFlag:
            self.move(event.globalPos() - self.dragPosition)
            event.accept()
    
    def force_close(self):
        """用于程序成功更新之后跳过确认窗口强制关闭。"""
        self.forceCloseFlag = True
        self.close()

    def check_if_can_close(self):
        closeChecked = False
        if self.managePage.exitmodePanel.mountoutDialog.countoutMode and not self.managePage.exitmodePanel.mountoutDialog.remainMount or self.managePage.exitmodePanel.timeoutDialog.timeoutFlag or self.forceCloseFlag:
            closeChecked = True
        else:
            if threading.active_count() == 1:
                closeChecked = True
            else:
                self.show()
                ok = QMessageBox.question(self, '退出', '当前有下载任务正在进行,您是否要挂起全部下载任务并退出?',QMessageBox.Cancel|QMessageBox.Ok, QMessageBox.Cancel )
                if ok == QMessageBox.Ok:
                    closeChecked = True
                else:
                    closeChecked = False
        return closeChecked

    def closeEvent(self, event):
        if self.check_if_can_close():
            self.handle_before_close()
            event.accept()  
        else:
            event.ignore()

    def handle_before_close(self):
        self.playbackPanel.stop_music()
        self.hide()
        self.trayIcon.hide()
        self.managePage.handle_before_app_exit()
        for t in threading.enumerate():
            if t.name == 'downloadLrc':
                t.stop()
            elif t!= threading.main_thread():
                t.pause()
                t.join()

    def playmode_changed(self, oldPlaymode, newPlaymode):
        self.playmodeActions[oldPlaymode].setIcon(QIcon(IconsHub.PlaymodeSelectedNo))
        self.playmodeActions[newPlaymode].setIcon(QIcon(IconsHub.PlaymodeSelected))
    
    def playmode_order_seted(self):
        if self.playbackPanel.playmode != Configures.PlaymodeOrder:
            self.playmode_changed(self.playbackPanel.playmode, Configures.PlaymodeOrder)
            self.playbackPanel.set_new_playmode(Configures.PlaymodeOrder)
    
    def playmode_random_seted(self):
        if self.playbackPanel.playmode != Configures.PlaymodeRandom:
            self.playmode_changed(self.playbackPanel.playmode, Configures.PlaymodeRandom)
            self.playbackPanel.set_new_playmode(Configures.PlaymodeRandom)
    
    def playmode_single_seted(self):
        if self.playbackPanel.playmode != Configures.PlaymodeSingle:
            self.playmode_changed(self.playbackPanel.playmode, Configures.PlaymodeSingle)
            self.playbackPanel.set_new_playmode(Configures.PlaymodeSingle)
    
    def show_minimized(self):
        self.showMinimized()

    def show_mainwindow(self):
        if self.isHidden():
            self.showMainWindowAction.setText('隐藏主界面')
            self.show()
        else:
            self.showMainWindowAction.setText('显示主界面')
            self.hide()
    
    def dont_hide_mainwindow(self):
        if self.isHidden():
            self.showMainWindowAction.setText('隐藏主界面')
            self.show()        
    
    def ui_initial(self):
        self.playbackPanel.ui_initial()
        self.managePage.ui_initial()
    
    def show_lyric_text(self):
        self.pageLabel.hide()
        self.mainPageButton.hide()
        self.managePage.show_main_stack_window()
    
    def show_about_page(self):
        self.show_page_label_and_button(self.tr('关于'))
        self.managePage.show_about_page()
    
    def show_settings_frame(self):
        self.show_page_label_and_button(self.tr('选项'))
        self.managePage.show_settings_frame()
    
    def search_musics_online(self, keyword):
        if self.managePage.searchFrame.search_musics(keyword):
            self.show_page_label_and_button(self.tr('搜索'))
            self.managePage.show_search_frame()

    def show_artist_info(self, name):
        self.show_page_label_and_button(self.tr('歌手'))
        self.managePage.show_artist_info(name)
    
    def show_song_info(self, row):
        self.show_page_label_and_button(self.tr('歌曲'))
        self.managePage.show_song_info(row)

    def hide_song_info_page(self, arg1=None, arg2=None):
        if self.managePage.get_page_description() == '歌曲':
            self.show_lyric_text()

    def show_page_label_and_button(self, pageName):
        self.pageLabel.setText(self.tr(pageName))
        self.mainPageButton.show()
        self.pageLabel.show()
    
    def close_button_acted(self):
        if self.closeButtonAct == Configures.SettingsHide:
            self.show_mainwindow()
        else:
            self.close()
Пример #24
0
class ShareWidget(QDialog):
    done = pyqtSignal(QWidget)
    closed = pyqtSignal(QWidget)

    def __init__(self, gateway, gui, folder_names=None):  # pylint:disable=too-many-statements
        super(ShareWidget, self).__init__()
        self.gateway = gateway
        self.gui = gui
        self.folder_names = folder_names
        self.folder_names_humanized = humanized_list(folder_names, 'folders')
        self.settings = {}
        self.wormhole = None
        self.pending_invites = []

        self.setMinimumSize(500, 300)

        header_icon = QLabel(self)
        if self.folder_names:
            icon = QFileIconProvider().icon(
                QFileInfo(
                    self.gateway.get_magic_folder_directory(
                        self.folder_names[0])))
        else:
            icon = QIcon(os.path.join(gateway.nodedir, 'icon'))
            if not icon.availableSizes():
                icon = QIcon(resource('tahoe-lafs.png'))
        header_icon.setPixmap(icon.pixmap(50, 50))

        header_text = QLabel(self)
        if self.folder_names:
            header_text.setText(self.folder_names_humanized)
        else:
            header_text.setText(self.gateway.name)
        font = QFont()
        font.setPointSize(18)
        header_text.setFont(font)
        header_text.setAlignment(Qt.AlignCenter)

        header_layout = QGridLayout()
        header_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1,
                              1)
        header_layout.addWidget(header_icon, 1, 2)
        header_layout.addWidget(header_text, 1, 3)
        header_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1,
                              4)

        self.subtext_label = QLabel(self)
        font = QFont()
        font.setPointSize(10)
        self.subtext_label.setFont(font)
        self.subtext_label.setStyleSheet("color: grey")
        self.subtext_label.setWordWrap(True)
        self.subtext_label.setAlignment(Qt.AlignCenter)

        self.noise_label = QLabel()
        font = QFont()
        font.setPointSize(16)
        font.setFamily("Courier")
        font.setStyleHint(QFont.Monospace)
        self.noise_label.setFont(font)
        self.noise_label.setStyleSheet("color: grey")

        self.noise_timer = QTimer()
        self.noise_timer.timeout.connect(
            lambda: self.noise_label.setText(b58encode(os.urandom(16))))
        self.noise_timer.start(75)

        self.code_label = QLabel()
        font = QFont()
        font.setPointSize(18)
        self.code_label.setFont(font)
        self.code_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.code_label.hide()

        self.box_title = QLabel(self)
        self.box_title.setAlignment(Qt.AlignCenter)
        font = QFont()
        font.setPointSize(16)
        self.box_title.setFont(font)

        self.box = QGroupBox()
        self.box.setAlignment(Qt.AlignCenter)
        self.box.setStyleSheet('QGroupBox {font-size: 16px}')

        self.copy_button = QToolButton()
        self.copy_button.setIcon(QIcon(resource('copy.png')))
        self.copy_button.setToolTip("Copy to clipboard")
        self.copy_button.setStyleSheet('border: 0px; padding: 0px;')
        self.copy_button.hide()

        box_layout = QGridLayout(self.box)
        box_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 1)
        box_layout.addWidget(self.noise_label, 1, 2)
        box_layout.addWidget(self.code_label, 1, 3)
        box_layout.addWidget(self.copy_button, 1, 4)
        box_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 5)

        self.close_button = QPushButton("Close and cancel invite")
        self.close_button.setAutoDefault(False)

        self.checkmark = QLabel()
        self.checkmark.setPixmap(
            QPixmap(resource('green_checkmark.png')).scaled(32, 32))
        self.checkmark.setAlignment(Qt.AlignCenter)
        self.checkmark.hide()

        self.progress_bar = QProgressBar()
        self.progress_bar.setMaximum(2)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.hide()

        layout = QGridLayout(self)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 0, 0)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 1)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 2)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 3)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 4)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 5)
        layout.addLayout(header_layout, 1, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 2, 1)
        layout.addWidget(self.box_title, 3, 2, 1, 3)
        layout.addWidget(self.checkmark, 3, 3)
        layout.addWidget(self.box, 4, 2, 1, 3)
        layout.addWidget(self.progress_bar, 4, 2, 1, 3)
        layout.addWidget(self.subtext_label, 5, 2, 1, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 6, 1)
        layout.addWidget(self.close_button, 7, 3)
        layout.addItem(QSpacerItem(0, 0, 0, QSizePolicy.Expanding), 8, 1)

        self.copy_button.clicked.connect(self.on_copy_button_clicked)
        self.close_button.clicked.connect(self.close)

        self.set_box_title("Generating invite code...")

        self.go()  # XXX

    def set_box_title(self, text):
        if sys.platform == 'darwin':
            self.box_title.setText(text)
            self.box_title.show()
        else:
            self.box.setTitle(text)

    def on_copy_button_clicked(self):
        code = self.code_label.text()
        for mode in get_clipboard_modes():
            set_clipboard_text(code, mode)
        self.subtext_label.setText(
            "Copied '{}' to clipboard!\n\n".format(code))

    def on_got_code(self, code):
        self.noise_timer.stop()
        self.noise_label.hide()
        self.set_box_title("Your invite code is:")
        self.code_label.setText(code)
        self.code_label.show()
        self.copy_button.show()
        if self.folder_names:
            if len(self.folder_names) == 1:
                abilities = 'download "{}" and modify its contents'.format(
                    self.folder_names[0])
            else:
                abilities = 'download {} and modify their contents'.format(
                    self.folder_names_humanized)
        else:
            abilities = 'connect to "{}" and upload new folders'.format(
                self.gateway.name)
        self.subtext_label.setText(
            "Entering this code on another device will allow it to {}.\n"
            "This code can only be used once.".format(abilities))

    def on_got_introduction(self):
        if sys.platform == 'darwin':
            self.box_title.hide()
        self.box.hide()
        self.progress_bar.show()
        self.progress_bar.setValue(1)
        self.subtext_label.setText("Connection established; sending invite...")

    def on_send_completed(self):
        self.box.hide()
        self.progress_bar.show()
        self.progress_bar.setValue(2)
        self.checkmark.show()
        self.close_button.setText("Finish")
        if self.folder_names:
            target = self.folder_names_humanized
        else:
            target = self.gateway.name
        text = "Your invitation to {} was accepted".format(target)
        self.subtext_label.setText("Invite successful!\n {} at {}".format(
            text,
            datetime.now().strftime('%H:%M')))
        if get_preference('notifications', 'invite') != 'false':
            self.gui.show_message("Invite successful", text)

    def handle_failure(self, failure):
        if failure.type == wormhole.errors.LonelyError:
            return
        logging.error(str(failure))
        show_failure(failure, self)
        self.wormhole.close()
        self.close()

    @inlineCallbacks
    def get_folder_invite(self, folder):
        member_id = b58encode(os.urandom(8))
        try:
            code = yield self.gateway.magic_folder_invite(folder, member_id)
        except TahoeError as err:
            code = None
            self.wormhole.close()
            error(self, "Invite Error", str(err))
            self.close()
        returnValue((folder, member_id, code))

    @inlineCallbacks
    def get_folder_invites(self):
        self.subtext_label.setText("Creating folder invite(s)...\n\n")
        folders_data = {}
        tasks = []
        for folder in self.folder_names:
            tasks.append(self.get_folder_invite(folder))
        results = yield gatherResults(tasks)
        for folder, member_id, code in results:
            folders_data[folder] = {'code': code}
            self.pending_invites.append((folder, member_id))
        returnValue(folders_data)

    @inlineCallbacks
    def go(self):
        self.wormhole = Wormhole()
        self.wormhole.got_code.connect(self.on_got_code)
        self.wormhole.got_introduction.connect(self.on_got_introduction)
        self.wormhole.send_completed.connect(self.on_send_completed)
        self.settings = self.gateway.get_settings()
        if self.folder_names:
            folders_data = yield self.get_folder_invites()
            self.settings['magic-folders'] = folders_data
        self.subtext_label.setText("Opening wormhole...\n\n")
        self.wormhole.send(self.settings).addErrback(self.handle_failure)

    def closeEvent(self, event):
        if self.code_label.text() and self.progress_bar.value() < 2:
            reply = QMessageBox.question(
                self, "Cancel invitation?",
                'Are you sure you wish to cancel the invitation to "{}"?\n\n'
                'The invite code "{}" will no longer be valid.'.format(
                    self.gateway.name, self.code_label.text()),
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if reply == QMessageBox.Yes:
                self.wormhole.close()
                if self.folder_names:
                    for folder, member_id in self.pending_invites:
                        self.gateway.magic_folder_uninvite(folder, member_id)
                event.accept()
                self.closed.emit(self)
            else:
                event.ignore()
        else:
            event.accept()
            if self.noise_timer.isActive():
                self.noise_timer.stop()
            self.closed.emit(self)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()
Пример #25
0
class StatusPanel(QWidget):
    def __init__(self, gateway, gui):
        super().__init__()
        self.gateway = gateway
        self.gui = gui

        self.state = 0
        self.num_connected = 0
        self.num_known = 0
        self.available_space = 0

        self.checkmark_icon = QLabel()
        self.checkmark_icon.setPixmap(Pixmap("checkmark.png", 20))

        self.syncing_icon = QLabel()

        self.sync_movie = QMovie(resource("sync.gif"))
        self.sync_movie.setCacheMode(True)
        self.sync_movie.updated.connect(
            lambda: self.syncing_icon.setPixmap(self.sync_movie.currentPixmap(
            ).scaled(20, 20, Qt.KeepAspectRatio, Qt.SmoothTransformation)))

        self.status_label = QLabel()
        p = self.palette()
        dimmer_grey = BlendedColor(p.windowText().color(),
                                   p.window().color(), 0.6).name()
        self.status_label.setStyleSheet(f"QLabel {{ color: {dimmer_grey} }}")
        self.status_label.setFont(Font(10))

        self.setStyleSheet("QToolButton { border: none }")
        # self.setStyleSheet("""
        #    QToolButton { color: dimgrey; border: none; }
        #    QToolButton:hover {
        #        background-color: #FAFAFA;
        #        border: 1px solid grey;
        #        border-radius: 2px;
        #    }
        # """)

        self.tor_button = QToolButton()
        self.tor_button.setIconSize(QSize(20, 20))
        self.tor_action = QAction(
            QIcon(resource("tor-onion.png")),
            "This connection is being routed through the Tor network",
        )
        self.tor_button.setDefaultAction(self.tor_action)
        if not self.gateway.use_tor:
            self.tor_button.hide()

        preferences_button = QToolButton(self)
        preferences_button.setIcon(QIcon(resource("preferences.png")))
        preferences_button.setIconSize(QSize(20, 20))
        preferences_button.setMenu(Menu(self.gui, show_open_action=False))
        preferences_button.setPopupMode(2)
        preferences_button.setStyleSheet(
            "QToolButton::menu-indicator { image: none }")

        layout = QGridLayout(self)
        left, _, right, bottom = layout.getContentsMargins()
        layout.setContentsMargins(left, 0, right, bottom - 2)
        layout.addWidget(self.checkmark_icon, 1, 1)
        layout.addWidget(self.syncing_icon, 1, 1)
        layout.addWidget(self.status_label, 1, 2)
        layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, 0), 1, 3)
        layout.addWidget(self.tor_button, 1, 4)
        layout.addWidget(preferences_button, 1, 6)

        self.gateway.monitor.total_sync_state_updated.connect(
            self.on_sync_state_updated)
        self.gateway.monitor.space_updated.connect(self.on_space_updated)
        self.gateway.monitor.nodes_updated.connect(self.on_nodes_updated)

        self.on_sync_state_updated(0)

    def _update_status_label(self):
        if self.state == 0:
            if self.gateway.shares_happy:
                if self.num_connected < self.gateway.shares_happy:
                    self.status_label.setText(
                        f"Connecting to {self.gateway.name} ("
                        f"{self.num_connected}/{self.gateway.shares_happy})..."
                    )
                else:
                    self.status_label.setText(
                        f"Connected to {self.gateway.name}")

            else:
                self.status_label.setText(
                    f"Connecting to {self.gateway.name}...")
            self.sync_movie.setPaused(True)
            self.syncing_icon.hide()
            self.checkmark_icon.hide()
        elif self.state == 1:
            self.status_label.setText("Syncing")
            self.checkmark_icon.hide()
            self.syncing_icon.show()
            self.sync_movie.setPaused(False)
        elif self.state == 2:
            self.status_label.setText("Up to date")
            self.sync_movie.setPaused(True)
            self.syncing_icon.hide()
            self.checkmark_icon.show()
        if self.available_space:
            self.status_label.setToolTip(
                "Connected to {} of {} storage nodes\n{} available".format(
                    self.num_connected, self.num_known, self.available_space))
        else:
            self.status_label.setToolTip(
                "Connected to {} of {} storage nodes".format(
                    self.num_connected, self.num_known))

    def on_sync_state_updated(self, state):
        self.state = state
        self._update_status_label()

    def on_space_updated(self, space):
        self.available_space = naturalsize(space)
        self._update_status_label()

    def on_nodes_updated(self, connected, known):
        self.num_connected = connected
        self.num_known = known
        self._update_status_label()
Пример #26
0
class myQTableWidget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.parent = parent
        self.lay = QVBoxLayout()
        self.laySearch = QHBoxLayout()
        self.lbl = QLabel()
        self.table = QTableWidget()
        self.table.setContextMenuPolicy(Qt.CustomContextMenu)
        self.table.verticalScrollBar().valueChanged.connect(
            self.on_table_verticalscrollbar_value_changed)
        self.table.verticalHeader().hide()
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.lbl.setText(self.tr("Add a string to filter rows"))
        self.txtSearch = QLineEdit()
        self.txtSearch.textChanged.connect(self.on_txt_textChanged)
        self.cmdCloseSearch = QToolButton()
        self.showSearchOptions(False)
        self.cmdCloseSearch.released.connect(self.on_cmdCloseSearch_released)
        self.laySearch.addWidget(self.lbl)
        self.laySearch.addWidget(self.txtSearch)
        self.laySearch.addWidget(self.cmdCloseSearch)
        self.lay.addWidget(self.table)
        self.lay.addLayout(self.laySearch)
        self.setLayout(self.lay)

        self.actionExport = QAction(self.tr("Export to Libreoffice Calc"))
        self.actionExport.setIcon(QIcon(":/reusingcode/libreoffice_calc.png"))
        self.actionExport.triggered.connect(self.on_actionExport_triggered)

        self.actionSizeMinimum = QAction(self.tr("Minimum column size"))
        self.actionSizeMinimum.triggered.connect(
            self.on_actionSizeMinimum_triggered)
        self.actionSizeNeeded = QAction(self.tr("Needed column size"))
        self.actionSizeNeeded.triggered.connect(
            self.on_actionSizeNeeded_triggered)

        self.actionSearch = QAction(self.tr("Search in table"))
        self.actionSearch.setIcon(QIcon(":/reusingcode/search.png"))
        self.actionSearch.triggered.connect(self.on_actionSearch_triggered)
        self.actionSearch.setShortcut(Qt.CTRL + Qt.Key_F)
        self.table.setAlternatingRowColors(True)
        self._last_height = None
        self._none_at_top = True

    def setVerticalHeaderHeight(self, height):
        """height, if null default.
        Must be after settings"""
        if height == None:
            self.table.verticalHeader().setSectionResizeMode(
                QHeaderView.ResizeToContents)
            self._last_height = None
        else:
            self.table.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
            self.table.verticalHeader().setDefaultSectionSize(height)
            self._last_height = height

    def sectionResized(self, logicalIndex, oldSize, newSize):
        modifiers = QApplication.keyboardModifiers()
        if modifiers == Qt.ShiftModifier:
            for i in range(self.table.columnCount()):
                self.table.setColumnWidth(i, newSize)
            self.settings.setValue(
                "{}/{}_horizontalheader_state".format(self.settingsSection,
                                                      self.settingsObject),
                self.table.horizontalHeader().saveState())
            debug("Saved {}/{}_horizontalheader_state".format(
                self.settingsSection, self.settingsObject))
        elif modifiers == Qt.ControlModifier:
            self.on_actionSizeMinimum_triggered()

    @pyqtSlot(int)
    def on_table_verticalscrollbar_value_changed(self, value):
        if value % 8 == 1:
            self.on_actionSizeNeeded_triggered()

    def settings(self, settings, settingsSection, objectname):
        self.settings = settings
        #For all myQTableWidget in settings app
        self.setVerticalHeaderHeight(
            int(self.settings.value("myQTableWidget/rowheight", 24)))
        self.settingsSection = settingsSection
        self.settingsObject = objectname
        self.setObjectName(self.settingsObject)

    def clear(self):
        """Clear table"""
        self.table.setRowCount(0)
        self.table.clearContents()

    ## Resizes columns if column width is less than table hint
    #def verticalScrollbarAction(self,  action):
    def wheelEvent(self, event):
        self.on_actionSizeNeeded_triggered()
        event.accept()

    @pyqtSlot()
    def keyPressEvent(self, event):
        if event.matches(QKeySequence.ZoomIn) and self._last_height != None:
            height = int(self.settings.value("myQTableWidget/rowheight", 24))
            self.settings.setValue("myQTableWidget/rowheight", height + 1)
            info("Setting myQTableWidget/rowheight set to {}".format(
                self.settings.value("myQTableWidget/rowheight", 24)))
            self.table.setVerticalHeaderHeight(
                int(self.settings.value("myQTableWidget/rowheight", 24)))
        elif event.matches(QKeySequence.ZoomOut) and self._last_height != None:
            height = int(self.settings.value("myQTableWidget/rowheight", 24))
            self.settings.setValue("myQTableWidget/rowheight", height - 1)
            ("Setting myQTableWidget/rowheight set to {}".format(
                self.settings.value("myQTableWidget/rowheight", 24)))
            self.table.setVerticalHeaderHeight(
                int(self.settings.value("myQTableWidget/rowheight", 24)))
        elif event.matches(QKeySequence.Print):
            filename = QFileDialog.getSaveFileName(
                self, self.tr("Save File"), "table.ods",
                self.tr("Libreoffice calc (*.ods)"))[0]
            if filename:
                ods = ODS_Write(filename)
                self.officegeneratorModel("My table").ods_sheet(ods)
                ods.save()

    ## Order data columns. None values are set at the beginning
    def on_orderby_action_triggered(self, action):
        action = QObject.sender(
            self
        )  #Busca el objeto que ha hecho la signal en el slot en el que está conectado
        action_index = self.hh.index(action.text().replace(
            " (desc)",
            ""))  #Search the position in the headers of the action Text

        # Sets if its reverse or not and renames action
        if action.text().find(self.tr(" (desc)")) > 0:
            reverse = True
            action.setText(action.text().replace(self.tr(" (desc)"), ""))
        else:  #No encontrado
            reverse = False
            action.setText(action.text() + " (desc)")

        nonull = []
        null = []
        for row in self.data:
            if row[action_index] is None:
                null.append(row)
            else:
                nonull.append(row)
        nonull = sorted(nonull, key=lambda c: c[action_index], reverse=reverse)
        if self._none_at_top == True:  #Set None at top of the list
            self.data = null + nonull
        else:
            self.data = nonull + null
        self.setData(self.hh, self.hv, self.data)

    def applySettings(self):
        """settings must be defined before"""
        self.table.horizontalHeader().setSectionResizeMode(
            QHeaderView.Interactive)
        self.table.horizontalHeader().sectionResized.connect(
            self.sectionResized)
        state = self.settings.value("{}/{}_horizontalheader_state".format(
            self.settingsSection, self.settingsObject))
        if state:
            self.table.horizontalHeader().restoreState(state)

    ## Adds a horizontal header array , a vertical header array and a data array
    ##
    ## Automatically set alignment
    ## @param decimals int or list with the columns decimals
    def setData(self,
                header_horizontal,
                header_vertical,
                data,
                decimals=2,
                zonename='UTC'):
        if decimals.__class__.__name__ == "int":
            decimals = [decimals] * len(header_horizontal)
        # Creates order actions here after creating data
        if hasattr(self, "actionListOrderBy") == False:
            self.actionListOrderBy = []
            for header in header_horizontal:
                action = QAction("{}".format(header))
                self.actionListOrderBy.append(action)
                action.triggered.connect(self.on_orderby_action_triggered)

        # Headers
        self.hh = header_horizontal
        self.hv = header_vertical
        self.data = data
        self.table.setColumnCount(len(self.hh))
        if self.hh is not None:
            for i in range(len(self.hh)):
                self.table.setHorizontalHeaderItem(
                    i, QTableWidgetItem(self.hh[i]))
        if self.hv is not None:
            self.table.verticalHeader().show()
            self.table.setRowCount(len(self.data))  # To do not lose data
            for i in range(len(self.hv)):
                self.table.setVerticalHeaderItem(i,
                                                 QTableWidgetItem(self.hv[i]))

        # Data
        self.applySettings()
        self.table.clearContents()
        self.table.setRowCount(len(self.data))
        for row in range(len(self.data)):
            for column in range(len(self.hh)):
                wdg = self.object2qtablewidgetitem(self.data[row][column],
                                                   decimals[column], zonename)
                if wdg.__class__.__name__ == "QWidget":  #wdgBool
                    self.table.setCellWidget(row, column, wdg)
                else:  #qtablewidgetitem
                    self.table.setItem(row, column, wdg)

    def print(self, hh, hv, data):

        print(hh)
        for i, row in enumerate(data):
            print(hv[i], row)

        print("Len hh:", len(hh))
        print("Len hv:", len(hv))
        print("Len data:", len(data[0]), "x", len(data))

    ## If true None values are set at the top of the list after sorting. If not at the bottom of the list
    def setNoneAtTop(self, boolean):
        self._none_at_top = boolean

    ## Adds a horizontal header array , a vertical header array and a data array
    ##
    ## Automatically set alignment
    ## @param manager Manager object from libmanagers
    ## @param manager_attributes List of Strings with name of the object attributes, order by appareance
    def setDataFromManager(self,
                           header_horizontal,
                           header_vertical,
                           manager,
                           manager_attributes,
                           decimals=2,
                           zonename='UTC'):
        self.manager_attributes = manager_attributes
        self.manager = manager
        data = []
        for o in manager.arr:
            row = []
            for attribute in self.manager_attributes:
                row.append(self._attribute_to_command(o, attribute))
            data.append(row)
        self.setData(header_horizontal, header_vertical, data, decimals,
                     zonename)

    ## @param attribute str or list
    ## Class Person, has self.name, self.age(), self.age_years_ago(year) self.son (another Person object)
    ## manager_attributes of setDataFromManager must be called in a PersonManager
    ## - ["name", ["age",[]], ["age_years_ago", [year]], ["son.age",[]]
    def _attribute_to_command(self, o, attribute):
        ## Returns an object
        def str_attribute_with_points(o, attribute):
            for s in attribute.split("."):
                o = getattr(o, s)
            return o

        # --------------------------------------
        if attribute.__class__.__name__ == "str":
            return str_attribute_with_points(o, attribute)
        else:  #List
            function = str_attribute_with_points(o, attribute[0])
            parameters = attribute[1]
            return function(*parameters)

    ## Converts a objecct class to a qtablewidgetitem
    def object2qtablewidgetitem(self, o, decimals=2, zonename="UTC"):
        if o.__class__.__name__ in ["int"]:
            return qright(o)
        elif o.__class__.__name__ in ["datetime"]:
            return qdatetime(o, zonename)
        elif o.__class__.__name__ in ["float", "Decimal"]:
            return qnumber(o, decimals)
        elif o.__class__.__name__ in ["Percentage", "Money", "Currency"]:
            return o.qtablewidgetitem(decimals)
        elif o.__class__.__name__ in [
                "bool",
        ]:
            return wdgBool(o)
        elif o is None:
            return qnone()
        elif o == "":
            return qempty()
        elif o == "#crossedout":
            return qcrossedout()
        else:
            return qleft(o)

    ## Returns a list of strings with the horizontal headers
    def listHorizontalHeaders(self):
        if self.hh is None:
            return None
        header = []
        for i in range(self.table.horizontalHeader().count()):
            header.append(self.table.horizontalHeaderItem(i).text())
        return header

    ## Returns a list of strings with the horizontal headers
    def listVerticalHeaders(self):
        if self.hv is None:
            return None
        header = []
        for i in range(self.table.verticalHeader().count()):
            if self.table.verticalHeaderItem(i) is not None:
                header.append(self.table.verticalHeaderItem(i).text())
        return header

    ## Returns a lisf of rows with the text of the
    def listText(self):
        data = []
        for i in range(self.table.rowCount()):
            row = []
            for column in range(self.table.columnCount()):
                data.append(self.table.item(row, column).text())
        return data

    ## @param rsActionExport String ":/xulpymoney/save.png" for example
    def setIcons(self, rsActionExport=None):
        if rsActionExport is not None:
            self.actionExport.setIcon(QIcon(rsActionExport))

    def on_cmdCloseSearch_released(self):
        self.txtSearch.setText("")
        self.showSearchOptions(False)

    def showSearchOptions(self, boolean):
        if boolean == True:
            self.lbl.show()
            self.txtSearch.show()
            self.cmdCloseSearch.show()
        else:
            self.lbl.hide()
            self.txtSearch.hide()
            self.cmdCloseSearch.hide()

    def showSearchCloseButton(self, boolean):
        if boolean == True:
            self.cmdCloseSearch.show()
        else:
            self.cmdCloseSearch.hide()

    def on_actionExport_triggered(self):
        filename = QFileDialog.getSaveFileName(
            self, self.tr("Save File"), "table.ods",
            self.tr("Libreoffice calc (*.ods)"))[0]
        if filename:
            ods = ODS_Write(filename)
            self.officegeneratorModel("My table").ods_sheet(ods)
            ods.save()

    def on_actionSizeMinimum_triggered(self):
        self.table.resizeRowsToContents()
        self.table.resizeColumnsToContents()
        self.settings.setValue(
            "{}/{}_horizontalheader_state".format(self.settingsSection,
                                                  self.settingsObject),
            self.table.horizontalHeader().saveState())
        debug("Saved {}/{}_horizontalheader_state".format(
            self.settingsSection, self.settingsObject))

    def on_actionSizeNeeded_triggered(self):
        for i in range(self.table.columnCount()):
            if self.table.sizeHintForColumn(i) > self.table.columnWidth(i):
                self.table.setColumnWidth(i, self.table.sizeHintForColumn(i))
        self.settings.setValue(
            "{}/{}_horizontalheader_state".format(self.settingsSection,
                                                  self.settingsObject),
            self.table.horizontalHeader().saveState())
        debug("Saved {}/{}_horizontalheader_state".format(
            self.settingsSection, self.settingsObject))

    def on_actionSearch_triggered(self):
        self.lbl.show()
        self.txtSearch.show()
        self.cmdCloseSearch.show()
        self.txtSearch.setFocus()

    ## Returns a qmenu to be used in other qmenus
    def qmenu(self, title="Table options"):
        menu = QMenu(self.parent)
        menu.setTitle(self.tr(title))
        menu.addAction(self.actionExport)
        menu.addSeparator()
        menu.addAction(self.actionSearch)
        menu.addSeparator()
        order = QMenu(menu)
        order.setTitle(self.tr("Order by"))
        for action in self.actionListOrderBy:
            order.addAction(action)
        menu.addMenu(order)
        size = QMenu(menu)
        size.setTitle(self.tr("Columns size"))
        size.addAction(self.actionSizeMinimum)
        size.addAction(self.actionSizeNeeded)
        menu.addMenu(size)
        return menu

    def on_txt_textChanged(self, text):
        for row in range(self.table.rowCount()):
            found = False
            for column in range(self.table.columnCount()):
                if self.table.item(row, column).text().lower().find(
                        text.lower()) >= 0:
                    found = True
                    break
            if found == False:
                self.table.hideRow(row)
            else:
                self.table.showRow(row)

    def officegeneratorModel(self, title="sheet"):
        def pixel2cm(pixels):
            #Converts size in pixels to cm
            PixelWidthDimension = self.logicalDpiX()  # width dots per inch
            inch = pixels / PixelWidthDimension
            cm = inch * 2.54 * (1 + 0.05)
            return cm

        # # # # # # # # # #
        widths = []
        vwidth = pixel2cm(self.table.verticalHeader().width())
        for i in range(self.table.columnCount()):
            widths.append(pixel2cm(self.table.columnWidth(i)))

        from officegenerator.standard_sheets import Model
        m = Model()
        m.setTitle(title)
        m.setHorizontalHeaders(self.listHorizontalHeaders(), widths)
        m.setVerticalHeaders(self.listVerticalHeaders(), vwidth)
        m.setData(self.data)
        return m
Пример #27
0
class Board(QWidget):
    def __init__(self, chessBoard, ai=None):
        super().__init__()
        self.oriChessBoard = copy.deepcopy(chessBoard)
        self.chessBoard = chessBoard
        self.ai = ai
        self.tiles = []
        self.lastMove = []
        self.pickedPiece = None
        self.edge = None
        self.checkEdge = None
        self.notice = None
        self.blackCheckBoard, self.blackCheck = fillCheckBoard(
            self.chessBoard, Team.BLACK)
        self.whiteCheckBoard, self.whiteCheck = fillCheckBoard(
            self.chessBoard, Team.WHITE)
        # self.repaintBoard()
        self.initUI()
        self.setCenter()

    def initUI(self):
        self.setFixedSize(800, 800)
        self.setGeometry(0, 0, 800, 800)
        self.setWindowTitle("Chess")
        self.selectMode()

        self.show()

    def selectMode(self):
        self.mainPalette = QPalette()
        self.mainPalette.setBrush(
            10,
            QBrush(
                QImage(
                    os.path.dirname(os.path.abspath(__file__)) +
                    '/images/mainWin.jpg').scaled(QSize(800, 800))))
        self.setPalette(self.mainPalette)

        self.singleButton = QToolButton(self)
        self.singleButton.setText("Single Mode")
        self.setStyleSheet("font-size: 40px;")
        self.singleButton.setStyleSheet("background-color:#993800;")
        self.singleButton.setGeometry(150, 200, 500, 100)
        self.singleButton.clicked.connect(self.callback)

        self.aiButton = QToolButton(self)
        self.aiButton.setText("AI Mode")
        self.aiButton.setStyleSheet("background-color:#FFDEA9;")
        self.aiButton.setGeometry(150, 500, 500, 100)
        self.aiButton.clicked.connect(self.callback)

    def callback(self):
        self.mode = self.sender().text()

        if self.mode == "Single Mode":
            self.ai = None
        elif self.mode == "AI Mode":
            self.ai = AI()
            notice = DifficultyNotice(self.ai)
            notice.exec_()
            print(self.ai.searcher.depth)

        self.singleButton.hide()
        self.aiButton.hide()

        self.turn = Team.WHITE
        self.drawBoard()

    def drawBoard(self):
        # 체스 보드를 배경화면으로 설정
        self.chessPalette = QPalette()
        self.chessPalette.setBrush(
            10,
            QBrush(
                QImage(
                    os.path.dirname(os.path.abspath(__file__)) +
                    '/images/chessboard.png').scaled(QSize(800, 800))))
        self.setPalette(self.chessPalette)

        self.repaintBoard()

    def setCenter(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def pickPiece(self):
        piece = self.sender().piece
        if piece.team == self.turn:
            self.pickedPiece = piece
            if self.edge != None:
                self.edge.move(piece.pos['x'] * 100, piece.pos['y'] * 100)
            else:
                self.edge = QLabel(self)
                self.edge.setPixmap(
                    QPixmap(
                        os.path.dirname(os.path.abspath(__file__)) +
                        '/images/yellowedge.png'))
                self.edge.move(piece.pos['x'] * 100, piece.pos['y'] * 100)
                self.edge.show()
        else:
            if self.pickedPiece != None:
                self.lastMove = [self.pickedPiece.pos, piece.pos]
                if self.pickedPiece.getType() == "Pawn":
                    #미리 움직여서 왕이 체크인지 확인. 체크이면 리턴
                    preBoard = copy.deepcopy(self.chessBoard)
                    prePiece = copy.deepcopy(self.pickedPiece)
                    preSuccess = prePiece.move(
                        Position(piece.pos['x'], piece.pos['y']), preBoard)[0]

                    if not (preSuccess):
                        return
                    check = fillCheckBoard(preBoard, prePiece.team)[1]
                    if check:
                        return

                    #실제 움직임
                    success, promotion = self.pickedPiece.move(
                        Position(piece.pos['x'], piece.pos['y']),
                        self.chessBoard)
                    if not (success):
                        return
                    else:
                        if promotion:
                            self.notice = PromotionNotice(
                                self.pickedPiece.team, self.chessBoard,
                                Position(self.pickedPiece.pos['x'],
                                         self.pickedPiece.pos['y']))
                            self.notice.exec_()
                elif self.pickedPiece.getType() != "King":
                    #미리 움직임
                    preBoard = copy.deepcopy(self.chessBoard)
                    prePiece = copy.deepcopy(self.pickedPiece)
                    preSuccess = prePiece.move(
                        Position(piece.pos['x'], piece.pos['y']), preBoard)

                    if not (preSuccess):
                        return
                    check = fillCheckBoard(preBoard, prePiece.team)[1]
                    if check:
                        return

                    #실제 움직임
                    if not (self.pickedPiece.move(
                            Position(piece.pos['x'], piece.pos['y']),
                            self.chessBoard)):
                        return
                else:  # King
                    if not (self.pickedPiece.move(
                            Position(piece.pos['x'], piece.pos['y']),
                            self.chessBoard, self.whiteCheckBoard if self.turn
                            == Team.WHITE else self.blackCheckBoard)):
                        return
                # try:
                self.blackCheckBoard, self.blackCheck = fillCheckBoard(
                    self.chessBoard, Team.BLACK)
                self.whiteCheckBoard, self.whiteCheck = fillCheckBoard(
                    self.chessBoard, Team.WHITE)
                # except:
                #     notice = EndNotice(self.turn)
                #     notice.exec_()
                #     self.deleteLater()
                self.turn = Team.BLACK if self.turn == Team.WHITE else Team.WHITE
                self.edge.hide()
                self.edge.deleteLater()
                self.edge = None
                self.repaintBoard()
                self.repaint()
                if self.ai != None and len(self.lastMove) == 2:
                    self.aiMove()
                    self.repaintBoard()
                self.pickedPiece = None
            else:
                return

    def mousePressEvent(self, e):
        x, y = e.x() // 100, e.y() // 100
        if self.pickedPiece != None:
            self.lastMove = [self.pickedPiece.pos, Position(x, y)]
            if self.pickedPiece.getType() == "Pawn":
                #미리 움직여서 왕이 체크인지 확인. 체크이면 리턴
                preBoard = copy.deepcopy(self.chessBoard)
                prePiece = copy.deepcopy(self.pickedPiece)
                preSuccess = prePiece.move(Position(x, y), preBoard)[0]
                if not (preSuccess):
                    return
                check = fillCheckBoard(preBoard, prePiece.team)[1]
                if check:
                    return

                #실제 움직임
                success, promotion = self.pickedPiece.move(
                    Position(x, y), self.chessBoard)
                if not (success):
                    return
                else:
                    if promotion:
                        self.notice = PromotionNotice(self.pickedPiece.team,
                                                      self.chessBoard,
                                                      Position(x, y))
                        self.notice.exec_()
            elif self.pickedPiece.getType() != "King":
                #미리 움직여서 왕이 체크인지 확인. 체크이면 리턴
                preBoard = copy.deepcopy(self.chessBoard)
                prePiece = copy.deepcopy(self.pickedPiece)
                preSuccess = prePiece.move(Position(x, y), preBoard)
                if not (preSuccess):
                    return
                check = fillCheckBoard(preBoard, prePiece.team)[1]
                if check:
                    return

                #실제 움직임
                if not (self.pickedPiece.move(Position(x, y),
                                              self.chessBoard)):
                    return
            else:
                if not (self.pickedPiece.move(
                        Position(x, y), self.chessBoard, self.whiteCheckBoard
                        if self.turn == Team.WHITE else self.blackCheckBoard)):
                    return
            self.pickedPiece = None
            self.edge.hide()
            self.edge.deleteLater()
            self.edge = None
            # try:
            self.blackCheckBoard, self.blackCheck = fillCheckBoard(
                self.chessBoard, Team.BLACK)
            self.whiteCheckBoard, self.whiteCheck = fillCheckBoard(
                self.chessBoard, Team.WHITE)
            # except:
            # notice = EndNotice(self.turn)
            # notice.exec_()
            # self.deleteLater()
            self.turn = Team.BLACK if self.turn == Team.WHITE else Team.WHITE
            self.repaintBoard()
            self.repaint()
            if self.ai != None and len(self.lastMove) == 2:
                self.aiMove()
                self.repaintBoard()

    def repaintBoard(self):
        ck = None
        for tile in self.tiles:
            tile.deleteLater()
        self.tiles = []
        if self.checkEdge != None:
            self.checkEdge.hide()
            self.checkEdge.deleteLater()
            self.checkEdge = None

        for y in range(8):
            for x in range(8):
                if self.chessBoard[y][x] == None:
                    continue
                # 폰의 dieByEnpassant 값을 내림.
                if self.chessBoard[y][x].getType() == "Pawn":
                    if self.chessBoard[y][x].dieByEnpassant > 0:
                        self.chessBoard[y][x].dieByEnpassant -= 1
                # 킹이 체크인 경우 하이라이팅
                elif self.chessBoard[y][x].getType() == "King":
                    if self.chessBoard[y][x].team == self.turn and (
                            self.whiteCheck
                            if self.turn == Team.WHITE else self.blackCheck):
                        self.checkEdge = QLabel(self)
                        self.checkEdge.setPixmap(
                            QPixmap(
                                os.path.dirname(os.path.abspath(__file__)) +
                                '/images/rededge.png'))
                        self.checkEdge.move(x * 100, y * 100)
                        self.checkEdge.show()

                        #체크메이트 확인
                        ck = checkmate(
                            self.chessBoard, self.whiteCheckBoard if self.turn
                            == Team.WHITE else self.blackCheckBoard, self.turn)
                        if ck:
                            print("CheckMate", ck)
                        else:
                            print("Check", ck)

                tile = Tile(self.chessBoard[y][x], self)
                self.tiles.append(tile)
                tile.setGeometry(x * 100, y * 100, 100, 100)
                tile.clicked.connect(self.pickPiece)
                tile.show()

        self.setWindowTitle(
            f"Chess: {Team.BLACK if self.turn == Team.BLACK else Team.WHITE}")
        if ck:
            self.reset("Checkmate")

        #스테일메이트 확인
        stm = staleMate(
            self.chessBoard, self.whiteCheckBoard
            if self.turn == Team.WHITE else self.blackCheckBoard, self.turn)
        if stm:
            print("Stalemate")
            self.reset("Stalemate")
        print(stm)

    # def reduceValueOfPawnEnpassant(self):
    #     for y in range(8):
    #         for x in range(8):
    #             if self.chessBoard[y][x] != None and self.chessBoard[y][x].getType() == "Pawn":
    #                 if self.chessBoard[y][x].dieByEnpassant > 0:
    #                     self.chessBoard[y][x].dieByEnpassant -= 1

    def reset(self, state):
        notice = EndNotice(
            Team.BLACK if self.turn == Team.WHITE else Team.WHITE, state)
        notice.exec_()
        self.singleButton.show()
        self.aiButton.show()
        self.chessBoard = copy.deepcopy(self.oriChessBoard)
        self.setPalette(self.mainPalette)
        for tile in self.tiles:
            tile.deleteLater()
        self.tiles = []
        self.lastMove = []
        if self.edge != None:
            self.edge.deleteLater()
            self.edge = None
        self.pickedPiece = None
        if self.checkEdge != None:
            self.checkEdge.deleteLater()
            self.checkEdge = None
        if self.notice != None:
            self.notice.deleteLater()
            self.notice = None
        self.blackCheckBoard, self.blackCheck = fillCheckBoard(
            self.chessBoard, Team.BLACK)
        self.whiteCheckBoard, self.whiteCheck = fillCheckBoard(
            self.chessBoard, Team.WHITE)
        self.repaint()

    def aiMove(self):
        self.setWindowTitle("Chess: AI")

        # parse
        move = ""
        for p in self.lastMove:
            move += chr(p['x'] + ord('a')) + str(8 - p['y'])
        print(f"player move: {move}")
        self.ai.hist.append(self.ai.hist[-1].move(
            (self.ai.parse(move[:2]), self.ai.parse(move[2:]))))
        self.ai.print_pos(self.ai.hist[-1].rotate())

        # search
        start = time.time()
        for _, move, _ in self.ai.searcher.search(self.ai.hist[-1],
                                                  self.ai.hist):
            if time.time() - start > self.ai.time:
                break

        # move
        self.ai.hist.append(self.ai.hist[-1].move(move))
        move = self.ai.render(119 - move[0]) + self.ai.render(119 - move[1])
        print(f"ai move: {move}")
        x1, y1, x2, y2 = ord(move[0]) - ord('a'), 8 - int(move[1]), ord(
            move[2]) - ord('a'), 8 - int(move[3])

        self.ai.print_pos(self.ai.hist[-1])

        if self.chessBoard[y1][x1].getType() == "Pawn":
            piece = self.chessBoard[y1][x1]
            _, promotion = piece.move(Position(x2, y2), self.chessBoard)
            if promotion:
                self.chessBoard[y2][x2] = Queen(piece.pos, piece.team)
        elif self.chessBoard[y1][x1].getType() == "King":
            self.chessBoard[y1][x1].move(Position(x2, y2), self.chessBoard,
                                         self.blackCheckBoard)
        else:
            self.chessBoard[y1][x1].move(Position(x2, y2), self.chessBoard)
        # refresh CheckBoard
        self.whiteCheckBoard, self.whiteCheck = fillCheckBoard(
            self.chessBoard, Team.WHITE)
        self.blackCheckBoard, self.BlackCheck = fillCheckBoard(
            self.chessBoard, Team.BLACK)
        self.turn = Team.WHITE

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Escape:
            self.close()
Пример #28
0
class HomeRecommendedItem(QWidget, fc_home_recommended_item):
    """
    This class represents a HomeRecommendedItem widget which is shown on the home page. This widget can either show
    a channel or a torrent.
    """

    def __init__(self, parent):
        QWidget.__init__(self, parent)
        fc_home_recommended_item.__init__(self)

        self.setupUi(self)

        self.show_torrent = True
        self.torrent_info = None
        self.channel_info = None
        self.download_uri = None
        self.dialog = None

        # Create the category label, shown on cells that display a torrent on the home page
        self.category_label = QLabel(self)
        self.category_label.setFixedHeight(24)
        self.category_label.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed))
        self.category_label.setStyleSheet("""
        border: 2px solid white;
        border-radius: 12px;
        background-color: transparent;
        color: white;
        padding-left: 4px;
        padding-right: 4px;
        font-weight: bold;
        """)
        self.category_label.move(QPoint(6, 6))
        self.category_label.show()

        # Create the dark overlay and download button over the thumbnail on hover
        self.dark_overlay = QWidget(self)
        self.dark_overlay.setStyleSheet("background-color: rgba(0, 0, 0, 0.65);")
        self.dark_overlay.hide()

        self.download_button = QToolButton(self)
        self.download_button.setFixedSize(QSize(40, 40))
        self.download_button.setStyleSheet("""
        QToolButton {
            background-color: transparent;
            border: 2px solid white;
            border-radius: 20px;
        }

        QToolButton::hover {
            border: 2px solid #B5B5B5;
        }
        """)
        self.download_button.setIcon(QIcon(get_image_path('downloads.png')))
        self.download_button.setIconSize(QSize(18, 18))
        self.download_button.clicked.connect(self.on_download_button_clicked)
        self.download_button.hide()

    def on_download_button_clicked(self):
        if not self.torrent_info:
            return
        self.download_uri = (u"magnet:?xt=urn:btih:%s&dn=%s" %
                             (self.torrent_info["infohash"], self.torrent_info['name'])).encode('utf-8')
        self.window().start_download_from_uri(self.download_uri)

    def update_with_torrent(self, torrent):
        if not torrent:
            return
        self.show_torrent = True
        self.torrent_info = torrent
        self.thumbnail_widget.initialize(torrent["name"], HOME_ITEM_FONT_SIZE)
        self.main_label.setText(torrent["name"])
        self.category_label.setText(torrent["category"].lower())
        self.category_label.adjustSize()
        self.category_label.setHidden(False)
        self.setCursor(Qt.ArrowCursor)
        self.detail_label.setText("Size: " + format_size(torrent["size"]))

    def update_with_channel(self, channel):
        if not channel:
            return
        self.show_torrent = False
        self.channel_info = channel
        self.thumbnail_widget.initialize(channel["name"], HOME_ITEM_FONT_SIZE)

        self.main_label.setText(channel["name"])
        self.detail_label.setText("Updated " + pretty_date(channel["modified"]))
        self.category_label.setHidden(True)
        self.setCursor(Qt.PointingHandCursor)

    def enterEvent(self, _):
        if self.show_torrent:
            self.dark_overlay.resize(self.thumbnail_widget.size())
            self.dark_overlay.show()
            self.download_button.move((self.thumbnail_widget.width() - self.download_button.width()) / 2,
                                      (self.thumbnail_widget.height() - self.download_button.height()) / 2)
            self.download_button.show()

    def leaveEvent(self, _):
        self.dark_overlay.hide()
        self.download_button.hide()
Пример #29
0
class wdgTwoCurrencyLineEdit(QWidget):
    factorChanged = pyqtSignal(
        Decimal
    )  #Se usa para cargar datos de ordenes en los datos de este formulario
    textChanged = pyqtSignal()

    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self.horizontalLayout = QHBoxLayout(self)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)

        self.label = QLabel(self)
        self.label.setText(self.tr("Select a product"))
        self.horizontalLayout.addWidget(self.label)

        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)

        self.txtA = myQLineEdit(self)
        self.txtA.setAlignment(Qt.AlignRight | Qt.AlignTrailing
                               | Qt.AlignVCenter)
        self.txtA.setToolTip(self.tr("Press the search button"))
        self.txtA.setText(0)
        self.horizontalLayout.addWidget(self.txtA)

        self.lblCurrencyA = QLabel(self)
        self.horizontalLayout.addWidget(self.lblCurrencyA)

        self.cmd = QToolButton(self)
        icon = QIcon()
        icon.addPixmap(QPixmap(":/xulpymoney/transfer.png"), QIcon.Normal,
                       QIcon.Off)
        self.cmd.setIcon(icon)
        self.cmd.released.connect(self.on_cmd_released)
        self.horizontalLayout.addWidget(self.cmd)
        self.cmd.hide()

        self.txtB = myQLineEdit(self)
        self.txtB.setAlignment(Qt.AlignRight | Qt.AlignTrailing
                               | Qt.AlignVCenter)
        self.txtB.setToolTip(self.tr("Press the search button"))
        self.txtB.setText(0)
        self.horizontalLayout.addWidget(self.txtB)

        self.lblCurrencyB = QLabel(self)
        self.horizontalLayout.addWidget(self.lblCurrencyB)

        sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(2)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.txtA.sizePolicy().hasHeightForWidth())
        self.txtA.setSizePolicy(sizePolicy)
        sizePolicyb = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        sizePolicyb.setHorizontalStretch(2)
        sizePolicyb.setVerticalStretch(0)
        sizePolicyb.setHeightForWidth(
            self.txtB.sizePolicy().hasHeightForWidth())
        self.txtB.setSizePolicy(sizePolicy)
        self.setLabelSize(200)
        self.factormode = False

    def setLabelSize(self, size):
        """
            Sets the label size
        """
        self.label.setFixedWidth(size)

    def setLabel(self, text):
        self.label.setText(text)

    def setFactorMode(self, boolean):
        """
            Este widget esta en factor mode y puede editar ambos textos, el resultado es un factor, que podrá ser 
            usado en otros widgets con setNewFactor
        """
        self.factormode = boolean
        if boolean == True:
            self.cmd.show()
            self.setTextA(1)
            self.setTextB(self.factor)
        else:
            self.cmd.hide()

    def on_cmd_released(self):
        self.txtA.textChanged.disconnect()
        self.txtB.textChanged.disconnect()
        tmp = self.txtA.decimal()
        self.txtA.setText(Decimal(1) / self.txtB.decimal())
        self.txtB.setText(Decimal(1) / tmp)
        self.txtA.textChanged.connect(self.on_txtA_textChanged)
        self.txtB.textChanged.connect(self.on_txtB_textChanged)

    def set(self, mem, currencya, currencyb, factor):
        """Investement is used to set investment pointer. It's usefull to see investment data in product report
        factor is to mul A to get b"""
        self.mem = mem
        self.factor = factor
        self.currencya = currencya
        self.currencyb = currencyb

        if self.currencya == self.currencyb:
            self.lblCurrencyB.hide()
            self.txtB.hide()

        self.lblCurrencyA.setText(currency_symbol(self.currencya) + " ")
        self.lblCurrencyB.setText(currency_symbol(self.currencyb))

        self.txtA.textChanged.disconnect()
        self.txtB.textChanged.disconnect()
        self.txtB.setText(self.txtA.decimal() * factor)
        self.textChanged.emit()
        self.txtA.textChanged.connect(self.on_txtA_textChanged)
        self.txtB.textChanged.connect(self.on_txtB_textChanged)

    def isValid(self):
        if self.txtA.isValid() and self.txtB.isValid():
            return True
        return False

    def setTextA(self, text):
        self.txtA.setText(text)

    def setTextB(self, text):
        self.txtB.setText(text)

    def decimalA(self):
        return self.txtA.decimal()

    def decimalB(self):
        return self.txtB.decimal()

    def on_txtA_textChanged(self, text):
        myQLineEdit.on_textChanged(self.txtA, text)
        if self.txtA.isValid():
            if self.factormode == True:
                if self.txtB.decimal() == Decimal(0):
                    return
                self.factor = self.txtA.decimal() / self.txtB.decimal()
                self.factorChanged.emit(self.factor)
            else:
                self.txtB.textChanged.disconnect()
                self.txtB.setText(self.txtA.decimal() * self.factor)
                self.txtB.textChanged.connect(self.on_txtB_textChanged)
        self.textChanged.emit()

    def on_txtB_textChanged(self, text):
        myQLineEdit.on_textChanged(self.txtB, text)
        if self.txtB.isValid():
            if self.factormode == True:
                if self.txtA.decimal() == Decimal(0):
                    return
                self.factor = self.txtB.decimal() / self.txtA.decimal()
                self.factorChanged.emit(self.factor)
            else:
                self.txtA.textChanged.disconnect()
                self.txtA.setText(self.txtB.decimal() / self.factor)
                self.txtA.textChanged.connect(self.on_txtA_textChanged)
        self.textChanged.emit()

    def setReadOnly(self, boolean):
        self.txtA.setReadOnly(boolean)
        self.txtB.setReadOnly(boolean)
Пример #30
0
class PictureEditor(QWidget):
    modeChanged = pyqtSignal(EditMode)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.bkimage = QPixmap('./ui/png/tile.png')
        self.photo = None
        self.currentZoom = 1.0
        self.offset = QPoint(0, 0)
        self.mode = EditMode.IDLE
        # overlays
        self.mesOverlay = MesOverlay(self)
        self.mesOverlay.doneCallBack = self._onMeasureDone
        self.roiOverlay = RoiOverlay(self)
        self.contOverlay = ContOverlay(self)
        self.contOverlay.freehandDone = self._onFreeHandDone
        self.overlays = [self.mesOverlay, self.roiOverlay, self.contOverlay]
        # eingebettete button
        self.btnContPlus = QToolButton(self)
        self.btnContPlus.setIcon(qta.icon('fa5s.plus', color='white'))
        self.btnContPlus.setStyleSheet("background-color: #19232D")
        self.btnContPlus.clicked.connect(self._onAddCountClicked)
        self.btnContPlus.hide()
        self.btnContMinus = QToolButton(self)
        self.btnContMinus.setIcon(qta.icon('fa5s.minus', color='white'))
        self.btnContMinus.setStyleSheet("background-color: #19232D")
        self.btnContMinus.clicked.connect(self._onRemoveCountClicked)
        self.btnContMinus.hide()
        self.btnFindCont = QPushButton('Find Contours', self)
        self.btnFindCont.clicked.connect(self._onFindContClicked)
        self.btnFindCont.hide()

        mngr = QtGui.qApp.sessionManager
        mngr.contourChanged.connect(self.updateContour)
        self.setMouseTracking(True)
        self.show()

    def setPhoto(self, photo, roi=None):
        self.mesOverlay.reset()
        self.photo = photo
        if roi is not None:
            if roi.isValid():
                self.roiOverlay.imageRoi = roi
            else:
                w = photo.width()
                h = photo.height()
                self.roiOverlay.imageRoi = QRect(w / 4, h / 4, w / 2, h / 2)
            self.setMode(EditMode.ROI)
        else:
            self.update()

    def setMode(self, mode):
        if mode == self.mode:
            return
        newoverlay = self.getOverlay(mode)
        oldoverlay = self.getOverlay(self.mode)
        if oldoverlay is not None:
            oldoverlay.leave()
        if newoverlay is not None:
            newoverlay.enter()
        self.btnContPlus.hide()
        self.btnContMinus.hide()
        self.btnFindCont.setVisible(mode == EditMode.ROI)
        self.mode = mode
        self.modeChanged.emit(mode)
        self.update()

    @pyqtSlot(QPolygonF)
    def updateContour(self, cont):
        self.contOverlay.contour = cont
        self.update()

    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        crc = self.rect()
        painter.fillRect(crc, QBrush(self.bkimage))
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setRenderHint(QPainter.HighQualityAntialiasing)
        if self.photo is not None:
            srcrect = self.photo.rect()
            destrect = self.transform().mapRect(srcrect)
            painter.drawPixmap(destrect, self.photo, srcrect)
            painter.fillRect(crc, QBrush(QColor(0, 0, 0, 40)))
        if self.mode == EditMode.IDLE:
            # alle duerfen zeichen
            for overlay in self.overlays:
                overlay.render(painter)
        else:
            self.getOverlay(self.mode).render(painter)
        painter.end()

    def event(self, event):
        proc = False
        overlay = self.getOverlay(self.mode)
        if overlay is not None:
            if overlay.routeEvent(event):
                proc = True
        if self.mode == EditMode.ROI:
            # update pos von fund contour button
            imroi = self.roiOverlay.imageRoi.normalized()
            br = self.transform().map(imroi.bottomRight())
            self.btnFindCont.move(br.x() - self.btnFindCont.width(),
                                  br.y() + 8)
        if proc is True:
            return True
        else:
            return super().event(event)

    def mousePressEvent(self, event):
        if event.button() == Qt.MiddleButton:
            self._mousePressedPos = event.pos() - self.offset

    def mouseMoveEvent(self, event):
        if event.buttons() & Qt.MiddleButton:
            self.offset = event.pos() - self._mousePressedPos
            self.update()

    def wheelEvent(self, event):
        if (event.angleDelta().y() > 0) and self.currentZoom < 3.0:
            fct = 1.10
        elif self.currentZoom > 1.0:
            fct = 1 / 1.10
        else:
            fct = 1.0
        self.currentZoom = self.currentZoom * fct
        self.update()

    def transform(self) -> QTransform:
        if self.photo is not None:
            srcrc = self.photo.rect()
            destrc = self.rect()
            trfshift = _translate(srcrc, destrc, self.offset)
            trfscale = _scale(srcrc, destrc, self.currentZoom)
            return trfscale * trfshift
        else:
            return QTransform()

    def _onMeasureDone(self):
        overlay = self.mesOverlay
        mngr = QtGui.qApp.sessionManager
        dlg = uic.loadUi('./ui/mesauredistdialog.ui')
        dlg.lineEdit.setValidator(QtGui.QIntValidator(0, 10000))
        res = dlg.exec_()
        if res == QDialog.Accepted and len(dlg.lineEdit.text()) > 0:
            overlay.lengthText = dlg.lineEdit.text() + 'mm'
            mngr.ppmm = overlay.lineLength() / float(dlg.lineEdit.text())
            if dlg.btnAcc.isChecked():
                mngr.sizeFlags = session.SizeFlags.ACCURATELY
            elif dlg.btnLessAcc.isChecked():
                mngr.sizeFlags = session.SizeFlags.LESS_ACCURATE
            elif dlg.btnInAcc.isChecked():
                mngr.sizeFlags = session.SizeFlags.INACCURATE
            else:
                mngr.sizeFlags = session.SizeFlags.UNKNOWN
        else:
            mngr.ppmm = None
            mngr.sizeFlags = session.SizeFlags.UNKNOWN
            overlay.reset()

        self.setMode(EditMode.IDLE)

    def _onFreeHandDone(self, mousePos):
        offs = 10
        h = self.btnContPlus.height()
        self.btnContMinus.move(mousePos.x() + offs, mousePos.y() + offs - h)
        self.btnContPlus.move(mousePos.x() + offs, mousePos.y() + offs)
        self.btnContPlus.show()
        self.btnContMinus.show()

    def _onAddCountClicked(self):
        sm = QtGui.qApp.sessionManager
        sm.addForeground(self.contOverlay.freeHandPath)
        self.contOverlay.freeHandPath.clear()
        self.btnContPlus.hide()
        self.btnContMinus.hide()
        self.update()

    def _onRemoveCountClicked(self):
        sm = QtGui.qApp.sessionManager
        sm.removeForeground(self.contOverlay.freeHandPath)
        self.contOverlay.freeHandPath.clear()
        self.btnContPlus.hide()
        self.btnContMinus.hide()
        self.update()

    def _onFindContClicked(self):
        self.setMode(EditMode.FG)
        sm = QtGui.qApp.sessionManager
        sm.findForeground(self.roiOverlay.imageRoi)

    def getOverlay(self, mode):
        o = {
            EditMode.IDLE: None,
            EditMode.MEASURE: self.mesOverlay,
            EditMode.ROI: self.roiOverlay,
            EditMode.FG: self.contOverlay
        }
        return o[mode]