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 != "")
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 != "")
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 )
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()
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']))
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)
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')
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()
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]
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()
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()
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()
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()
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)
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()
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
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')
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()
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()
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]
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)
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()
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()
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()
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()
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
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()
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()
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)
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]