Mon, 26 Dec 2011 19:31:22 +0100
Updated copyright for 2012.
# -*- coding: utf-8 -*- # Copyright (c) 2009 - 2012 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the history menu. """ import sys from PyQt4.QtCore import pyqtSignal, Qt, QMimeData, QUrl, QModelIndex from PyQt4.QtGui import QAbstractProxyModel from E5Gui.E5ModelMenu import E5ModelMenu from E5Gui import E5MessageBox import Helpviewer.HelpWindow from .HistoryModel import HistoryModel from .HistoryDialog import HistoryDialog import UI.PixmapCache class HistoryMenuModel(QAbstractProxyModel): """ Class implementing a model for the history menu. It maps the first bunch of items of the source model to the root. """ MOVEDROWS = 15 def __init__(self, sourceModel, parent=None): """ Constructor @param sourceModel reference to the source model (QAbstractItemModel) @param parent reference to the parent object (QObject) """ super().__init__(parent) self.__treeModel = sourceModel self.setSourceModel(sourceModel) def bumpedRows(self): """ Public method to determine the number of rows moved to the root. @return number of rows moved to the root (integer) """ first = self.__treeModel.index(0, 0) if not first.isValid(): return 0 return min(self.__treeModel.rowCount(first), self.MOVEDROWS) def columnCount(self, parent=QModelIndex()): """ Public method to get the number of columns. @param parent index of parent (QModelIndex) @return number of columns (integer) """ return self.__treeModel.columnCount(self.mapToSource(parent)) def rowCount(self, parent=QModelIndex()): """ Public method to determine the number of rows. @param parent index of parent (QModelIndex) @return number of rows (integer) """ if parent.column() > 0: return 0 if not parent.isValid(): folders = self.sourceModel().rowCount() bumpedItems = self.bumpedRows() if bumpedItems <= self.MOVEDROWS and \ bumpedItems == self.sourceModel().rowCount(self.sourceModel().index(0, 0)): folders -= 1 return bumpedItems + folders if parent.internalId() == sys.maxsize: if parent.row() < self.bumpedRows(): return 0 idx = self.mapToSource(parent) defaultCount = self.sourceModel().rowCount(idx) if idx == self.sourceModel().index(0, 0): return defaultCount - self.bumpedRows() return defaultCount def mapFromSource(self, sourceIndex): """ Public method to map an index to the proxy model index. @param sourceIndex reference to a source model index (QModelIndex) @return proxy model index (QModelIndex) """ assert False sourceRow = self.__treeModel.mapToSource(sourceIndex).row() return self.createIndex(sourceIndex.row(), sourceIndex.column(), sourceRow) def mapToSource(self, proxyIndex): """ Public method to map an index to the source model index. @param proxyIndex reference to a proxy model index (QModelIndex) @return source model index (QModelIndex) """ if not proxyIndex.isValid(): return QModelIndex() if proxyIndex.internalId() == sys.maxsize: bumpedItems = self.bumpedRows() if proxyIndex.row() < bumpedItems: return self.__treeModel.index(proxyIndex.row(), proxyIndex.column(), self.__treeModel.index(0, 0)) if bumpedItems <= self.MOVEDROWS and \ bumpedItems == self.sourceModel().rowCount(self.__treeModel.index(0, 0)): bumpedItems -= 1 return self.__treeModel.index(proxyIndex.row() - bumpedItems, proxyIndex.column()) historyIndex = self.__treeModel.sourceModel()\ .index(proxyIndex.internalId(), proxyIndex.column()) treeIndex = self.__treeModel.mapFromSource(historyIndex) return treeIndex def index(self, row, column, parent=QModelIndex()): """ Public method to create an index. @param row row number for the index (integer) @param column column number for the index (integer) @param parent index of the parent item (QModelIndex) @return requested index (QModelIndex) """ if row < 0 or \ column < 0 or \ column >= self.columnCount(parent) or \ parent.column() > 0: return QModelIndex() if not parent.isValid(): return self.createIndex(row, column, sys.maxsize) treeIndexParent = self.mapToSource(parent) bumpedItems = 0 if treeIndexParent == self.sourceModel().index(0, 0): bumpedItems = self.bumpedRows() treeIndex = self.__treeModel.index(row + bumpedItems, column, treeIndexParent) historyIndex = self.__treeModel.mapToSource(treeIndex) historyRow = historyIndex.row() if historyRow == -1: historyRow = treeIndex.row() return self.createIndex(row, column, historyRow) def parent(self, index): """ Public method to get the parent index. @param index index of item to get parent (QModelIndex) @return index of parent (QModelIndex) """ offset = index.internalId() if offset == sys.maxsize or not index.isValid(): return QModelIndex() historyIndex = self.__treeModel.sourceModel().index(index.internalId(), 0) treeIndex = self.__treeModel.mapFromSource(historyIndex) treeIndexParent = treeIndex.parent() sourceRow = self.sourceModel().mapToSource(treeIndexParent).row() bumpedItems = self.bumpedRows() if bumpedItems <= self.MOVEDROWS and \ bumpedItems == self.sourceModel().rowCount(self.sourceModel().index(0, 0)): bumpedItems -= 1 return self.createIndex(bumpedItems + treeIndexParent.row(), treeIndexParent.column(), sourceRow) def mimeData(self, indexes): """ Public method to return the mime data. @param indexes list of indexes (QModelIndexList) @return mime data (QMimeData) """ urls = [] for index in indexes: url = index.data(HistoryModel.UrlRole) urls.append(url) mdata = QMimeData() mdata.setUrls(urls) return mdata class HistoryMenu(E5ModelMenu): """ Class implementing the history menu. @signal openUrl(QUrl, str) emitted to open a URL in the current tab @signal newUrl(QUrl, str) emitted to open a URL in a new tab """ openUrl = pyqtSignal(QUrl, str) newUrl = pyqtSignal(QUrl, str) def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget (QWidget) """ E5ModelMenu.__init__(self, parent) self.__historyManager = None self.__historyMenuModel = None self.__initialActions = [] self.setMaxRows(7) self.activated.connect(self.__activated) self.setStatusBarTextRole(HistoryModel.UrlStringRole) def __activated(self, idx): """ Private slot handling the activated signal. @param idx index of the activated item (QModelIndex) """ if self._keyboardModifiers & Qt.ControlModifier: self.newUrl.emit( idx.data(HistoryModel.UrlRole), idx.data(HistoryModel.TitleRole)) else: self.openUrl.emit( idx.data(HistoryModel.UrlRole), idx.data(HistoryModel.TitleRole)) def prePopulated(self): """ Public method to add any actions before the tree. @return flag indicating if any actions were added (boolean) """ if self.__historyManager is None: self.__historyManager = Helpviewer.HelpWindow.HelpWindow.historyManager() self.__historyMenuModel = \ HistoryMenuModel(self.__historyManager.historyTreeModel(), self) self.setModel(self.__historyMenuModel) # initial actions for act in self.__initialActions: self.addAction(act) if len(self.__initialActions) != 0: self.addSeparator() self.setFirstSeparator(self.__historyMenuModel.bumpedRows()) return False def postPopulated(self): """ Public method to add any actions after the tree. """ if len(self.__historyManager.history()) > 0: self.addSeparator() act = self.addAction(UI.PixmapCache.getIcon("history.png"), self.trUtf8("Show All History...")) act.triggered[()].connect(self.__showHistoryDialog) act = self.addAction(UI.PixmapCache.getIcon("historyClear.png"), self.trUtf8("Clear History...")) act.triggered[()].connect(self.__clearHistoryDialog) def setInitialActions(self, actions): """ Public method to set the list of actions that should appear first in the menu. @param actions list of initial actions (list of QAction) """ self.__initialActions = actions[:] for act in self.__initialActions: self.addAction(act) def __showHistoryDialog(self): """ Private slot to show the history dialog. """ dlg = HistoryDialog(self) dlg.setAttribute(Qt.WA_DeleteOnClose) dlg.newUrl.connect(self.newUrl) dlg.openUrl.connect(self.openUrl) dlg.show() def __clearHistoryDialog(self): """ Private slot to clear the history. """ if self.__historyManager is not None and \ E5MessageBox.yesNo(self, self.trUtf8("Clear History"), self.trUtf8("""Do you want to clear the history?""")): self.__historyManager.clear()