diff -r eaf2cf171f3a -r 5cf645f6daab eric6/Helpviewer/Bookmarks/BookmarksManager.py --- a/eric6/Helpviewer/Bookmarks/BookmarksManager.py Sat Sep 07 14:45:27 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,642 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2009 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Module implementing the bookmarks manager. -""" - -from __future__ import unicode_literals - -import os - -from PyQt5.QtCore import pyqtSignal, Qt, QT_TRANSLATE_NOOP, QObject, QFile, \ - QIODevice, QXmlStreamReader, QDate, QDateTime, QFileInfo, QUrl, \ - QCoreApplication -from PyQt5.QtWidgets import QUndoStack, QUndoCommand, QDialog - -from E5Gui import E5MessageBox, E5FileDialog - -from .BookmarkNode import BookmarkNode - -from Utilities.AutoSaver import AutoSaver -import Utilities -import Preferences - -BOOKMARKBAR = QT_TRANSLATE_NOOP("BookmarksManager", "Bookmarks Bar") -BOOKMARKMENU = QT_TRANSLATE_NOOP("BookmarksManager", "Bookmarks Menu") - -StartRoot = 0 -StartMenu = 1 -StartToolBar = 2 - - -class BookmarksManager(QObject): - """ - Class implementing the bookmarks manager. - - @signal entryAdded(BookmarkNode) emitted after a bookmark node has been - added - @signal entryRemoved(BookmarkNode, int, BookmarkNode) emitted after a - bookmark node has been removed - @signal entryChanged(BookmarkNode) emitted after a bookmark node has been - changed - @signal bookmarksSaved() emitted after the bookmarks were saved - @signal bookmarksReloaded() emitted after the bookmarks were reloaded - """ - entryAdded = pyqtSignal(BookmarkNode) - entryRemoved = pyqtSignal(BookmarkNode, int, BookmarkNode) - entryChanged = pyqtSignal(BookmarkNode) - bookmarksSaved = pyqtSignal() - bookmarksReloaded = pyqtSignal() - - def __init__(self, parent=None): - """ - Constructor - - @param parent reference to the parent object (QObject) - """ - super(BookmarksManager, self).__init__(parent) - - self.__saveTimer = AutoSaver(self, self.save) - self.entryAdded.connect(self.__saveTimer.changeOccurred) - self.entryRemoved.connect(self.__saveTimer.changeOccurred) - self.entryChanged.connect(self.__saveTimer.changeOccurred) - - self.__initialize() - - def __initialize(self): - """ - Private method to initialize some data. - """ - self.__loaded = False - self.__bookmarkRootNode = None - self.__toolbar = None - self.__menu = None - self.__bookmarksModel = None - self.__commands = QUndoStack() - - @classmethod - def getFileName(cls): - """ - Class method to get the file name of the bookmark file. - - @return name of the bookmark file (string) - """ - return os.path.join(Utilities.getConfigDir(), "browser", - "bookmarks.xbel") - - def close(self): - """ - Public method to close the bookmark manager. - """ - self.__saveTimer.saveIfNeccessary() - - def undoRedoStack(self): - """ - Public method to get a reference to the undo stack. - - @return reference to the undo stack (QUndoStack) - """ - return self.__commands - - def changeExpanded(self): - """ - Public method to handle a change of the expanded state. - """ - self.__saveTimer.changeOccurred() - - def reload(self): - """ - Public method used to initiate a reloading of the bookmarks. - """ - self.__initialize() - self.load() - self.bookmarksReloaded.emit() - - def load(self): - """ - Public method to load the bookmarks. - - @exception RuntimeError raised to indicate an error loading the - bookmarks - """ - if self.__loaded: - return - - self.__loaded = True - - bookmarkFile = self.getFileName() - if not QFile.exists(bookmarkFile): - from . import DefaultBookmarks_rc # __IGNORE_WARNING__ - bookmarkFile = QFile(":/DefaultBookmarks.xbel") - bookmarkFile.open(QIODevice.ReadOnly) - - from .XbelReader import XbelReader - reader = XbelReader() - self.__bookmarkRootNode = reader.read(bookmarkFile) - if reader.error() != QXmlStreamReader.NoError: - E5MessageBox.warning( - None, - self.tr("Loading Bookmarks"), - self.tr( - """Error when loading bookmarks on line {0},""" - """ column {1}:\n {2}""") - .format(reader.lineNumber(), - reader.columnNumber(), - reader.errorString())) - - others = [] - for index in range( - len(self.__bookmarkRootNode.children()) - 1, -1, -1): - node = self.__bookmarkRootNode.children()[index] - if node.type() == BookmarkNode.Folder: - if (node.title == self.tr("Toolbar Bookmarks") or - node.title == BOOKMARKBAR) and \ - self.__toolbar is None: - node.title = self.tr(BOOKMARKBAR) - self.__toolbar = node - - if (node.title == self.tr("Menu") or - node.title == BOOKMARKMENU) and \ - self.__menu is None: - node.title = self.tr(BOOKMARKMENU) - self.__menu = node - else: - others.append(node) - self.__bookmarkRootNode.remove(node) - - if len(self.__bookmarkRootNode.children()) > 0: - raise RuntimeError("Error loading bookmarks.") - - if self.__toolbar is None: - self.__toolbar = BookmarkNode(BookmarkNode.Folder, - self.__bookmarkRootNode) - self.__toolbar.title = self.tr(BOOKMARKBAR) - else: - self.__bookmarkRootNode.add(self.__toolbar) - - if self.__menu is None: - self.__menu = BookmarkNode(BookmarkNode.Folder, - self.__bookmarkRootNode) - self.__menu.title = self.tr(BOOKMARKMENU) - else: - self.__bookmarkRootNode.add(self.__menu) - - for node in others: - self.__menu.add(node) - - self.__convertFromOldBookmarks() - - def save(self): - """ - Public method to save the bookmarks. - """ - if not self.__loaded: - return - - from .XbelWriter import XbelWriter - writer = XbelWriter() - bookmarkFile = self.getFileName() - - # save root folder titles in English (i.e. not localized) - self.__menu.title = BOOKMARKMENU - self.__toolbar.title = BOOKMARKBAR - if not writer.write(bookmarkFile, self.__bookmarkRootNode): - E5MessageBox.warning( - None, - self.tr("Saving Bookmarks"), - self.tr("""Error saving bookmarks to <b>{0}</b>.""") - .format(bookmarkFile)) - - # restore localized titles - self.__menu.title = self.tr(BOOKMARKMENU) - self.__toolbar.title = self.tr(BOOKMARKBAR) - - self.bookmarksSaved.emit() - - def addBookmark(self, parent, node, row=-1): - """ - Public method to add a bookmark. - - @param parent reference to the node to add to (BookmarkNode) - @param node reference to the node to add (BookmarkNode) - @param row row number (integer) - """ - if not self.__loaded: - return - - self.setTimestamp(node, BookmarkNode.TsAdded, - QDateTime.currentDateTime()) - - command = InsertBookmarksCommand(self, parent, node, row) - self.__commands.push(command) - - def removeBookmark(self, node): - """ - Public method to remove a bookmark. - - @param node reference to the node to be removed (BookmarkNode) - """ - if not self.__loaded: - return - - parent = node.parent() - row = parent.children().index(node) - command = RemoveBookmarksCommand(self, parent, row) - self.__commands.push(command) - - def setTitle(self, node, newTitle): - """ - Public method to set the title of a bookmark. - - @param node reference to the node to be changed (BookmarkNode) - @param newTitle title to be set (string) - """ - if not self.__loaded: - return - - command = ChangeBookmarkCommand(self, node, newTitle, True) - self.__commands.push(command) - - def setUrl(self, node, newUrl): - """ - Public method to set the URL of a bookmark. - - @param node reference to the node to be changed (BookmarkNode) - @param newUrl URL to be set (string) - """ - if not self.__loaded: - return - - command = ChangeBookmarkCommand(self, node, newUrl, False) - self.__commands.push(command) - - def setNodeChanged(self, node): - """ - Public method to signal changes of bookmarks other than title, URL - or timestamp. - - @param node reference to the bookmark (BookmarkNode) - """ - self.__saveTimer.changeOccurred() - - def setTimestamp(self, node, timestampType, timestamp): - """ - Public method to set the URL of a bookmark. - - @param node reference to the node to be changed (BookmarkNode) - @param timestampType type of the timestamp to set - (BookmarkNode.TsAdded, BookmarkNode.TsModified, - BookmarkNode.TsVisited) - @param timestamp timestamp to set (QDateTime) - """ - if not self.__loaded: - return - - assert timestampType in [BookmarkNode.TsAdded, - BookmarkNode.TsModified, - BookmarkNode.TsVisited] - - if timestampType == BookmarkNode.TsAdded: - node.added = timestamp - elif timestampType == BookmarkNode.TsModified: - node.modified = timestamp - elif timestampType == BookmarkNode.TsVisited: - node.visited = timestamp - self.__saveTimer.changeOccurred() - - def bookmarks(self): - """ - Public method to get a reference to the root bookmark node. - - @return reference to the root bookmark node (BookmarkNode) - """ - if not self.__loaded: - self.load() - - return self.__bookmarkRootNode - - def menu(self): - """ - Public method to get a reference to the bookmarks menu node. - - @return reference to the bookmarks menu node (BookmarkNode) - """ - if not self.__loaded: - self.load() - - return self.__menu - - def toolbar(self): - """ - Public method to get a reference to the bookmarks toolbar node. - - @return reference to the bookmarks toolbar node (BookmarkNode) - """ - if not self.__loaded: - self.load() - - return self.__toolbar - - def bookmarksModel(self): - """ - Public method to get a reference to the bookmarks model. - - @return reference to the bookmarks model (BookmarksModel) - """ - if self.__bookmarksModel is None: - from .BookmarksModel import BookmarksModel - self.__bookmarksModel = BookmarksModel(self, self) - return self.__bookmarksModel - - def importBookmarks(self): - """ - Public method to import bookmarks. - """ - from .BookmarksImportDialog import BookmarksImportDialog - dlg = BookmarksImportDialog() - if dlg.exec_() == QDialog.Accepted: - importRootNode = dlg.getImportedBookmarks() - if importRootNode is not None: - self.addBookmark(self.menu(), importRootNode) - - def exportBookmarks(self): - """ - Public method to export the bookmarks. - """ - fileName, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( - None, - self.tr("Export Bookmarks"), - "eric6_bookmarks.xbel", - self.tr("XBEL bookmarks (*.xbel);;" - "XBEL bookmarks (*.xml);;" - "HTML Bookmarks (*.html)")) - if not fileName: - return - - ext = QFileInfo(fileName).suffix() - if not ext: - ex = selectedFilter.split("(*")[1].split(")")[0] - if ex: - fileName += ex - - ext = QFileInfo(fileName).suffix() - if ext == "html": - from .NsHtmlWriter import NsHtmlWriter - writer = NsHtmlWriter() - else: - from .XbelWriter import XbelWriter - writer = XbelWriter() - if not writer.write(fileName, self.__bookmarkRootNode): - E5MessageBox.critical( - None, - self.tr("Exporting Bookmarks"), - self.tr("""Error exporting bookmarks to <b>{0}</b>.""") - .format(fileName)) - - def __convertFromOldBookmarks(self): - """ - Private method to convert the old bookmarks into the new ones. - """ - bmNames = Preferences.Prefs.settings.value('Bookmarks/Names') - bmFiles = Preferences.Prefs.settings.value('Bookmarks/Files') - - if bmNames is not None and bmFiles is not None: - if len(bmNames) == len(bmFiles): - convertedRootNode = BookmarkNode(BookmarkNode.Folder) - convertedRootNode.title = self.tr("Converted {0}")\ - .format(QDate.currentDate().toString( - Qt.SystemLocaleShortDate)) - for i in range(len(bmNames)): - node = BookmarkNode(BookmarkNode.Bookmark, - convertedRootNode) - node.title = bmNames[i] - url = QUrl(bmFiles[i]) - if not url.scheme(): - url.setScheme("file") - node.url = url.toString() - self.addBookmark(self.menu(), convertedRootNode) - - Preferences.Prefs.settings.remove('Bookmarks') - - def iconChanged(self, url): - """ - Public slot to update the icon image for an URL. - - @param url URL of the icon to update (QUrl or string) - """ - if isinstance(url, QUrl): - url = url.toString() - nodes = self.bookmarksForUrl(url) - for node in nodes: - self.bookmarksModel().entryChanged(node) - - def bookmarkForUrl(self, url, start=StartRoot): - """ - Public method to get a bookmark node for a given URL. - - @param url URL of the bookmark to search for (QUrl or string) - @keyparam start indicator for the start of the search - (StartRoot, StartMenu, StartToolBar) - @return bookmark node for the given url (BookmarkNode) - """ - if start == StartMenu: - startNode = self.__menu - elif start == StartToolBar: - startNode = self.__toolbar - else: - startNode = self.__bookmarkRootNode - if startNode is None: - return None - - if isinstance(url, QUrl): - url = url.toString() - - return self.__searchBookmark(url, startNode) - - def __searchBookmark(self, url, startNode): - """ - Private method get a bookmark node for a given URL. - - @param url URL of the bookmark to search for (string) - @param startNode reference to the node to start searching - (BookmarkNode) - @return bookmark node for the given url (BookmarkNode) - """ - bm = None - for node in startNode.children(): - if node.type() == BookmarkNode.Folder: - bm = self.__searchBookmark(url, node) - elif node.type() == BookmarkNode.Bookmark: - if node.url == url: - bm = node - if bm is not None: - return bm - return None - - def bookmarksForUrl(self, url, start=StartRoot): - """ - Public method to get a list of bookmark nodes for a given URL. - - @param url URL of the bookmarks to search for (QUrl or string) - @keyparam start indicator for the start of the search - (StartRoot, StartMenu, StartToolBar) - @return list of bookmark nodes for the given url (list of BookmarkNode) - """ - if start == StartMenu: - startNode = self.__menu - elif start == StartToolBar: - startNode = self.__toolbar - else: - startNode = self.__bookmarkRootNode - if startNode is None: - return None - - if isinstance(url, QUrl): - url = url.toString() - - return self.__searchBookmarks(url, startNode) - - def __searchBookmarks(self, url, startNode): - """ - Private method get a list of bookmark nodes for a given URL. - - @param url URL of the bookmarks to search for (string) - @param startNode reference to the node to start searching - (BookmarkNode) - @return list of bookmark nodes for the given url (list of BookmarkNode) - """ - bm = [] - for node in startNode.children(): - if node.type() == BookmarkNode.Folder: - bm.extend(self.__searchBookmarks(url, node)) - elif node.type() == BookmarkNode.Bookmark: - if node.url == url: - bm.append(node) - return bm - - -class RemoveBookmarksCommand(QUndoCommand): - """ - Class implementing the Remove undo command. - """ - def __init__(self, bookmarksManager, parent, row): - """ - Constructor - - @param bookmarksManager reference to the bookmarks manager - (BookmarksManager) - @param parent reference to the parent node (BookmarkNode) - @param row row number of bookmark (integer) - """ - super(RemoveBookmarksCommand, self).__init__( - QCoreApplication.translate("BookmarksManager", "Remove Bookmark")) - - self._row = row - self._bookmarksManager = bookmarksManager - try: - self._node = parent.children()[row] - except IndexError: - self._node = BookmarkNode() - self._parent = parent - - def undo(self): - """ - Public slot to perform the undo action. - """ - self._parent.add(self._node, self._row) - self._bookmarksManager.entryAdded.emit(self._node) - - def redo(self): - """ - Public slot to perform the redo action. - """ - self._parent.remove(self._node) - self._bookmarksManager.entryRemoved.emit( - self._parent, self._row, self._node) - - -class InsertBookmarksCommand(RemoveBookmarksCommand): - """ - Class implementing the Insert undo command. - """ - def __init__(self, bookmarksManager, parent, node, row): - """ - Constructor - - @param bookmarksManager reference to the bookmarks manager - (BookmarksManager) - @param parent reference to the parent node (BookmarkNode) - @param node reference to the node to be inserted (BookmarkNode) - @param row row number of bookmark (integer) - """ - RemoveBookmarksCommand.__init__(self, bookmarksManager, parent, row) - self.setText(QCoreApplication.translate( - "BookmarksManager", "Insert Bookmark")) - self._node = node - - def undo(self): - """ - Public slot to perform the undo action. - """ - RemoveBookmarksCommand.redo(self) - - def redo(self): - """ - Public slot to perform the redo action. - """ - RemoveBookmarksCommand.undo(self) - - -class ChangeBookmarkCommand(QUndoCommand): - """ - Class implementing the Insert undo command. - """ - def __init__(self, bookmarksManager, node, newValue, title): - """ - Constructor - - @param bookmarksManager reference to the bookmarks manager - (BookmarksManager) - @param node reference to the node to be changed (BookmarkNode) - @param newValue new value to be set (string) - @param title flag indicating a change of the title (True) or - the URL (False) (boolean) - """ - super(ChangeBookmarkCommand, self).__init__() - - self._bookmarksManager = bookmarksManager - self._title = title - self._newValue = newValue - self._node = node - - if self._title: - self._oldValue = self._node.title - self.setText(QCoreApplication.translate( - "BookmarksManager", "Name Change")) - else: - self._oldValue = self._node.url - self.setText(QCoreApplication.translate( - "BookmarksManager", "Address Change")) - - def undo(self): - """ - Public slot to perform the undo action. - """ - if self._title: - self._node.title = self._oldValue - else: - self._node.url = self._oldValue - self._bookmarksManager.entryChanged.emit(self._node) - - def redo(self): - """ - Public slot to perform the redo action. - """ - if self._title: - self._node.title = self._newValue - else: - self._node.url = self._newValue - self._bookmarksManager.entryChanged.emit(self._node)