Thu, 14 Oct 2021 20:15:58 +0200
Continued implementing the embedded help viewer widget. Added the help index and help search widgets.
# -*- coding: utf-8 -*- # Copyright (c) 2021 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a widget showing the list of open pages. """ from PyQt6.QtCore import pyqtSlot, pyqtSignal, Qt, QPoint from PyQt6.QtGui import QGuiApplication, QClipboard from PyQt6.QtWidgets import ( QWidget, QLabel, QListWidget, QVBoxLayout, QAbstractItemView, QMenu ) import UI.PixmapCache class OpenPagesWidget(QWidget): """ Class implementing a widget showing the list of open pages. """ currentChanged = pyqtSignal(int) def __init__(self, stack, parent=None): """ Constructor @param stack reference to the stack widget containing the open help pages @type QStackedWidget @param parent reference to the parent widget (defaults to None) @type QWidget (optional) """ super().__init__(parent) self.setObjectName("OpenPagesWidget") self.__helpViewer = parent self.__layout = QVBoxLayout() self.__layout.setContentsMargins(0, 0, 0, 0) self.__title = QLabel(self.tr("Open Pages"), self) self.__layout.addWidget(self.__title) self.__openPagesList = QListWidget(self) self.__openPagesList.setAlternatingRowColors(True) self.__openPagesList.setSelectionMode( QAbstractItemView.SelectionMode.SingleSelection) self.__openPagesList.setContextMenuPolicy( Qt.ContextMenuPolicy.CustomContextMenu) self.__openPagesList.currentRowChanged.connect( self.__currentRowChanged) self.__openPagesList.customContextMenuRequested.connect( self.__showContextMenu) self.__layout.addWidget(self.__openPagesList) self.setLayout(self.__layout) self.__stack = stack self.__stack.currentChanged.connect(self.__currentPageChanged) self.__initContextMenu() self.__defaultFont = self.__openPagesList.font() self.__boldFont = self.__openPagesList.font() self.__boldFont.setBold(True) def __initContextMenu(self): """ Private method to initialize the context menu. """ self.__menu = QMenu(self) self.__menu.addAction( UI.PixmapCache.getIcon("tabClose"), self.tr('Close'), self.__contextMenuClose) self.closeOthersMenuAct = self.__menu.addAction( UI.PixmapCache.getIcon("tabCloseOther"), self.tr("Close Others"), self.__contextMenuCloseOthers) self.__menu.addAction( self.tr('Close All'), self.__contextMenuCloseAll) self.__menu.addSeparator() self.__copyUrlAct = self.__menu.addAction( self.tr("Copy URL to Clipboard"), self.__contextMenuCopyUrlToClipboard) @pyqtSlot(QPoint) def __showContextMenu(self, point): """ Private slot to handle the customContextMenuRequested signal of the viewlist. @param point position to open the menu at @type QPoint """ itm = self.__openPagesList.itemAt(point) self.__copyUrlAct.setEnabled(bool(itm) and itm.text() != "about:blank") self.__menu.popup(self.__openPagesList.mapToGlobal(point)) @pyqtSlot(int) def __currentPageChanged(self, index): """ Private slot to handle a change of the shown page. @param index index of the current page @type int """ for row in range(self.__openPagesList.count()): itm = self.__openPagesList.item(row) itm.setFont( self.__boldFont if row == index else self.__defaultFont ) @pyqtSlot(int) def __currentRowChanged(self, row): """ Private slot handling a change of the current row. @param row current row @type int """ self.__stack.setCurrentIndex(row) self.currentChanged.emit(row) def addPage(self, viewer, background=False): """ Public method to add a viewer page to our list. @param viewer reference to the viewer object @type HelpViewerImpl @param background flag indicating to not change the current page (defaults to False) @type bool (optional) """ self.__openPagesList.addItem(viewer.title()) viewer.titleChanged.connect( lambda: self.__viewerTitleChanged(viewer)) if not background: self.__openPagesList.setCurrentRow( self.__openPagesList.count() - 1) if self.__openPagesList.count() == 1: self.__currentPageChanged(0) def insertPage(self, index, viewer, background=False): """ Public method to insert a viewer page into our list. @param index index to insert at @type int @param viewer reference to the viewer object @type HelpViewerImpl @param background flag indicating to not change the current page (defaults to False) @type bool (optional) """ currentRow = self.__openPagesList.currentRow() self.__openPagesList.insertItem(index, viewer.title()) viewer.titleChanged.connect( lambda: self.__viewerTitleChanged(viewer)) if not background: self.__openPagesList.setCurrentRow(index) else: self.__openPagesList.setCurrentRow(currentRow) def __viewerTitleChanged(self, viewer): """ Private method to handle the change of a viewer title. @param viewer reference to the viewer that change title @type HelpViewerImpl """ index = self.__stack.indexOf(viewer) itm = self.__openPagesList.item(index) itm.setText(viewer.title()) self.currentChanged.emit(index) ####################################################################### ## Context menu action methods ####################################################################### @pyqtSlot() def __contextMenuClose(self): """ Private slot to close a page. """ row = self.__openPagesList.currentRow() self.__removeViewer(row) if self.__openPagesList.count() == 0: self.__helpViewer.addPage() @pyqtSlot() def __contextMenuCloseOthers(self): """ Private slot to close all other pages. """ currentRow = self.__openPagesList.currentRow() for row in range(self.__openPagesList.count() - 1, -1, -1): if row != currentRow: self.__removeViewer(row) @pyqtSlot() def __contextMenuCloseAll(self): """ Private slot to close all pages. """ while self.__openPagesList.count() != 0: self.__removeViewer(0) self.__helpViewer.addPage() @pyqtSlot() def __contextMenuCopyUrlToClipboard(self): """ Private slot to copy the URL to the clipboard. """ row = self.__openPagesList.currentRow() viewer = self.__stack.widget(row) url = viewer.url() if url.isValid(): urlStr = url.toString() # copy the URL to both clipboard areas QGuiApplication.clipboard().setText( urlStr, QClipboard.Mode.Clipboard) QGuiApplication.clipboard().setText( urlStr, QClipboard.Mode.Selection) def __removeViewer(self, row): """ Private method to remove a viewer page. @param row row associated with the viewer @type int """ viewer = self.__stack.widget(row) self.__stack.removeWidget(viewer) viewer.deleteLater() itm = self.__openPagesList.takeItem(row) del itm