diff -r e9e7eca7efee -r bf71ee032bb4 src/eric7/WebBrowser/Bookmarks/BookmarksModel.py --- a/src/eric7/WebBrowser/Bookmarks/BookmarksModel.py Wed Jul 13 11:16:20 2022 +0200 +++ b/src/eric7/WebBrowser/Bookmarks/BookmarksModel.py Wed Jul 13 14:55:47 2022 +0200 @@ -10,8 +10,15 @@ import contextlib from PyQt6.QtCore import ( - Qt, QAbstractItemModel, QModelIndex, QUrl, QByteArray, QDataStream, - QIODevice, QBuffer, QMimeData + Qt, + QAbstractItemModel, + QModelIndex, + QUrl, + QByteArray, + QDataStream, + QIODevice, + QBuffer, + QMimeData, ) import UI.PixmapCache @@ -21,48 +28,49 @@ """ Class implementing the bookmark model. """ + TypeRole = Qt.ItemDataRole.UserRole + 1 UrlRole = Qt.ItemDataRole.UserRole + 2 UrlStringRole = Qt.ItemDataRole.UserRole + 3 VisitCountRole = Qt.ItemDataRole.UserRole + 4 SeparatorRole = Qt.ItemDataRole.UserRole + 5 - + MIMETYPE = "application/bookmarks.xbel" - + def __init__(self, manager, parent=None): """ Constructor - + @param manager reference to the bookmark manager object (BookmarksManager) @param parent reference to the parent object (QObject) """ super().__init__(parent) - + self.__endMacro = False self.__bookmarksManager = manager - + manager.entryAdded.connect(self.entryAdded) manager.entryRemoved.connect(self.entryRemoved) manager.entryChanged.connect(self.entryChanged) - + self.__headers = [ self.tr("Title"), self.tr("Address"), ] - + def bookmarksManager(self): """ Public method to get a reference to the bookmarks manager. - + @return reference to the bookmarks manager object (BookmarksManager) """ return self.__bookmarksManager - + def nodeIndex(self, node): """ Public method to get a model index. - + @param node reference to the node to get the index for (BookmarkNode) @return model index (QModelIndex) """ @@ -70,16 +78,16 @@ if parent is None: return QModelIndex() return self.createIndex(parent.children().index(node), 0, node) - + def entryAdded(self, node): """ Public slot to add a bookmark node. - + @param node reference to the bookmark node to add (BookmarkNode) """ if node is None or node.parent() is None: return - + parent = node.parent() row = parent.children().index(node) # node was already added so remove before beginInsertRows is called @@ -87,11 +95,11 @@ self.beginInsertRows(self.nodeIndex(parent), row, row) parent.add(node, row) self.endInsertRows() - + def entryRemoved(self, parent, row, node): """ Public slot to remove a bookmark node. - + @param parent reference to the parent bookmark node (BookmarkNode) @param row row number of the node (integer) @param node reference to the bookmark node to remove (BookmarkNode) @@ -101,20 +109,20 @@ self.beginRemoveRows(self.nodeIndex(parent), row, row) parent.remove(node) self.endRemoveRows() - + def entryChanged(self, node): """ Public method to change a node. - + @param node reference to the bookmark node to change (BookmarkNode) """ idx = self.nodeIndex(node) self.dataChanged.emit(idx, idx) - + def removeRows(self, row, count, parent=None): """ Public method to remove bookmarks from the model. - + @param row row of the first bookmark to remove (integer) @param count number of bookmarks to remove (integer) @param parent index of the parent bookmark node (QModelIndex) @@ -122,135 +130,133 @@ """ if parent is None: parent = QModelIndex() - + if row < 0 or count <= 0 or row + count > self.rowCount(parent): return False - + bookmarkNode = self.node(parent) - children = bookmarkNode.children()[row:(row + count)] + children = bookmarkNode.children()[row : (row + count)] for node in children: if node in ( self.__bookmarksManager.menu(), - self.__bookmarksManager.toolbar() + self.__bookmarksManager.toolbar(), ): continue self.__bookmarksManager.removeBookmark(node) - + if self.__endMacro: self.__bookmarksManager.undoRedoStack().endMacro() self.__endMacro = False - + return True - - def headerData(self, section, orientation, - role=Qt.ItemDataRole.DisplayRole): + + def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole): """ Public method to get the header data. - + @param section section number (integer) @param orientation header orientation (Qt.Orientation) @param role data role (Qt.ItemDataRole) @return header data """ if ( - orientation == Qt.Orientation.Horizontal and - role == Qt.ItemDataRole.DisplayRole + orientation == Qt.Orientation.Horizontal + and role == Qt.ItemDataRole.DisplayRole ): with contextlib.suppress(IndexError): return self.__headers[section] return QAbstractItemModel.headerData(self, section, orientation, role) - + def data(self, index, role=Qt.ItemDataRole.DisplayRole): """ Public method to get data from the model. - + @param index index of bookmark to get data for (QModelIndex) @param role data role (integer) @return bookmark data """ if not index.isValid() or index.model() != self: return None - + from .BookmarkNode import BookmarkNode - + bookmarkNode = self.node(index) if role in [Qt.ItemDataRole.EditRole, Qt.ItemDataRole.DisplayRole]: if bookmarkNode.type() == BookmarkNode.Separator: if index.column() == 0: - return 50 * '\xB7' + return 50 * "\xB7" elif index.column() == 1: return "" - + if index.column() == 0: return bookmarkNode.title elif index.column() == 1: return bookmarkNode.url - + elif role == BookmarksModel.UrlRole: return QUrl(bookmarkNode.url) - + elif role == BookmarksModel.UrlStringRole: return bookmarkNode.url - + elif role == BookmarksModel.VisitCountRole: return bookmarkNode.visitCount - + elif role == BookmarksModel.TypeRole: return bookmarkNode.type() - + elif role == BookmarksModel.SeparatorRole: return bookmarkNode.type() == BookmarkNode.Separator - - elif ( - role == Qt.ItemDataRole.DecorationRole and - index.column() == 0 - ): + + elif role == Qt.ItemDataRole.DecorationRole and index.column() == 0: if bookmarkNode.type() == BookmarkNode.Folder: return UI.PixmapCache.getIcon("dirOpen") import WebBrowser.WebBrowserWindow + return WebBrowser.WebBrowserWindow.WebBrowserWindow.icon( - QUrl(bookmarkNode.url)) - + QUrl(bookmarkNode.url) + ) + return None - + def columnCount(self, parent=None): """ Public method to get the number of columns. - + @param parent index of parent (QModelIndex) @return number of columns (integer) """ if parent is None: parent = QModelIndex() - + if parent.column() > 0: return 0 else: return len(self.__headers) - + def rowCount(self, parent=None): """ Public method to determine the number of rows. - + @param parent index of parent (QModelIndex) @return number of rows (integer) """ if parent is None: parent = QModelIndex() - + if parent.column() > 0: return 0 - + if not parent.isValid(): return len(self.__bookmarksManager.bookmarks().children()) - + itm = parent.internalPointer() return len(itm.children()) - + def index(self, row, column, parent=None): """ Public method to get a model index for a node cell. - + @param row row number (integer) @param column column number (integer) @param parent index of the parent (QModelIndex) @@ -258,129 +264,124 @@ """ if parent is None: parent = QModelIndex() - + if ( - row < 0 or - column < 0 or - row >= self.rowCount(parent) or - column >= self.columnCount(parent) + row < 0 + or column < 0 + or row >= self.rowCount(parent) + or column >= self.columnCount(parent) ): return QModelIndex() - + parentNode = self.node(parent) return self.createIndex(row, column, parentNode.children()[row]) - + def parent(self, index=None): """ Public method to get the index of the parent node. - + @param index index of the child node (QModelIndex) @return index of the parent node (QModelIndex) """ if index is None: index = QModelIndex() - + if not index.isValid(): return QModelIndex() - + itemNode = self.node(index) parentNode = itemNode.parent() if itemNode else None - - if ( - parentNode is None or - parentNode == self.__bookmarksManager.bookmarks() - ): + + if parentNode is None or parentNode == self.__bookmarksManager.bookmarks(): return QModelIndex() - + # get the parent's row grandParentNode = parentNode.parent() parentRow = grandParentNode.children().index(parentNode) return self.createIndex(parentRow, 0, parentNode) - + def hasChildren(self, parent=None): """ Public method to check, if a parent node has some children. - + @param parent index of the parent node (QModelIndex) @return flag indicating the presence of children (boolean) """ if parent is None: parent = QModelIndex() - + if not parent.isValid(): return True - + from .BookmarkNode import BookmarkNode + parentNode = self.node(parent) return parentNode.type() == BookmarkNode.Folder - + def flags(self, index): """ Public method to get flags for a node cell. - + @param index index of the node cell (QModelIndex) @return flags (Qt.ItemFlags) """ if not index.isValid(): return Qt.ItemFlag.NoItemFlags - + node = self.node(index) type_ = node.type() flags = Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled - + if self.hasChildren(index): flags |= Qt.ItemFlag.ItemIsDropEnabled - - if node in ( - self.__bookmarksManager.menu(), - self.__bookmarksManager.toolbar() - ): + + if node in (self.__bookmarksManager.menu(), self.__bookmarksManager.toolbar()): return flags - + flags |= Qt.ItemFlag.ItemIsDragEnabled - + from .BookmarkNode import BookmarkNode - if ( - (index.column() == 0 and type_ != BookmarkNode.Separator) or - (index.column() == 1 and type_ == BookmarkNode.Bookmark) + + if (index.column() == 0 and type_ != BookmarkNode.Separator) or ( + index.column() == 1 and type_ == BookmarkNode.Bookmark ): flags |= Qt.ItemFlag.ItemIsEditable - + return flags - + def supportedDropActions(self): """ Public method to report the supported drop actions. - + @return supported drop actions (Qt.DropAction) """ return Qt.DropAction.CopyAction | Qt.DropAction.MoveAction - + def mimeTypes(self): """ Public method to report the supported mime types. - + @return supported mime types (list of strings) """ return [self.MIMETYPE, "text/uri-list"] - + def mimeData(self, indexes): """ Public method to return the mime data. - + @param indexes list of indexes (QModelIndexList) @return mime data (QMimeData) """ from .XbelWriter import XbelWriter - + data = QByteArray() stream = QDataStream(data, QIODevice.OpenModeFlag.WriteOnly) urls = [] - + for index in indexes: if index.column() != 0 or not index.isValid(): continue - + encodedData = QByteArray() buffer = QBuffer(encodedData) buffer.open(QIODevice.OpenModeFlag.ReadWrite) @@ -389,16 +390,16 @@ writer.write(buffer, parentNode) stream << encodedData urls.append(index.data(self.UrlRole)) - + mdata = QMimeData() mdata.setData(self.MIMETYPE, data) mdata.setUrls(urls) return mdata - + def dropMimeData(self, data, action, row, column, parent): """ Public method to accept the mime data of a drop action. - + @param data reference to the mime data (QMimeData) @param action drop action requested (Qt.DropAction) @param row row number (integer) @@ -408,71 +409,69 @@ """ if action == Qt.DropAction.IgnoreAction: return True - + if column > 0: return False - + parentNode = self.node(parent) - + if not data.hasFormat(self.MIMETYPE): if not data.hasUrls(): return False - + from .BookmarkNode import BookmarkNode + node = BookmarkNode(BookmarkNode.Bookmark, parentNode) node.url = bytes(data.urls()[0].toEncoded()).decode() - + if data.hasText(): node.title = data.text() else: node.title = node.url - + self.__bookmarksManager.addBookmark(parentNode, node, row) return True - + ba = data.data(self.MIMETYPE) stream = QDataStream(ba, QIODevice.OpenModeFlag.ReadOnly) if stream.atEnd(): return False - + undoStack = self.__bookmarksManager.undoRedoStack() undoStack.beginMacro("Move Bookmarks") - + from .XbelReader import XbelReader + while not stream.atEnd(): encodedData = QByteArray() stream >> encodedData buffer = QBuffer(encodedData) buffer.open(QIODevice.OpenModeFlag.ReadOnly) - + reader = XbelReader() rootNode = reader.read(buffer) for bookmarkNode in rootNode.children(): rootNode.remove(bookmarkNode) row = max(0, row) - self.__bookmarksManager.addBookmark( - parentNode, bookmarkNode, row) + self.__bookmarksManager.addBookmark(parentNode, bookmarkNode, row) self.__endMacro = True - + return True - + def setData(self, index, value, role=Qt.ItemDataRole.EditRole): """ Public method to set the data of a node cell. - + @param index index of the node cell (QModelIndex) @param value value to be set @param role role of the data (integer) @return flag indicating success (boolean) """ - if ( - not index.isValid() or - (self.flags(index) & Qt.ItemFlag.ItemIsEditable) == 0 - ): + if not index.isValid() or (self.flags(index) & Qt.ItemFlag.ItemIsEditable) == 0: return False - + item = self.node(index) - + if role in (Qt.ItemDataRole.EditRole, Qt.ItemDataRole.DisplayRole): if index.column() == 0: self.__bookmarksManager.setTitle(item, value) @@ -480,25 +479,25 @@ self.__bookmarksManager.setUrl(item, value) else: return False - + elif role == BookmarksModel.UrlRole: self.__bookmarksManager.setUrl(item, value.toString()) - + elif role == BookmarksModel.UrlStringRole: self.__bookmarksManager.setUrl(item, value) - + elif role == BookmarksModel.VisitCountRole: self.__bookmarksManager.setVisitCount(item, value) - + else: return False - + return True - + def node(self, index): """ Public method to get a bookmark node given its index. - + @param index index of the node (QModelIndex) @return bookmark node (BookmarkNode) """