Thu, 11 Feb 2016 20:27:07 +0100
Continued porting the web browser.
- added the bookmarks stuff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/AddBookmarkDialog.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,248 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to add a bookmark or a bookmark folder. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QModelIndex, QSortFilterProxyModel +from PyQt5.QtWidgets import QDialog, QTreeView + +from .Ui_AddBookmarkDialog import Ui_AddBookmarkDialog + + +class AddBookmarkProxyModel(QSortFilterProxyModel): + """ + Class implementing a proxy model used by the AddBookmarkDialog dialog. + """ + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object (QObject) + """ + super(AddBookmarkProxyModel, self).__init__(parent) + + def columnCount(self, parent): + """ + Public method to return the number of columns. + + @param parent index of the parent (QModelIndex) + @return number of columns (integer) + """ + return min(1, QSortFilterProxyModel.columnCount(self, parent)) + + def filterAcceptsRow(self, sourceRow, sourceParent): + """ + Public method to determine, if the row is acceptable. + + @param sourceRow row number in the source model (integer) + @param sourceParent index of the source item (QModelIndex) + @return flag indicating acceptance (boolean) + """ + idx = self.sourceModel().index(sourceRow, 0, sourceParent) + return self.sourceModel().hasChildren(idx) + + def filterAcceptsColumn(self, sourceColumn, sourceParent): + """ + Public method to determine, if the column is acceptable. + + @param sourceColumn column number in the source model (integer) + @param sourceParent index of the source item (QModelIndex) + @return flag indicating acceptance (boolean) + """ + return sourceColumn == 0 + + def hasChildren(self, parent=QModelIndex()): + """ + 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) + """ + sindex = self.mapToSource(parent) + return self.sourceModel().hasChildren(sindex) + + +class AddBookmarkDialog(QDialog, Ui_AddBookmarkDialog): + """ + Class implementing a dialog to add a bookmark or a bookmark folder. + """ + def __init__(self, parent=None, bookmarksManager=None): + """ + Constructor + + @param parent reference to the parent widget (QWidget) + @param bookmarksManager reference to the bookmarks manager + object (BookmarksManager) + """ + super(AddBookmarkDialog, self).__init__(parent) + self.setupUi(self) + + self.__bookmarksManager = bookmarksManager + self.__addedNode = None + self.__addFolder = False + + if self.__bookmarksManager is None: + import WebBrowser.WebBrowserWindow + self.__bookmarksManager = \ + WebBrowser.WebBrowserWindow.WebBrowserWindow.bookmarksManager() + + self.__proxyModel = AddBookmarkProxyModel(self) + model = self.__bookmarksManager.bookmarksModel() + self.__proxyModel.setSourceModel(model) + + self.__treeView = QTreeView(self) + self.__treeView.setModel(self.__proxyModel) + self.__treeView.expandAll() + self.__treeView.header().setStretchLastSection(True) + self.__treeView.header().hide() + self.__treeView.setItemsExpandable(False) + self.__treeView.setRootIsDecorated(False) + self.__treeView.setIndentation(10) + self.__treeView.show() + + self.locationCombo.setModel(self.__proxyModel) + self.locationCombo.setView(self.__treeView) + + self.addressEdit.setInactiveText(self.tr("Url")) + self.nameEdit.setInactiveText(self.tr("Title")) + + self.resize(self.sizeHint()) + + def setUrl(self, url): + """ + Public slot to set the URL of the new bookmark. + + @param url URL of the bookmark (string) + """ + self.addressEdit.setText(url) + self.resize(self.sizeHint()) + + def url(self): + """ + Public method to get the URL of the bookmark. + + @return URL of the bookmark (string) + """ + return self.addressEdit.text() + + def setTitle(self, title): + """ + Public method to set the title of the new bookmark. + + @param title title of the bookmark (string) + """ + self.nameEdit.setText(title) + + def title(self): + """ + Public method to get the title of the bookmark. + + @return title of the bookmark (string) + """ + return self.nameEdit.text() + + def setDescription(self, description): + """ + Public method to set the description of the new bookmark. + + @param description description of the bookamrk (string) + """ + self.descriptionEdit.setPlainText(description) + + def description(self): + """ + Public method to get the description of the bookmark. + + @return description of the bookamrk (string) + """ + return self.descriptionEdit.toPlainText() + + def setCurrentIndex(self, idx): + """ + Public method to set the current index. + + @param idx current index to be set (QModelIndex) + """ + proxyIndex = self.__proxyModel.mapFromSource(idx) + self.__treeView.setCurrentIndex(proxyIndex) + self.locationCombo.setCurrentIndex(proxyIndex.row()) + + def currentIndex(self): + """ + Public method to get the current index. + + @return current index (QModelIndex) + """ + idx = self.locationCombo.view().currentIndex() + idx = self.__proxyModel.mapToSource(idx) + return idx + + def setFolder(self, folder): + """ + Public method to set the dialog to "Add Folder" mode. + + @param folder flag indicating "Add Folder" mode (boolean) + """ + self.__addFolder = folder + + if folder: + self.setWindowTitle(self.tr("Add Folder")) + self.addressEdit.setVisible(False) + else: + self.setWindowTitle(self.tr("Add Bookmark")) + self.addressEdit.setVisible(True) + + self.resize(self.sizeHint()) + + def isFolder(self): + """ + Public method to test, if the dialog is in "Add Folder" mode. + + @return flag indicating "Add Folder" mode (boolean) + """ + return self.__addFolder + + def addedNode(self): + """ + Public method to get a reference to the added bookmark node. + + @return reference to the added bookmark node (BookmarkNode) + """ + return self.__addedNode + + def accept(self): + """ + Public slot handling the acceptance of the dialog. + """ + if (not self.__addFolder and not self.addressEdit.text()) or \ + not self.nameEdit.text(): + super(AddBookmarkDialog, self).accept() + return + + from .BookmarkNode import BookmarkNode + + idx = self.currentIndex() + if not idx.isValid(): + idx = self.__bookmarksManager.bookmarksModel().index(0, 0) + parent = self.__bookmarksManager.bookmarksModel().node(idx) + + if self.__addFolder: + type_ = BookmarkNode.Folder + else: + type_ = BookmarkNode.Bookmark + bookmark = BookmarkNode(type_) + bookmark.title = self.nameEdit.text() + if not self.__addFolder: + bookmark.url = self.addressEdit.text() + bookmark.desc = self.descriptionEdit.toPlainText() + + self.__bookmarksManager.addBookmark(parent, bookmark) + self.__addedNode = bookmark + + super(AddBookmarkDialog, self).accept()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/AddBookmarkDialog.ui Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AddBookmarkDialog</class> + <widget class="QDialog" name="AddBookmarkDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>230</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>500</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>500</width> + <height>250</height> + </size> + </property> + <property name="windowTitle"> + <string>Add Bookmark</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="E5LineEdit" name="nameEdit"> + <property name="toolTip"> + <string>Enter the name</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Address:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="E5LineEdit" name="addressEdit"> + <property name="toolTip"> + <string>Enter the address</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Description:</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QPlainTextEdit" name="descriptionEdit"> + <property name="toolTip"> + <string>Enter a description</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Folder:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="locationCombo"/> + </item> + <item row="4" column="0" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>E5LineEdit</class> + <extends>QLineEdit</extends> + <header>E5Gui/E5LineEdit.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>nameEdit</tabstop> + <tabstop>addressEdit</tabstop> + <tabstop>descriptionEdit</tabstop> + <tabstop>locationCombo</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>AddBookmarkDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>AddBookmarkDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarkNode.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the bookmark node. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QDateTime + + +class BookmarkNode(object): + """ + Class implementing the bookmark node type. + """ + # possible bookmark node types + Root = 0 + Folder = 1 + Bookmark = 2 + Separator = 3 + + # possible timestamp types + TsAdded = 0 + TsModified = 1 + TsVisited = 2 + + def __init__(self, type_=Root, parent=None): + """ + Constructor + + @param type_ type of the bookmark node (BookmarkNode.Type) + @param parent reference to the parent node (BookmarkNode) + """ + self.url = "" + self.title = "" + self.desc = "" + self.expanded = False + self.added = QDateTime() + self.modified = QDateTime() + self.visited = QDateTime() + + self._children = [] + self._parent = parent + self._type = type_ + + if parent is not None: + parent.add(self) + + def type(self): + """ + Public method to get the bookmark's type. + + @return bookmark type (BookmarkNode.Type) + """ + return self._type + + def setType(self, type_): + """ + Public method to set the bookmark's type. + + @param type_ type of the bookmark node (BookmarkNode.Type) + """ + self._type = type_ + + def children(self): + """ + Public method to get the list of child nodes. + + @return list of all child nodes (list of BookmarkNode) + """ + return self._children[:] + + def parent(self): + """ + Public method to get a reference to the parent node. + + @return reference to the parent node (BookmarkNode) + """ + return self._parent + + def add(self, child, offset=-1): + """ + Public method to add/insert a child node. + + @param child reference to the node to add (BookmarkNode) + @param offset position where to insert child (integer, -1 = append) + """ + if child._type == BookmarkNode.Root: + return + + if child._parent is not None: + child._parent.remove(child) + + child._parent = self + if offset == -1: + self._children.append(child) + else: + self._children.insert(offset, child) + + def remove(self, child): + """ + Public method to remove a child node. + + @param child reference to the child node (BookmarkNode) + """ + child._parent = None + if child in self._children: + self._children.remove(child)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarkPropertiesDialog.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to show and edit bookmark properties. +""" + +from __future__ import unicode_literals + +from PyQt5.QtWidgets import QDialog + +from .Ui_BookmarkPropertiesDialog import Ui_BookmarkPropertiesDialog + + +class BookmarkPropertiesDialog(QDialog, Ui_BookmarkPropertiesDialog): + """ + Class implementing a dialog to show and edit bookmark properties. + """ + def __init__(self, node, parent=None): + """ + Constructor + + @param node reference to the bookmark (BookmarkNode) + @param parent reference to the parent widget (QWidget) + """ + super(BookmarkPropertiesDialog, self).__init__(parent) + self.setupUi(self) + + from .BookmarkNode import BookmarkNode + self.__node = node + if self.__node.type() == BookmarkNode.Folder: + self.addressLabel.hide() + self.addressEdit.hide() + + self.nameEdit.setText(self.__node.title) + self.descriptionEdit.setPlainText(self.__node.desc) + self.addressEdit.setText(self.__node.url) + + def accept(self): + """ + Public slot handling the acceptance of the dialog. + """ + from .BookmarkNode import BookmarkNode + + if (self.__node.type() == BookmarkNode.Bookmark and + not self.addressEdit.text()) or \ + not self.nameEdit.text(): + super(BookmarkPropertiesDialog, self).accept() + return + + import WebBrowser.WebBrowserWindow + bookmarksManager = WebBrowser.WebBrowserWindow.WebBrowserWindow\ + .bookmarksManager() + title = self.nameEdit.text() + if title != self.__node.title: + bookmarksManager.setTitle(self.__node, title) + if self.__node.type() == BookmarkNode.Bookmark: + url = self.addressEdit.text() + if url != self.__node.url: + bookmarksManager.setUrl(self.__node, url) + description = self.descriptionEdit.toPlainText() + if description != self.__node.desc: + self.__node.desc = description + bookmarksManager.setNodeChanged(self.__node) + + super(BookmarkPropertiesDialog, self).accept()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarkPropertiesDialog.ui Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>BookmarkPropertiesDialog</class> + <widget class="QDialog" name="BookmarkPropertiesDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>500</width> + <height>221</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>500</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>500</width> + <height>250</height> + </size> + </property> + <property name="windowTitle"> + <string>Bookmark Properties</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="E5LineEdit" name="nameEdit"> + <property name="toolTip"> + <string>Enter the name</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="addressLabel"> + <property name="text"> + <string>Address:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="E5LineEdit" name="addressEdit"> + <property name="toolTip"> + <string>Enter the address</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Description:</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QPlainTextEdit" name="descriptionEdit"> + <property name="toolTip"> + <string>Enter a description</string> + </property> + </widget> + </item> + <item row="3" column="0" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>E5LineEdit</class> + <extends>QLineEdit</extends> + <header>E5Gui/E5LineEdit.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>nameEdit</tabstop> + <tabstop>addressEdit</tabstop> + <tabstop>descriptionEdit</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>BookmarkPropertiesDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>BookmarkPropertiesDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksDialog.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,266 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to manage bookmarks. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSignal, Qt, QUrl, QModelIndex +from PyQt5.QtGui import QFontMetrics, QCursor +from PyQt5.QtWidgets import QDialog, QMenu, QApplication + +from E5Gui.E5TreeSortFilterProxyModel import E5TreeSortFilterProxyModel + +from .Ui_BookmarksDialog import Ui_BookmarksDialog + + +class BookmarksDialog(QDialog, Ui_BookmarksDialog): + """ + Class implementing a dialog to manage bookmarks. + + @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, manager=None): + """ + Constructor + + @param parent reference to the parent widget (QWidget + @param manager reference to the bookmarks manager object + (BookmarksManager) + """ + super(BookmarksDialog, self).__init__(parent) + self.setupUi(self) + self.setWindowFlags(Qt.Window) + + self.__bookmarksManager = manager + if self.__bookmarksManager is None: + import WebBrowser.WebBrowserWindow + self.__bookmarksManager = WebBrowser.WebBrowserWindow\ + .WebBrowserWindow.bookmarksManager() + + self.__bookmarksModel = self.__bookmarksManager.bookmarksModel() + self.__proxyModel = E5TreeSortFilterProxyModel(self) + self.__proxyModel.setFilterKeyColumn(-1) + self.__proxyModel.setSourceModel(self.__bookmarksModel) + + self.searchEdit.textChanged.connect( + self.__proxyModel.setFilterFixedString) + + self.bookmarksTree.setModel(self.__proxyModel) + self.bookmarksTree.setExpanded(self.__proxyModel.index(0, 0), True) + fm = QFontMetrics(self.font()) + header = fm.width("m") * 40 + self.bookmarksTree.header().resizeSection(0, header) + self.bookmarksTree.header().setStretchLastSection(True) + self.bookmarksTree.setContextMenuPolicy(Qt.CustomContextMenu) + + self.bookmarksTree.activated.connect(self.__activated) + self.bookmarksTree.customContextMenuRequested.connect( + self.__customContextMenuRequested) + + self.removeButton.clicked.connect( + self.bookmarksTree.removeSelected) + self.addFolderButton.clicked.connect(self.__newFolder) + + self.__expandNodes(self.__bookmarksManager.bookmarks()) + + def closeEvent(self, evt): + """ + Protected method to handle the closing of the dialog. + + @param evt reference to the event object (QCloseEvent) (ignored) + """ + self.__shutdown() + + def reject(self): + """ + Public method called when the dialog is rejected. + """ + self.__shutdown() + super(BookmarksDialog, self).reject() + + def __shutdown(self): + """ + Private method to perform shutdown actions for the dialog. + """ + if self.__saveExpandedNodes(self.bookmarksTree.rootIndex()): + self.__bookmarksManager.changeExpanded() + + def __saveExpandedNodes(self, parent): + """ + Private method to save the child nodes of an expanded node. + + @param parent index of the parent node (QModelIndex) + @return flag indicating a change (boolean) + """ + changed = False + for row in range(self.__proxyModel.rowCount(parent)): + child = self.__proxyModel.index(row, 0, parent) + sourceIndex = self.__proxyModel.mapToSource(child) + childNode = self.__bookmarksModel.node(sourceIndex) + wasExpanded = childNode.expanded + if self.bookmarksTree.isExpanded(child): + childNode.expanded = True + changed |= self.__saveExpandedNodes(child) + else: + childNode.expanded = False + changed |= (wasExpanded != childNode.expanded) + + return changed + + def __expandNodes(self, node): + """ + Private method to expand all child nodes of a node. + + @param node reference to the bookmark node to expand (BookmarkNode) + """ + for childNode in node.children(): + if childNode.expanded: + idx = self.__bookmarksModel.nodeIndex(childNode) + idx = self.__proxyModel.mapFromSource(idx) + self.bookmarksTree.setExpanded(idx, True) + self.__expandNodes(childNode) + + def __customContextMenuRequested(self, pos): + """ + Private slot to handle the context menu request for the bookmarks tree. + + @param pos position the context menu was requested (QPoint) + """ + from .BookmarkNode import BookmarkNode + + menu = QMenu() + idx = self.bookmarksTree.indexAt(pos) + idx = idx.sibling(idx.row(), 0) + sourceIndex = self.__proxyModel.mapToSource(idx) + node = self.__bookmarksModel.node(sourceIndex) + if idx.isValid() and node.type() != BookmarkNode.Folder: + menu.addAction( + self.tr("&Open"), self.__openBookmarkInCurrentTab) + menu.addAction( + self.tr("Open in New &Tab"), self.__openBookmarkInNewTab) + menu.addSeparator() + act = menu.addAction(self.tr("Edit &Name"), self.__editName) + act.setEnabled(idx.flags() & Qt.ItemIsEditable) + if idx.isValid() and node.type() != BookmarkNode.Folder: + menu.addAction(self.tr("Edit &Address"), self.__editAddress) + menu.addSeparator() + act = menu.addAction( + self.tr("&Delete"), self.bookmarksTree.removeSelected) + act.setEnabled(idx.flags() & Qt.ItemIsDragEnabled) + menu.addSeparator() + act = menu.addAction(self.tr("&Properties..."), self.__edit) + act.setEnabled(idx.flags() & Qt.ItemIsEditable) + menu.exec_(QCursor.pos()) + + def __activated(self, idx): + """ + Private slot to handle the activation of an entry. + + @param idx reference to the entry index (QModelIndex) + """ + self.__openBookmark( + QApplication.keyboardModifiers() & Qt.ControlModifier) + + def __openBookmarkInCurrentTab(self): + """ + Private slot to open a bookmark in the current browser tab. + """ + self.__openBookmark(False) + + def __openBookmarkInNewTab(self): + """ + Private slot to open a bookmark in a new browser tab. + """ + self.__openBookmark(True) + + def __openBookmark(self, newTab): + """ + Private method to open a bookmark. + + @param newTab flag indicating to open the bookmark in a new tab + (boolean) + """ + from .BookmarkNode import BookmarkNode + from .BookmarksModel import BookmarksModel + + idx = self.bookmarksTree.currentIndex() + sourceIndex = self.__proxyModel.mapToSource(idx) + node = self.__bookmarksModel.node(sourceIndex) + if not idx.parent().isValid() or \ + node is None or \ + node.type() == BookmarkNode.Folder: + return + if newTab: + self.newUrl.emit( + idx.sibling(idx.row(), 1).data(BookmarksModel.UrlRole), + idx.sibling(idx.row(), 0).data(Qt.DisplayRole)) + else: + self.openUrl.emit( + idx.sibling(idx.row(), 1).data(BookmarksModel.UrlRole), + idx.sibling(idx.row(), 0).data(Qt.DisplayRole)) + + def __editName(self): + """ + Private slot to edit the name part of a bookmark. + """ + idx = self.bookmarksTree.currentIndex() + idx = idx.sibling(idx.row(), 0) + self.bookmarksTree.edit(idx) + + def __editAddress(self): + """ + Private slot to edit the address part of a bookmark. + """ + idx = self.bookmarksTree.currentIndex() + idx = idx.sibling(idx.row(), 1) + self.bookmarksTree.edit(idx) + + def __edit(self): + """ + Private slot to edit a bookmarks properties. + """ + from .BookmarkPropertiesDialog import BookmarkPropertiesDialog + + idx = self.bookmarksTree.currentIndex() + sourceIndex = self.__proxyModel.mapToSource(idx) + node = self.__bookmarksModel.node(sourceIndex) + dlg = BookmarkPropertiesDialog(node) + dlg.exec_() + + def __newFolder(self): + """ + Private slot to add a new bookmarks folder. + """ + from .BookmarkNode import BookmarkNode + + currentIndex = self.bookmarksTree.currentIndex() + idx = QModelIndex(currentIndex) + sourceIndex = self.__proxyModel.mapToSource(idx) + sourceNode = self.__bookmarksModel.node(sourceIndex) + row = -1 # append new folder as the last item per default + + if sourceNode is not None and \ + sourceNode.type() != BookmarkNode.Folder: + # If the selected item is not a folder, add a new folder to the + # parent folder, but directly below the selected item. + idx = idx.parent() + row = currentIndex.row() + 1 + + if not idx.isValid(): + # Select bookmarks menu as default. + idx = self.__proxyModel.index(1, 0) + + idx = self.__proxyModel.mapToSource(idx) + parent = self.__bookmarksModel.node(idx) + node = BookmarkNode(BookmarkNode.Folder) + node.title = self.tr("New Folder") + self.__bookmarksManager.addBookmark(parent, node, row)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksDialog.ui Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,179 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>BookmarksDialog</class> + <widget class="QDialog" name="BookmarksDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>750</width> + <height>450</height> + </rect> + </property> + <property name="windowTitle"> + <string>Manage Bookmarks</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <item> + <widget class="E5ClearableLineEdit" name="searchEdit"> + <property name="toolTip"> + <string>Enter search term for bookmarks</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <widget class="E5TreeView" name="bookmarksTree"> + <property name="dragDropMode"> + <enum>QAbstractItemView::InternalMove</enum> + </property> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::ExtendedSelection</enum> + </property> + <property name="textElideMode"> + <enum>Qt::ElideMiddle</enum> + </property> + <property name="uniformRowHeights"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QPushButton" name="removeButton"> + <property name="toolTip"> + <string>Press to delete the selected entries</string> + </property> + <property name="text"> + <string>&Delete</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="addFolderButton"> + <property name="toolTip"> + <string>Press to add a new bookmarks folder</string> + </property> + <property name="text"> + <string>Add &Folder</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <spacer name="spacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>E5ClearableLineEdit</class> + <extends>QLineEdit</extends> + <header>E5Gui/E5LineEdit.h</header> + </customwidget> + <customwidget> + <class>E5TreeView</class> + <extends>QTreeView</extends> + <header>E5Gui/E5TreeView.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>searchEdit</tabstop> + <tabstop>bookmarksTree</tabstop> + <tabstop>removeButton</tabstop> + <tabstop>addFolderButton</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>BookmarksDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>252</x> + <y>445</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>BookmarksDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>320</x> + <y>445</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImportDialog.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog for importing bookmarks from other sources. +""" + +from __future__ import unicode_literals + +import os + +from PyQt5.QtCore import pyqtSlot, Qt, QSize +from PyQt5.QtWidgets import QDialog, QListWidgetItem + +from E5Gui import E5MessageBox +from E5Gui.E5PathPicker import E5PathPickerModes + +from .Ui_BookmarksImportDialog import Ui_BookmarksImportDialog + +from . import BookmarksImporters + +import Globals + + +class BookmarksImportDialog(QDialog, Ui_BookmarksImportDialog): + """ + Class implementing a dialog for importing bookmarks from other sources. + """ + SourcesListIdRole = Qt.UserRole + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent widget (QWidget) + """ + super(BookmarksImportDialog, self).__init__(parent) + self.setupUi(self) + + self.filePicker.setMode(E5PathPickerModes.OpenFileMode) + + self.sourcesList.setIconSize(QSize(48, 48)) + for icon, displayText, idText in BookmarksImporters.getImporters(): + itm = QListWidgetItem(icon, displayText, self.sourcesList) + itm.setData(self.SourcesListIdRole, idText) + + self.__currentPage = 0 + self.__selectedSource = "" + self.__topLevelBookmarkNode = None + self.__sourceFile = "" + self.__sourceDir = "" + + self.pagesWidget.setCurrentIndex(self.__currentPage) + self.__enableNextButton() + + def __enableNextButton(self): + """ + Private slot to set the enabled state of the next button. + """ + if self.__currentPage == 0: + self.nextButton.setEnabled( + len(self.sourcesList.selectedItems()) == 1) + elif self.__currentPage == 1: + self.nextButton.setEnabled(self.filePicker.text() != "") + + @pyqtSlot() + def on_sourcesList_itemSelectionChanged(self): + """ + Private slot to handle changes of the selection of the import source. + """ + self.__enableNextButton() + + @pyqtSlot(str) + def on_filePicker_textChanged(self, txt): + """ + Private slot handling changes of the file to import bookmarks form. + + @param txt text of the line edit (string) + """ + self.__enableNextButton() + + @pyqtSlot() + def on_nextButton_clicked(self): + """ + Private slot to switch to the next page. + """ + if self.sourcesList.currentItem() is None: + return + + if self.__currentPage == 0: + self.__selectedSource = self.sourcesList.currentItem().data( + self.SourcesListIdRole) + (pixmap, sourceName, self.__sourceFile, info, prompt, + self.__sourceDir) = BookmarksImporters.getImporterInfo( + self.__selectedSource) + + self.iconLabel.setPixmap(pixmap) + self.importingFromLabel.setText( + self.tr("<b>Importing from {0}</b>").format(sourceName)) + self.fileLabel1.setText(info) + self.fileLabel2.setText(prompt) + self.standardDirLabel.setText( + "<i>{0}</i>".format(self.__sourceDir)) + + self.nextButton.setText(self.tr("Finish")) + + self.__currentPage += 1 + self.pagesWidget.setCurrentIndex(self.__currentPage) + self.__enableNextButton() + + if self.__selectedSource == "ie": + self.filePicker.setMode(E5PathPickerModes.DirectoryMode) + else: + self.filePicker.setMode(E5PathPickerModes.OpenFileMode) + if Globals.isMacPlatform(): + filter = "*{0}".format( + os.path.splitext(self.__sourceFile)[1]) + else: + filter = self.__sourceFile + self.filePicker.setFilters(filter) + self.filePicker.setDefaultDirectory(self.__sourceDir) + + elif self.__currentPage == 1: + if self.filePicker.text() == "": + return + + importer = BookmarksImporters.getImporter(self.__selectedSource) + importer.setPath(self.filePicker.text()) + if importer.open(): + self.__topLevelBookmarkNode = importer.importedBookmarks() + if importer.error(): + E5MessageBox.critical( + self, + self.tr("Error importing bookmarks"), + importer.errorString()) + return + + self.accept() + + @pyqtSlot() + def on_cancelButton_clicked(self): + """ + Private slot documentation goes here. + """ + self.reject() + + def getImportedBookmarks(self): + """ + Public method to get the imported bookmarks. + + @return top level bookmark (BookmarkNode) + """ + return self.__topLevelBookmarkNode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImportDialog.ui Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,211 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>BookmarksImportDialog</class> + <widget class="QDialog" name="BookmarksImportDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>550</width> + <height>354</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>550</width> + <height>350</height> + </size> + </property> + <property name="windowTitle"> + <string>Import Bookmarks</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QStackedWidget" name="pagesWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="sourcePage"> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Choose source from which you want to import bookmarks:</string> + </property> + </widget> + </item> + <item> + <widget class="QListWidget" name="sourcesList"> + <property name="toolTip"> + <string>Choose the source to import from</string> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="filePage"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="iconLabel"> + <property name="minimumSize"> + <size> + <width>48</width> + <height>48</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>48</width> + <height>48</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="importingFromLabel"/> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>44</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="fileLabel1"> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="standardDirLabel"> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="fileLabel2"/> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>44</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="E5PathPicker" name="filePicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string>Enter the name of the bookmarks file or directory</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>44</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="nextButton"> + <property name="text"> + <string>Next ></string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cancelButton"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>E5PathPicker</class> + <extends>QWidget</extends> + <header>E5Gui/E5PathPicker.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>sourcesList</tabstop> + <tabstop>nextButton</tabstop> + <tabstop>cancelButton</tabstop> + <tabstop>filePicker</tabstop> + </tabstops> + <resources/> + <connections/> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImporters/BookmarksImporter.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a base class for the bookmarks importers. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QObject + + +class BookmarksImporter(QObject): + """ + Class implementing the base class for the bookmarks importers. + """ + def __init__(self, id="", parent=None): + """ + Constructor + + @param id source ID (string) + @param parent reference to the parent object (QObject) + """ + super(BookmarksImporter, self).__init__(parent) + + self._path = "" + self._file = "" + self._error = False + self._errorString = "" + self._id = id + + def setPath(self, path): + """ + Public method to set the path of the bookmarks file or directory. + + @param path bookmarks file or directory (string) + @exception NotImplementedError raised to indicate this method must + be implemented by a subclass + """ + raise NotImplementedError + + def open(self): + """ + Public method to open the bookmarks file. + + It must return a flag indicating success (boolean). + + @exception NotImplementedError raised to indicate this method must + be implemented by a subclass + """ + raise NotImplementedError + + def importedBookmarks(self): + """ + Public method to get the imported bookmarks. + + It must return the imported bookmarks (BookmarkNode). + + @exception NotImplementedError raised to indicate this method must + be implemented by a subclass + """ + raise NotImplementedError + + def error(self): + """ + Public method to check for an error. + + @return flag indicating an error (boolean) + """ + return self._error + + def errorString(self): + """ + Public method to get the error description. + + @return error description (string) + """ + return self._errorString
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImporters/ChromeImporter.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an importer for Chrome bookmarks. +""" + +from __future__ import unicode_literals + +import os +import json + +from PyQt5.QtCore import QCoreApplication, QDate, Qt + +from .BookmarksImporter import BookmarksImporter + +import UI.PixmapCache +import Globals + + +def getImporterInfo(id): + """ + Module function to get information for the given source id. + + @param id id of the browser ("chrome" or "chromium") + @return tuple with an icon (QPixmap), readable name (string), name of + the default bookmarks file (string), an info text (string), + a prompt (string) and the default directory of the bookmarks file + (string) + @exception ValueError raised to indicate an invalid browser ID + """ + if id == "chrome": + if Globals.isWindowsPlatform(): + standardDir = os.path.expandvars( + "%USERPROFILE%\\AppData\\Local\\Google\\Chrome\\" + "User Data\\Default") + elif Globals.isMacPlatform(): + standardDir = os.path.expanduser( + "~/Library/Application Support/Google/Chrome/Default") + else: + standardDir = os.path.expanduser("~/.config/google-chrome/Default") + return ( + UI.PixmapCache.getPixmap("chrome.png"), + "Google Chrome", + "Bookmarks", + QCoreApplication.translate( + "ChromeImporter", + """Google Chrome stores its bookmarks in the""" + """ <b>Bookmarks</b> text file. This file is usually""" + """ located in"""), + QCoreApplication.translate( + "ChromeImporter", + """Please choose the file to begin importing bookmarks."""), + standardDir, + ) + elif id == "chromium": + if Globals.isWindowsPlatform(): + standardDir = os.path.expandvars( + "%USERPROFILE%\\AppData\\Local\\Google\\Chrome\\" + "User Data\\Default") + else: + standardDir = os.path.expanduser("~/.config/chromium/Default") + return ( + UI.PixmapCache.getPixmap("chromium.png"), + "Chromium", + "Bookmarks", + QCoreApplication.translate( + "ChromeImporter", + """Chromium stores its bookmarks in the <b>Bookmarks</b>""" + """ text file. This file is usually located in"""), + QCoreApplication.translate( + "ChromeImporter", + """Please choose the file to begin importing bookmarks."""), + standardDir, + ) + else: + raise ValueError("Unsupported browser ID given ({0}).".format(id)) + + +class ChromeImporter(BookmarksImporter): + """ + Class implementing the Chrome bookmarks importer. + """ + def __init__(self, id="", parent=None): + """ + Constructor + + @param id source ID (string) + @param parent reference to the parent object (QObject) + """ + super(ChromeImporter, self).__init__(id, parent) + + self.__fileName = "" + + def setPath(self, path): + """ + Public method to set the path of the bookmarks file or directory. + + @param path bookmarks file or directory (string) + """ + self.__fileName = path + + def open(self): + """ + Public method to open the bookmarks file. + + @return flag indicating success (boolean) + """ + if not os.path.exists(self.__fileName): + self._error = True + self._errorString = self.tr( + "File '{0}' does not exist.").format(self.__fileName) + return False + return True + + def importedBookmarks(self): + """ + Public method to get the imported bookmarks. + + @return imported bookmarks (BookmarkNode) + """ + try: + f = open(self.__fileName, "r", encoding="utf-8") + contents = json.load(f) + f.close() + except IOError as err: + self._error = True + self._errorString = self.tr( + "File '{0}' cannot be read.\nReason: {1}")\ + .format(self.__fileName, str(err)) + return None + + from ..BookmarkNode import BookmarkNode + importRootNode = BookmarkNode(BookmarkNode.Folder) + if contents["version"] == 1: + self.__processRoots(contents["roots"], importRootNode) + + if self._id == "chrome": + importRootNode.title = self.tr("Google Chrome Import") + elif self._id == "chromium": + importRootNode.title = self.tr("Chromium Import") + else: + importRootNode.title = self.tr("Imported {0}")\ + .format(QDate.currentDate().toString(Qt.SystemLocaleShortDate)) + return importRootNode + + def __processRoots(self, data, rootNode): + """ + Private method to process the bookmark roots. + + @param data dictionary with the bookmarks data (dict) + @param rootNode node to add the bookmarks to (BookmarkNode) + """ + for node in data.values(): + if node["type"] == "folder": + self.__generateFolderNode(node, rootNode) + elif node["type"] == "url": + self.__generateUrlNode(node, rootNode) + + def __generateFolderNode(self, data, rootNode): + """ + Private method to process a bookmarks folder. + + @param data dictionary with the bookmarks data (dict) + @param rootNode node to add the bookmarks to (BookmarkNode) + """ + from ..BookmarkNode import BookmarkNode + folder = BookmarkNode(BookmarkNode.Folder, rootNode) + folder.title = data["name"].replace("&", "&&") + for node in data["children"]: + if node["type"] == "folder": + self.__generateFolderNode(node, folder) + elif node["type"] == "url": + self.__generateUrlNode(node, folder) + + def __generateUrlNode(self, data, rootNode): + """ + Private method to process a bookmarks node. + + @param data dictionary with the bookmarks data (dict) + @param rootNode node to add the bookmarks to (BookmarkNode) + """ + from ..BookmarkNode import BookmarkNode + bookmark = BookmarkNode(BookmarkNode.Bookmark, rootNode) + bookmark.url = data["url"] + bookmark.title = data["name"].replace("&", "&&")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImporters/FirefoxImporter.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an importer for Firefox bookmarks. +""" + +from __future__ import unicode_literals + +import os +import sqlite3 + +from PyQt5.QtCore import QCoreApplication, QDate, Qt, QUrl + +from .BookmarksImporter import BookmarksImporter + +import UI.PixmapCache +import Globals + + +def getImporterInfo(id): + """ + Module function to get information for the given source id. + + @param id id of the browser ("chrome" or "chromium") + @return tuple with an icon (QPixmap), readable name (string), name of + the default bookmarks file (string), an info text (string), + a prompt (string) and the default directory of the bookmarks file + (string) + @exception ValueError raised to indicate an invalid browser ID + """ + if id == "firefox": + if Globals.isWindowsPlatform(): + standardDir = os.path.expandvars( + "%APPDATA%\\Mozilla\\Firefox\\Profiles") + elif Globals.isMacPlatform(): + standardDir = os.path.expanduser( + "~/Library/Application Support/Firefox/Profiles") + else: + standardDir = os.path.expanduser("~/.mozilla/firefox") + return ( + UI.PixmapCache.getPixmap("chrome.png"), + "Mozilla Firefox", + "places.sqlite", + QCoreApplication.translate( + "FirefoxImporter", + """Mozilla Firefox stores its bookmarks in the""" + """ <b>places.sqlite</b> SQLite database. This file is""" + """ usually located in"""), + QCoreApplication.translate( + "FirefoxImporter", + """Please choose the file to begin importing bookmarks."""), + standardDir, + ) + else: + raise ValueError("Unsupported browser ID given ({0}).".format(id)) + + +class FirefoxImporter(BookmarksImporter): + """ + Class implementing the Chrome bookmarks importer. + """ + def __init__(self, id="", parent=None): + """ + Constructor + + @param id source ID (string) + @param parent reference to the parent object (QObject) + """ + super(FirefoxImporter, self).__init__(id, parent) + + self.__fileName = "" + self.__db = None + + def setPath(self, path): + """ + Public method to set the path of the bookmarks file or directory. + + @param path bookmarks file or directory (string) + """ + self.__fileName = path + + def open(self): + """ + Public method to open the bookmarks file. + + @return flag indicating success (boolean) + """ + if not os.path.exists(self.__fileName): + self._error = True + self._errorString = self.tr("File '{0}' does not exist.")\ + .format(self.__fileName) + return False + + try: + self.__db = sqlite3.connect(self.__fileName) + except sqlite3.DatabaseError as err: + self._error = True + self._errorString = self.tr( + "Unable to open database.\nReason: {0}").format(str(err)) + return False + + return True + + def importedBookmarks(self): + """ + Public method to get the imported bookmarks. + + @return imported bookmarks (BookmarkNode) + """ + from ..BookmarkNode import BookmarkNode + importRootNode = BookmarkNode(BookmarkNode.Root) + + # step 1: build the hierarchy of bookmark folders + folders = {} + + try: + cursor = self.__db.cursor() + cursor.execute( + "SELECT id, parent, title FROM moz_bookmarks " + "WHERE type = 2 and title !=''") + for row in cursor: + id_ = row[0] + parent = row[1] + title = row[2] + if parent in folders: + folder = BookmarkNode(BookmarkNode.Folder, folders[parent]) + else: + folder = BookmarkNode(BookmarkNode.Folder, importRootNode) + folder.title = title.replace("&", "&&") + folders[id_] = folder + except sqlite3.DatabaseError as err: + self._error = True + self._errorString = self.tr( + "Unable to open database.\nReason: {0}").format(str(err)) + return None + + try: + cursor = self.__db.cursor() + cursor.execute( + "SELECT parent, title, fk, position FROM moz_bookmarks" + " WHERE type = 1 and title != '' ORDER BY position") + for row in cursor: + parent = row[0] + title = row[1] + placesId = row[2] + + cursor2 = self.__db.cursor() + cursor2.execute( + "SELECT url FROM moz_places WHERE id = {0}" + .format(placesId)) + row2 = cursor2.fetchone() + if row2: + url = QUrl(row2[0]) + if not title or url.isEmpty() or \ + url.scheme() in ["place", "about"]: + continue + + if parent in folders: + bookmark = BookmarkNode(BookmarkNode.Bookmark, + folders[parent]) + else: + bookmark = BookmarkNode(BookmarkNode.Bookmark, + importRootNode) + bookmark.url = url.toString() + bookmark.title = title.replace("&", "&&") + except sqlite3.DatabaseError as err: + self._error = True + self._errorString = self.tr( + "Unable to open database.\nReason: {0}").format(str(err)) + return None + + importRootNode.setType(BookmarkNode.Folder) + if self._id == "firefox": + importRootNode.title = self.tr("Mozilla Firefox Import") + else: + importRootNode.title = self.tr("Imported {0}")\ + .format(QDate.currentDate().toString(Qt.SystemLocaleShortDate)) + return importRootNode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImporters/HtmlImporter.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an importer for HTML bookmark files. +""" + +from __future__ import unicode_literals + +import os + +from PyQt5.QtCore import QCoreApplication, QDate, Qt + +from .BookmarksImporter import BookmarksImporter + +import UI.PixmapCache + + +def getImporterInfo(id): + """ + Module function to get information for the given HTML source id. + + @param id id of the browser ("chrome" or "chromium") + @return tuple with an icon (QPixmap), readable name (string), name of + the default bookmarks file (string), an info text (string), + a prompt (string) and the default directory of the bookmarks file + (string) + @exception ValueError raised to indicate an invalid browser ID + """ + if id == "html": + return ( + UI.PixmapCache.getPixmap("html.png"), + "HTML Netscape Bookmarks", + QCoreApplication.translate( + "HtmlImporter", + "HTML Netscape Bookmarks") + " (*.htm *.html)", + QCoreApplication.translate( + "HtmlImporter", + """You can import bookmarks from any browser that supports""" + """ HTML exporting. This file has usually the extension""" + """ .htm or .html."""), + QCoreApplication.translate( + "HtmlImporter", + """Please choose the file to begin importing bookmarks."""), + "", + ) + else: + raise ValueError("Unsupported browser ID given ({0}).".format(id)) + + +class HtmlImporter(BookmarksImporter): + """ + Class implementing the HTML bookmarks importer. + """ + def __init__(self, id="", parent=None): + """ + Constructor + + @param id source ID (string) + @param parent reference to the parent object (QObject) + """ + super(HtmlImporter, self).__init__(id, parent) + + self.__fileName = "" + self.__inFile = None + + def setPath(self, path): + """ + Public method to set the path of the bookmarks file or directory. + + @param path bookmarks file or directory (string) + """ + self.__fileName = path + + def open(self): + """ + Public method to open the bookmarks file. + + @return flag indicating success (boolean) + """ + if not os.path.exists(self.__fileName): + self._error = True + self._errorString = self.tr("File '{0}' does not exist.")\ + .format(self.__fileName) + return False + return True + + def importedBookmarks(self): + """ + Public method to get the imported bookmarks. + + @return imported bookmarks (BookmarkNode) + """ + from ..BookmarkNode import BookmarkNode + from ..NsHtmlReader import NsHtmlReader + + reader = NsHtmlReader() + importRootNode = reader.read(self.__fileName) + + importRootNode.setType(BookmarkNode.Folder) + if self._id == "html": + importRootNode.title = self.tr("HTML Import") + else: + importRootNode.title = self.tr("Imported {0}")\ + .format(QDate.currentDate().toString(Qt.SystemLocaleShortDate)) + return importRootNode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImporters/IExplorerImporter.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an importer for Internet Explorer bookmarks. +""" + +from __future__ import unicode_literals + +import os + +from PyQt5.QtCore import QCoreApplication, QDate, Qt + +from .BookmarksImporter import BookmarksImporter + +import UI.PixmapCache +import Globals + + +def getImporterInfo(id): + """ + Module function to get information for the given source id. + + @param id id of the browser ("chrome" or "chromium") + @return tuple with an icon (QPixmap), readable name (string), name of + the default bookmarks file (string), an info text (string), + a prompt (string) and the default directory of the bookmarks file + (string) + @exception ValueError raised to indicate an invalid browser ID + """ + if id == "ie": + if Globals.isWindowsPlatform(): + standardDir = os.path.expandvars( + "%USERPROFILE%\\Favorites") + else: + standardDir = "" + return ( + UI.PixmapCache.getPixmap("internet_explorer.png"), + "Internet Explorer", + "", + QCoreApplication.translate( + "IExplorerImporter", + """Internet Explorer stores its bookmarks in the""" + """ <b>Favorites</b> folder This folder is usually""" + """ located in"""), + QCoreApplication.translate( + "IExplorerImporter", + """Please choose the folder to begin importing bookmarks."""), + standardDir, + ) + else: + raise ValueError("Unsupported browser ID given ({0}).".format(id)) + + +class IExplorerImporter(BookmarksImporter): + """ + Class implementing the Chrome bookmarks importer. + """ + def __init__(self, id="", parent=None): + """ + Constructor + + @param id source ID (string) + @param parent reference to the parent object (QObject) + """ + super(IExplorerImporter, self).__init__(id, parent) + + self.__fileName = "" + + def setPath(self, path): + """ + Public method to set the path of the bookmarks file or directory. + + @param path bookmarks file or directory (string) + """ + self.__fileName = path + + def open(self): + """ + Public method to open the bookmarks file. + + @return flag indicating success (boolean) + """ + if not os.path.exists(self.__fileName): + self._error = True + self._errorString = self.tr("Folder '{0}' does not exist.")\ + .format(self.__fileName) + return False + if not os.path.isdir(self.__fileName): + self._error = True + self._errorString = self.tr("'{0}' is not a folder.")\ + .format(self.__fileName) + return True + + def importedBookmarks(self): + """ + Public method to get the imported bookmarks. + + @return imported bookmarks (BookmarkNode) + """ + from ..BookmarkNode import BookmarkNode + + folders = {} + + importRootNode = BookmarkNode(BookmarkNode.Folder) + folders[self.__fileName] = importRootNode + + for dir, subdirs, files in os.walk(self.__fileName): + for subdir in subdirs: + path = os.path.join(dir, subdir) + if dir in folders: + folder = BookmarkNode(BookmarkNode.Folder, folders[dir]) + else: + folder = BookmarkNode(BookmarkNode.Folder, importRootNode) + folder.title = subdir.replace("&", "&&") + folders[path] = folder + + for file in files: + name, ext = os.path.splitext(file) + if ext.lower() == ".url": + path = os.path.join(dir, file) + try: + f = open(path, "r") + contents = f.read() + f.close() + except IOError: + continue + url = "" + for line in contents.splitlines(): + if line.startswith("URL="): + url = line.replace("URL=", "") + break + if url: + if dir in folders: + bookmark = BookmarkNode(BookmarkNode.Bookmark, + folders[dir]) + else: + bookmark = BookmarkNode(BookmarkNode.Bookmark, + importRootNode) + bookmark.url = url + bookmark.title = name.replace("&", "&&") + + if self._id == "ie": + importRootNode.title = self.tr("Internet Explorer Import") + else: + importRootNode.title = self.tr("Imported {0}")\ + .format(QDate.currentDate().toString(Qt.SystemLocaleShortDate)) + return importRootNode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImporters/OperaImporter.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an importer for Opera bookmarks. +""" + +from __future__ import unicode_literals + +import os + +from PyQt5.QtCore import QCoreApplication, QDate, Qt + +from .BookmarksImporter import BookmarksImporter + +import UI.PixmapCache +import Globals + + +def getImporterInfo(id): + """ + Module function to get information for the given source id. + + @param id id of the browser ("chrome" or "chromium") + @return tuple with an icon (QPixmap), readable name (string), name of + the default bookmarks file (string), an info text (string), + a prompt (string) and the default directory of the bookmarks file + (string) + @exception ValueError raised to indicate an invalid browser ID + """ + if id == "opera": + if Globals.isWindowsPlatform(): + standardDir = os.path.expandvars("%APPDATA%\\Opera\\Opera") + elif Globals.isMacPlatform(): + standardDir = os.path.expanduser( + "~/Library/Opera") + else: + standardDir = os.path.expanduser("~/.opera") + return ( + UI.PixmapCache.getPixmap("opera.png"), + "Opera", + "bookmarks.adr", + QCoreApplication.translate( + "OperaImporter", + """Opera stores its bookmarks in the <b>bookmarks.adr</b> """ + """text file. This file is usually located in"""), + QCoreApplication.translate( + "OperaImporter", + """Please choose the file to begin importing bookmarks."""), + standardDir, + ) + else: + raise ValueError("Unsupported browser ID given ({0}).".format(id)) + + +class OperaImporter(BookmarksImporter): + """ + Class implementing the Opera bookmarks importer. + """ + def __init__(self, id="", parent=None): + """ + Constructor + + @param id source ID (string) + @param parent reference to the parent object (QObject) + """ + super(OperaImporter, self).__init__(id, parent) + + self.__fileName = "" + + def setPath(self, path): + """ + Public method to set the path of the bookmarks file or directory. + + @param path bookmarks file or directory (string) + """ + self.__fileName = path + + def open(self): + """ + Public method to open the bookmarks file. + + @return flag indicating success (boolean) + """ + if not os.path.exists(self.__fileName): + self._error = True + self._errorString = self.tr("File '{0}' does not exist.")\ + .format(self.__fileName) + return False + return True + + def importedBookmarks(self): + """ + Public method to get the imported bookmarks. + + @return imported bookmarks (BookmarkNode) + """ + try: + f = open(self.__fileName, "r", encoding="utf-8") + contents = f.read() + f.close() + except IOError as err: + self._error = True + self._errorString = self.tr( + "File '{0}' cannot be read.\nReason: {1}")\ + .format(self.__fileName, str(err)) + return None + + folderStack = [] + + from ..BookmarkNode import BookmarkNode + importRootNode = BookmarkNode(BookmarkNode.Folder) + folderStack.append(importRootNode) + + for line in contents.splitlines(): + line = line.strip() + if line == "#FOLDER": + node = BookmarkNode(BookmarkNode.Folder, folderStack[-1]) + folderStack.append(node) + elif line == "#URL": + node = BookmarkNode(BookmarkNode.Bookmark, folderStack[-1]) + elif line == "-": + folderStack.pop() + elif line.startswith("NAME="): + node.title = line.replace("NAME=", "").replace("&", "&&") + elif line.startswith("URL="): + node.url = line.replace("URL=", "") + + if self._id == "opera": + importRootNode.title = self.tr("Opera Import") + else: + importRootNode.title = self.tr("Imported {0}")\ + .format(QDate.currentDate().toString(Qt.SystemLocaleShortDate)) + return importRootNode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImporters/SafariImporter.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an importer for Apple Safari bookmarks. +""" + +from __future__ import unicode_literals + +import os + +from PyQt5.QtCore import QCoreApplication, QDate, Qt + +from .BookmarksImporter import BookmarksImporter + +import UI.PixmapCache +import Globals + +from Utilities import binplistlib + + +def getImporterInfo(id): + """ + Module function to get information for the given source id. + + @param id id of the browser ("chrome" or "chromium") + @return tuple with an icon (QPixmap), readable name (string), name of + the default bookmarks file (string), an info text (string), + a prompt (string) and the default directory of the bookmarks file + (string) + @exception ValueError raised to indicate an invalid browser ID + """ + if id == "safari": + if Globals.isWindowsPlatform(): + standardDir = os.path.expandvars( + "%APPDATA%\\Apple Computer\\Safari") + elif Globals.isMacPlatform(): + standardDir = os.path.expanduser("~/Library/Safari") + else: + standardDir = "" + return ( + UI.PixmapCache.getPixmap("safari.png"), + "Apple Safari", + "Bookmarks.plist", + QCoreApplication.translate( + "SafariImporter", + """Apple Safari stores its bookmarks in the""" + """ <b>Bookmarks.plist</b> file. This file is usually""" + """ located in"""), + QCoreApplication.translate( + "SafariImporter", + """Please choose the file to begin importing bookmarks."""), + standardDir, + ) + else: + raise ValueError("Unsupported browser ID given ({0}).".format(id)) + + +class SafariImporter(BookmarksImporter): + """ + Class implementing the Apple Safari bookmarks importer. + """ + def __init__(self, id="", parent=None): + """ + Constructor + + @param id source ID (string) + @param parent reference to the parent object (QObject) + """ + super(SafariImporter, self).__init__(id, parent) + + self.__fileName = "" + + def setPath(self, path): + """ + Public method to set the path of the bookmarks file or directory. + + @param path bookmarks file or directory (string) + """ + self.__fileName = path + + def open(self): + """ + Public method to open the bookmarks file. + + @return flag indicating success (boolean) + """ + if not os.path.exists(self.__fileName): + self._error = True + self._errorString = self.tr("File '{0}' does not exist.")\ + .format(self.__fileName) + return False + return True + + def importedBookmarks(self): + """ + Public method to get the imported bookmarks. + + @return imported bookmarks (BookmarkNode) + """ + try: + bookmarksDict = binplistlib.readPlist(self.__fileName) + except binplistlib.InvalidPlistException as err: + self._error = True + self._errorString = self.tr( + "Bookmarks file cannot be read.\nReason: {0}".format(str(err))) + return None + + from ..BookmarkNode import BookmarkNode + importRootNode = BookmarkNode(BookmarkNode.Folder) + if bookmarksDict["WebBookmarkFileVersion"] == 1 and \ + bookmarksDict["WebBookmarkType"] == "WebBookmarkTypeList": + self.__processChildren(bookmarksDict["Children"], importRootNode) + + if self._id == "safari": + importRootNode.title = self.tr("Apple Safari Import") + else: + importRootNode.title = self.tr("Imported {0}")\ + .format(QDate.currentDate().toString(Qt.SystemLocaleShortDate)) + return importRootNode + + def __processChildren(self, children, rootNode): + """ + Private method to process the list of children. + + @param children list of child nodes to be processed (list of dict) + @param rootNode node to add the bookmarks to (BookmarkNode) + """ + from ..BookmarkNode import BookmarkNode + for child in children: + if child["WebBookmarkType"] == "WebBookmarkTypeList": + folder = BookmarkNode(BookmarkNode.Folder, rootNode) + folder.title = child["Title"].replace("&", "&&") + if "Children" in child: + self.__processChildren(child["Children"], folder) + elif child["WebBookmarkType"] == "WebBookmarkTypeLeaf": + url = child["URLString"] + if url.startswith(("place:", "about:")): + continue + + bookmark = BookmarkNode(BookmarkNode.Bookmark, rootNode) + bookmark.url = url + bookmark.title = child["URIDictionary"]["title"]\ + .replace("&", "&&")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImporters/XbelImporter.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an importer for XBEL files. +""" + +from __future__ import unicode_literals + +import os + +from PyQt5.QtCore import QCoreApplication, QXmlStreamReader, QDate, Qt + +from .BookmarksImporter import BookmarksImporter + +import UI.PixmapCache + + +def getImporterInfo(id): + """ + Module function to get information for the given XBEL source id. + + @param id id of the browser ("chrome" or "chromium") + @return tuple with an icon (QPixmap), readable name (string), name of + the default bookmarks file (string), an info text (string), + a prompt (string) and the default directory of the bookmarks file + (string) + @exception ValueError raised to indicate an invalid browser ID + """ + if id == "e5browser": + from ..BookmarksManager import BookmarksManager + bookmarksFile = BookmarksManager.getFileName() + return ( + UI.PixmapCache.getPixmap("ericWeb48.png"), + "eric6 Web Browser", + os.path.basename(bookmarksFile), + QCoreApplication.translate( + "XbelImporter", + """eric6 Web Browser stores its bookmarks in the""" + """ <b>{0}</b> XML file. This file is usually located in""" + ).format(os.path.basename(bookmarksFile)), + QCoreApplication.translate( + "XbelImporter", + """Please choose the file to begin importing bookmarks."""), + os.path.dirname(bookmarksFile), + ) + elif id == "konqueror": + if os.path.exists(os.path.expanduser("~/.kde4")): + standardDir = os.path.expanduser("~/.kde4/share/apps/konqueror") + elif os.path.exists(os.path.expanduser("~/.kde")): + standardDir = os.path.expanduser("~/.kde/share/apps/konqueror") + else: + standardDir = "" + return ( + UI.PixmapCache.getPixmap("konqueror.png"), + "Konqueror", + "bookmarks.xml", + QCoreApplication.translate( + "XbelImporter", + """Konqueror stores its bookmarks in the""" + """ <b>bookmarks.xml</b> XML file. This file is usually""" + """ located in"""), + QCoreApplication.translate( + "XbelImporter", + """Please choose the file to begin importing bookmarks."""), + standardDir, + ) + elif id == "xbel": + return ( + UI.PixmapCache.getPixmap("xbel.png"), + "XBEL Bookmarks", + QCoreApplication.translate( + "XbelImporter", "XBEL Bookmarks") + " (*.xbel *.xml)", + QCoreApplication.translate( + "XbelImporter", + """You can import bookmarks from any browser that supports""" + """ XBEL exporting. This file has usually the extension""" + """ .xbel or .xml."""), + QCoreApplication.translate( + "XbelImporter", + """Please choose the file to begin importing bookmarks."""), + "", + ) + else: + raise ValueError("Unsupported browser ID given ({0}).".format(id)) + + +class XbelImporter(BookmarksImporter): + """ + Class implementing the XBEL bookmarks importer. + """ + def __init__(self, id="", parent=None): + """ + Constructor + + @param id source ID (string) + @param parent reference to the parent object (QObject) + """ + super(XbelImporter, self).__init__(id, parent) + + self.__fileName = "" + + def setPath(self, path): + """ + Public method to set the path of the bookmarks file or directory. + + @param path bookmarks file or directory (string) + """ + self.__fileName = path + + def open(self): + """ + Public method to open the bookmarks file. + + @return flag indicating success (boolean) + """ + if not os.path.exists(self.__fileName): + self._error = True + self._errorString = self.tr("File '{0}' does not exist.")\ + .format(self.__fileName) + return False + return True + + def importedBookmarks(self): + """ + Public method to get the imported bookmarks. + + @return imported bookmarks (BookmarkNode) + """ + from ..XbelReader import XbelReader + + reader = XbelReader() + importRootNode = reader.read(self.__fileName) + + if reader.error() != QXmlStreamReader.NoError: + self._error = True + self._errorString = self.tr( + """Error when importing bookmarks on line {0},""" + """ column {1}:\n{2}""")\ + .format(reader.lineNumber(), + reader.columnNumber(), + reader.errorString()) + return None + + from ..BookmarkNode import BookmarkNode + importRootNode.setType(BookmarkNode.Folder) + if self._id == "e5browser": + importRootNode.title = self.tr("eric6 Web Browser Import") + elif self._id == "konqueror": + importRootNode.title = self.tr("Konqueror Import") + elif self._id == "xbel": + importRootNode.title = self.tr("XBEL Import") + else: + importRootNode.title = self.tr("Imported {0}")\ + .format(QDate.currentDate().toString(Qt.SystemLocaleShortDate)) + return importRootNode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksImporters/__init__.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,125 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package implementing bookmarks importers for various sources. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QCoreApplication + +import UI.PixmapCache +import Globals + + +def getImporters(): + """ + Module function to get a list of supported importers. + + @return list of tuples with an icon (QIcon), readable name (string) and + internal name (string) + """ + importers = [] + importers.append( + (UI.PixmapCache.getIcon("ericWeb48.png"), "eric6 Web Browser", + "e5browser")) + importers.append( + (UI.PixmapCache.getIcon("firefox.png"), "Mozilla Firefox", "firefox")) + importers.append( + (UI.PixmapCache.getIcon("chrome.png"), "Google Chrome", "chrome")) + if Globals.isLinuxPlatform(): + importers.append( + (UI.PixmapCache.getIcon("chromium.png"), "Chromium", "chromium")) + importers.append( + (UI.PixmapCache.getIcon("konqueror.png"), "Konqueror", + "konqueror")) + importers.append( + (UI.PixmapCache.getIcon("opera.png"), "Opera", "opera")) + importers.append( + (UI.PixmapCache.getIcon("safari.png"), "Apple Safari", "safari")) + if Globals.isWindowsPlatform(): + importers.append( + (UI.PixmapCache.getIcon("internet_explorer.png"), + "Internet Explorer", "ie")) + importers.append( + (UI.PixmapCache.getIcon("xbel.png"), + QCoreApplication.translate("BookmarksImporters", "XBEL File"), + "xbel")) + importers.append( + (UI.PixmapCache.getIcon("html.png"), + QCoreApplication.translate("BookmarksImporters", "HTML File"), + "html")) + return importers + + +def getImporterInfo(id): + """ + Module function to get information for the given source id. + + @param id source id to get info for (string) + @return tuple with an icon (QPixmap), readable name (string), name of + the default bookmarks file (string), an info text (string), + a prompt (string) and the default directory of the bookmarks + file (string) + @exception ValueError raised to indicate an unsupported importer + """ + if id in ["e5browser", "xbel", "konqueror"]: + from . import XbelImporter + return XbelImporter.getImporterInfo(id) + elif id == "html": + from . import HtmlImporter + return HtmlImporter.getImporterInfo(id) + elif id in ["chrome", "chromium"]: + from . import ChromeImporter + return ChromeImporter.getImporterInfo(id) + elif id == "opera": + from . import OperaImporter + return OperaImporter.getImporterInfo(id) + elif id == "firefox": + from . import FirefoxImporter + return FirefoxImporter.getImporterInfo(id) + elif id == "ie": + from . import IExplorerImporter + return IExplorerImporter.getImporterInfo(id) + elif id == "safari": + from . import SafariImporter + return SafariImporter.getImporterInfo(id) + else: + raise ValueError("Invalid importer ID given ({0}).".format(id)) + + +def getImporter(id, parent=None): + """ + Module function to get an importer for the given source id. + + @param id source id to get an importer for (string) + @param parent reference to the parent object (QObject) + @return bookmarks importer (BookmarksImporter) + @exception ValueError raised to indicate an unsupported importer + """ + if id in ["e5browser", "xbel", "konqueror"]: + from . import XbelImporter + return XbelImporter.XbelImporter(id, parent) + elif id == "html": + from . import HtmlImporter + return HtmlImporter.HtmlImporter(id, parent) + elif id in ["chrome", "chromium"]: + from . import ChromeImporter + return ChromeImporter.ChromeImporter(id, parent) + elif id == "opera": + from . import OperaImporter + return OperaImporter.OperaImporter(id, parent) + elif id == "firefox": + from . import FirefoxImporter + return FirefoxImporter.FirefoxImporter(id, parent) + elif id == "ie": + from . import IExplorerImporter + return IExplorerImporter.IExplorerImporter(id, parent) + elif id == "safari": + from . import SafariImporter + return SafariImporter.SafariImporter(id, parent) + else: + raise ValueError("No importer for ID {0}.".format(id))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksManager.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,643 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 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(), "web_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)) + + # TODO: Bookmarks: remove this obsolete method + 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 [] + + 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)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksMenu.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,308 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the bookmarks menu. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSignal, Qt, QUrl +from PyQt5.QtGui import QCursor +from PyQt5.QtWidgets import QMenu + +from E5Gui.E5ModelMenu import E5ModelMenu + +from .BookmarksModel import BookmarksModel +from .BookmarkNode import BookmarkNode + + +class BookmarksMenu(E5ModelMenu): + """ + Class implementing the bookmarks menu base class. + + @signal openUrl(QUrl, str) emitted to open a URL with the given title in + the current tab + @signal newUrl(QUrl, str) emitted to open a URL with the given title 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.activated.connect(self.__activated) + self.setStatusBarTextRole(BookmarksModel.UrlStringRole) + self.setSeparatorRole(BookmarksModel.SeparatorRole) + + self.setContextMenuPolicy(Qt.CustomContextMenu) + self.customContextMenuRequested.connect(self.__contextMenuRequested) + + def createBaseMenu(self): + """ + Public method to get the menu that is used to populate sub menu's. + + @return reference to the menu (BookmarksMenu) + """ + menu = BookmarksMenu(self) + menu.openUrl.connect(self.openUrl) + menu.newUrl.connect(self.newUrl) + return menu + + 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(BookmarksModel.UrlRole), + idx.data(Qt.DisplayRole)) + else: + self.openUrl.emit( + idx.data(BookmarksModel.UrlRole), + idx.data(Qt.DisplayRole)) + self.resetFlags() + + def postPopulated(self): + """ + Public method to add any actions after the tree. + """ + if self.isEmpty(): + return + + parent = self.rootIndex() + + hasBookmarks = False + + for i in range(parent.model().rowCount(parent)): + child = parent.model().index(i, 0, parent) + + if child.data(BookmarksModel.TypeRole) == BookmarkNode.Bookmark: + hasBookmarks = True + break + + if not hasBookmarks: + return + + self.addSeparator() + act = self.addAction(self.tr("Open all in Tabs")) + act.triggered.connect(self.openAll) + + def openAll(self): + """ + Public slot to open all the menu's items. + """ + menu = self.sender().parent() + if menu is None: + return + + parent = menu.rootIndex() + if not parent.isValid(): + return + + for i in range(parent.model().rowCount(parent)): + child = parent.model().index(i, 0, parent) + + if child.data(BookmarksModel.TypeRole) != BookmarkNode.Bookmark: + continue + + if i == 0: + self.openUrl.emit( + child.data(BookmarksModel.UrlRole), + child.data(Qt.DisplayRole)) + else: + self.newUrl.emit( + child.data(BookmarksModel.UrlRole), + child.data(Qt.DisplayRole)) + + def __contextMenuRequested(self, pos): + """ + Private slot to handle the context menu request. + + @param pos position the context menu shall be shown (QPoint) + """ + act = self.actionAt(pos) + + if act is not None and \ + act.menu() is None and \ + self.index(act).isValid(): + menu = QMenu() + v = act.data() + + menuAction = menu.addAction( + self.tr("&Open"), self.__openBookmark) + menuAction.setData(v) + menuAction = menu.addAction( + self.tr("Open in New &Tab\tCtrl+LMB"), + self.__openBookmarkInNewTab) + menuAction.setData(v) + menu.addSeparator() + + menuAction = menu.addAction( + self.tr("&Remove"), self.__removeBookmark) + menuAction.setData(v) + menu.addSeparator() + + menuAction = menu.addAction( + self.tr("&Properties..."), self.__edit) + menuAction.setData(v) + + execAct = menu.exec_(QCursor.pos()) + if execAct is not None: + self.close() + parent = self.parent() + while parent is not None and isinstance(parent, QMenu): + parent.close() + parent = parent.parent() + + def __openBookmark(self): + """ + Private slot to open a bookmark in the current browser tab. + """ + idx = self.index(self.sender()) + + self.openUrl.emit( + idx.data(BookmarksModel.UrlRole), + idx.data(Qt.DisplayRole)) + + def __openBookmarkInNewTab(self): + """ + Private slot to open a bookmark in a new browser tab. + """ + idx = self.index(self.sender()) + + self.newUrl.emit( + idx.data(BookmarksModel.UrlRole), + idx.data(Qt.DisplayRole)) + + def __removeBookmark(self): + """ + Private slot to remove a bookmark. + """ + idx = self.index(self.sender()) + self.removeEntry(idx) + + def __edit(self): + """ + Private slot to edit a bookmarks properties. + """ + from .BookmarkPropertiesDialog import BookmarkPropertiesDialog + + idx = self.index(self.sender()) + node = self.model().node(idx) + dlg = BookmarkPropertiesDialog(node) + dlg.exec_() + +############################################################################## + + +class BookmarksMenuBarMenu(BookmarksMenu): + """ + Class implementing a dynamically populated menu for bookmarks. + + @signal openUrl(QUrl, str) emitted to open a URL with the given title in + the current tab + """ + openUrl = pyqtSignal(QUrl, str) + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent widget (QWidget) + """ + BookmarksMenu.__init__(self, parent) + + self.__bookmarksManager = None + self.__initialActions = [] + + def prePopulated(self): + """ + Public method to add any actions before the tree. + + @return flag indicating if any actions were added (boolean) + """ + import WebBrowser.WebBrowserWindow + + self.__bookmarksManager = WebBrowser.WebBrowserWindow.WebBrowserWindow\ + .bookmarksManager() + self.setModel(self.__bookmarksManager.bookmarksModel()) + self.setRootIndex(self.__bookmarksManager.bookmarksModel() + .nodeIndex(self.__bookmarksManager.menu())) + + # initial actions + for act in self.__initialActions: + if act == "--SEPARATOR--": + self.addSeparator() + else: + self.addAction(act) + if len(self.__initialActions) != 0: + self.addSeparator() + + self.createMenu( + self.__bookmarksManager.bookmarksModel() + .nodeIndex(self.__bookmarksManager.toolbar()), + 1, self) + return True + + def postPopulated(self): + """ + Public method to add any actions after the tree. + """ + if self.isEmpty(): + return + + parent = self.rootIndex() + + hasBookmarks = False + + for i in range(parent.model().rowCount(parent)): + child = parent.model().index(i, 0, parent) + + if child.data(BookmarksModel.TypeRole) == BookmarkNode.Bookmark: + hasBookmarks = True + break + + if not hasBookmarks: + return + + self.addSeparator() + act = self.addAction(self.tr("Default Home Page")) + act.setData("eric:home") + act.triggered.connect(self.__defaultBookmarkTriggered) + act = self.addAction(self.tr("Speed Dial")) + act.setData("eric:speeddial") + act.triggered.connect(self.__defaultBookmarkTriggered) + self.addSeparator() + act = self.addAction(self.tr("Open all in Tabs")) + act.triggered.connect(self.openAll) + + 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 __defaultBookmarkTriggered(self): + """ + Private slot handling the default bookmark menu entries. + """ + act = self.sender() + urlStr = act.data() + if urlStr.startswith("eric:"): + self.openUrl.emit(QUrl(urlStr), "")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksModel.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,466 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the bookmark model class. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import Qt, QAbstractItemModel, QModelIndex, QUrl, \ + QByteArray, QDataStream, QIODevice, QBuffer, QMimeData + +import UI.PixmapCache + + +class BookmarksModel(QAbstractItemModel): + """ + Class implementing the bookmark model. + """ + TypeRole = Qt.UserRole + 1 + UrlRole = Qt.UserRole + 2 + UrlStringRole = Qt.UserRole + 3 + SeparatorRole = Qt.UserRole + 4 + + 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(BookmarksModel, self).__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) + """ + parent = node.parent() + 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 + parent.remove(node) + 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) + """ + # node was already removed, re-add so beginRemoveRows works + parent.add(node, row) + 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=QModelIndex()): + """ + 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) + @return flag indicating successful removal (boolean) + """ + if row < 0 or count <= 0 or row + count > self.rowCount(parent): + return False + + bookmarkNode = self.node(parent) + children = bookmarkNode.children()[row:(row + count)] + for node in children: + if node == self.__bookmarksManager.menu() or \ + node == 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.DisplayRole): + """ + Public method to get the header data. + + @param section section number (integer) + @param orientation header orientation (Qt.Orientation) + @param role data role (integer) + @return header data + """ + if orientation == Qt.Horizontal and role == Qt.DisplayRole: + try: + return self.__headers[section] + except IndexError: + pass + return QAbstractItemModel.headerData(self, section, orientation, role) + + def data(self, index, role=Qt.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.EditRole, Qt.DisplayRole]: + if bookmarkNode.type() == BookmarkNode.Separator: + if index.column() == 0: + return 50 * '\xB7' + elif index.column() == 1: + return "" + + if index.column() == 0: + return bookmarkNode.title + elif index.column() == 1: + return bookmarkNode.url + + elif role == self.UrlRole: + return QUrl(bookmarkNode.url) + + elif role == self.UrlStringRole: + return bookmarkNode.url + + elif role == self.TypeRole: + return bookmarkNode.type() + + elif role == self.SeparatorRole: + return bookmarkNode.type() == BookmarkNode.Separator + + elif role == Qt.DecorationRole: + if index.column() == 0: + if bookmarkNode.type() == BookmarkNode.Folder: + return UI.PixmapCache.getIcon("dirOpen.png") + import WebBrowser.WebBrowserWindow + return WebBrowser.WebBrowserWindow.WebBrowserWindow.icon( + QUrl(bookmarkNode.url)) + + return None + + def columnCount(self, parent=QModelIndex()): + """ + Public method to get the number of columns. + + @param parent index of parent (QModelIndex) + @return number of columns (integer) + """ + if parent.column() > 0: + return 0 + else: + return len(self.__headers) + + 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(): + return len(self.__bookmarksManager.bookmarks().children()) + + itm = parent.internalPointer() + return len(itm.children()) + + def index(self, row, column, parent=QModelIndex()): + """ + 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) + @return index (QModelIndex) + """ + if 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=QModelIndex()): + """ + 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 not index.isValid(): + return QModelIndex() + + itemNode = self.node(index) + if itemNode is None: + parentNode = None + else: + parentNode = itemNode.parent() + + 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=QModelIndex()): + """ + 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 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.NoItemFlags + + node = self.node(index) + type_ = node.type() + flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled + + if self.hasChildren(index): + flags |= Qt.ItemIsDropEnabled + + if node == self.__bookmarksManager.menu() or \ + node == self.__bookmarksManager.toolbar(): + return flags + + flags |= Qt.ItemIsDragEnabled + + from .BookmarkNode import BookmarkNode + if (index.column() == 0 and type_ != BookmarkNode.Separator) or \ + (index.column() == 1 and type_ == BookmarkNode.Bookmark): + flags |= Qt.ItemIsEditable + + return flags + + def supportedDropActions(self): + """ + Public method to report the supported drop actions. + + @return supported drop actions (Qt.DropAction) + """ + return Qt.CopyAction | Qt.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.WriteOnly) + urls = [] + + for index in indexes: + if index.column() != 0 or not index.isValid(): + continue + + encodedData = QByteArray() + buffer = QBuffer(encodedData) + buffer.open(QIODevice.ReadWrite) + writer = XbelWriter() + parentNode = self.node(index) + 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) + @param column column number (integer) + @param parent index of the parent node (QModelIndex) + @return flag indicating successful acceptance of the data (boolean) + """ + if action == Qt.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.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.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.__endMacro = True + + return True + + def setData(self, index, value, role=Qt.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.ItemIsEditable) == 0: + return False + + item = self.node(index) + + if role in (Qt.EditRole, Qt.DisplayRole): + if index.column() == 0: + self.__bookmarksManager.setTitle(item, value) + elif index.column() == 1: + 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) + + 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) + """ + itemNode = index.internalPointer() + if itemNode is None: + return self.__bookmarksManager.bookmarks() + else: + return itemNode
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/BookmarksToolBar.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,215 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a tool bar showing bookmarks. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSignal, Qt, QUrl, QCoreApplication +from PyQt5.QtGui import QCursor +from PyQt5.QtWidgets import QMenu +from PyQt5.QtWebKitWidgets import QWebPage + +from E5Gui.E5ModelToolBar import E5ModelToolBar + +from .BookmarksModel import BookmarksModel + + +class BookmarksToolBar(E5ModelToolBar): + """ + Class implementing a tool bar showing bookmarks. + + @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, mainWindow, model, parent=None): + """ + Constructor + + @param mainWindow reference to the main window (HelpWindow) + @param model reference to the bookmarks model (BookmarksModel) + @param parent reference to the parent widget (QWidget) + """ + E5ModelToolBar.__init__( + self, QCoreApplication.translate("BookmarksToolBar", "Bookmarks"), + parent) + + self.__mw = mainWindow + self.__bookmarksModel = model + + self.__mw.bookmarksManager().bookmarksReloaded.connect(self.__rebuild) + + self.setModel(model) + self.setRootIndex(model.nodeIndex( + self.__mw.bookmarksManager().toolbar())) + + self.setContextMenuPolicy(Qt.CustomContextMenu) + self.customContextMenuRequested.connect(self.__contextMenuRequested) + self.activated.connect(self.__bookmarkActivated) + + self.setHidden(True) + self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) + + self._build() + + def __rebuild(self): + """ + Private slot to rebuild the toolbar. + """ + self.__bookmarksModel = \ + self.__mw.bookmarksManager().bookmarksModel() + self.setModel(self.__bookmarksModel) + self.setRootIndex(self.__bookmarksModel.nodeIndex( + self.__mw.bookmarksManager().toolbar())) + self._build() + + def __contextMenuRequested(self, pos): + """ + Private slot to handle the context menu request. + + @param pos position the context menu shall be shown (QPoint) + """ + act = self.actionAt(pos) + menu = QMenu() + + if act is not None: + v = act.data() + + if act.menu() is None: + menuAction = menu.addAction( + self.tr("&Open"), self.__openBookmark) + menuAction.setData(v) + menuAction = menu.addAction( + self.tr("Open in New &Tab\tCtrl+LMB"), + self.__openBookmarkInNewTab) + menuAction.setData(v) + menu.addSeparator() + + menuAction = menu.addAction( + self.tr("&Remove"), self.__removeBookmark) + menuAction.setData(v) + menu.addSeparator() + + menuAction = menu.addAction( + self.tr("&Properties..."), self.__edit) + menuAction.setData(v) + menu.addSeparator() + + menu.addAction(self.tr("Add &Bookmark..."), self.__newBookmark) + menu.addAction(self.tr("Add &Folder..."), self.__newFolder) + + menu.exec_(QCursor.pos()) + + def __bookmarkActivated(self, idx): + """ + Private slot handling the activation of a bookmark. + + @param idx index of the activated bookmark (QModelIndex) + """ + assert idx.isValid() + + if self._mouseButton == Qt.XButton1: + self.__mw.currentBrowser().pageAction(QWebPage.Back).trigger() + elif self._mouseButton == Qt.XButton2: + self.__mw.currentBrowser().pageAction(QWebPage.Forward).trigger() + elif self._mouseButton == Qt.LeftButton: + if self._keyboardModifiers & Qt.ControlModifier: + self.newUrl.emit( + idx.data(BookmarksModel.UrlRole), + idx.data(Qt.DisplayRole)) + else: + self.openUrl.emit( + idx.data(BookmarksModel.UrlRole), + idx.data(Qt.DisplayRole)) + + def __openToolBarBookmark(self): + """ + Private slot to open a bookmark in the current browser tab. + """ + idx = self.index(self.sender()) + + if self._keyboardModifiers & Qt.ControlModifier: + self.newUrl.emit( + idx.data(BookmarksModel.UrlRole), + idx.data(Qt.DisplayRole)) + else: + self.openUrl.emit( + idx.data(BookmarksModel.UrlRole), + idx.data(Qt.DisplayRole)) + self.resetFlags() + + def __openBookmark(self): + """ + Private slot to open a bookmark in the current browser tab. + """ + idx = self.index(self.sender()) + + self.openUrl.emit( + idx.data(BookmarksModel.UrlRole), + idx.data(Qt.DisplayRole)) + + def __openBookmarkInNewTab(self): + """ + Private slot to open a bookmark in a new browser tab. + """ + idx = self.index(self.sender()) + + self.newUrl.emit( + idx.data(BookmarksModel.UrlRole), + idx.data(Qt.DisplayRole)) + + def __removeBookmark(self): + """ + Private slot to remove a bookmark. + """ + idx = self.index(self.sender()) + + self.__bookmarksModel.removeRow(idx.row(), self.rootIndex()) + + def __newBookmark(self): + """ + Private slot to add a new bookmark. + """ + from .AddBookmarkDialog import AddBookmarkDialog + dlg = AddBookmarkDialog() + dlg.setCurrentIndex(self.rootIndex()) + dlg.exec_() + + def __newFolder(self): + """ + Private slot to add a new bookmarks folder. + """ + from .AddBookmarkDialog import AddBookmarkDialog + dlg = AddBookmarkDialog() + dlg.setCurrentIndex(self.rootIndex()) + dlg.setFolder(True) + dlg.exec_() + + def _createMenu(self): + """ + Protected method to create the menu for a tool bar action. + + @return menu for a tool bar action (E5ModelMenu) + """ + from .BookmarksMenu import BookmarksMenu + menu = BookmarksMenu(self) + menu.openUrl.connect(self.openUrl) + menu.newUrl.connect(self.newUrl) + return menu + + def __edit(self): + """ + Private slot to edit a bookmarks properties. + """ + from .BookmarkPropertiesDialog import BookmarkPropertiesDialog + idx = self.index(self.sender()) + node = self.__bookmarksModel.node(idx) + dlg = BookmarkPropertiesDialog(node) + dlg.exec_()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/DefaultBookmarks.qrc Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,6 @@ +<!DOCTYPE RCC> +<RCC version="1.0"> +<qresource> + <file>DefaultBookmarks.xbel</file> +</qresource> +</RCC>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/DefaultBookmarks.xbel Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE xbel> +<xbel version="1.0"> + <folder folded="no"> + <title>Bookmarks Bar</title> + <bookmark href="http://eric-ide.python-projects.org/"> + <title>Eric Web Site</title> + </bookmark> + <bookmark href="http://www.riverbankcomputing.com/"> + <title>PyQt Web Site</title> + </bookmark> + <folder folded="no"> + <title>Qt Web Sites</title> + <bookmark href="http://www.qt.io//"> + <title>Qt Web Site</title> + </bookmark> + <bookmark href="http://www.qt.io/developers/"> + <title>Qt Developers</title> + </bookmark> + <bookmark href="http://doc.qt.io/"> + <title>Qt Documentation</title> + </bookmark> + <bookmark href="http://blog.qt.io/"> + <title>Qt Blog</title> + </bookmark> + <bookmark href="http://forum.qt.io/"> + <title>Qt Forum</title> + </bookmark> + <bookmark href="http://planet.qt.io/"> + <title>Planet Qt</title> + </bookmark> + <bookmark href="http://qtcentre.org/"> + <title>Qt Centre</title> + </bookmark> + <bookmark href="http://qt-apps.org/"> + <title>Qt-Apps.org</title> + </bookmark> + </folder> + <folder folded="no"> + <title>Python Web Sites</title> + <bookmark href="http://www.python.org/"> + <title>Python Language Website</title> + </bookmark> + <bookmark href="http://pypi.python.org/pypi"> + <title>Python Package Index: PyPI</title> + </bookmark> + </folder> + </folder> + <folder folded="yes"> + <title>Bookmarks Menu</title> + <bookmark href="http://eric-ide.python-projects.org/"> + <title>Eric Web Site</title> + </bookmark> + <bookmark href="http://www.riverbankcomputing.com/"> + <title>PyQt4 Web Site</title> + </bookmark> + <bookmark href="javascript:location.href='mailto:?SUBJECT=' + document.title + '&BODY=' + escape(location.href);"> + <title>Send Link</title> + </bookmark> + </folder> +</xbel>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/DefaultBookmarks_rc.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +# Resource object code +# +# Created by: The Resource Compiler for PyQt5 (Qt v5.4.1) +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore + +qt_resource_data = b"\ +\x00\x00\x01\xf1\ +\x00\ +\x00\x09\x00\x78\x9c\xdd\x96\x51\x6f\x9b\x30\x10\xc7\xdf\xfb\x29\ +\x3c\x1e\x9a\x4d\x15\xd0\x49\x7b\x98\x52\x48\x34\x92\x4c\xea\xd4\ +\xaa\x54\x69\x55\xf5\xd1\x98\x0b\x71\x01\xdb\x35\x26\x09\xdf\x7e\ +\x86\xb0\x96\xa4\x2c\xa4\x1d\x4f\xe3\xc5\xd8\x77\xbe\xdf\x9d\x8d\ +\xff\xc6\x19\x6f\xd2\x04\xad\x40\x66\x94\x33\xd7\xf8\x6a\x9d\x1b\ +\x08\x18\xe1\x21\x65\x91\x6b\xe4\x6a\x61\x7e\x37\xc6\xa3\x13\xe7\ +\xd3\xf4\x66\x72\xf7\xe8\xcf\xd0\x26\x80\x44\xf7\xcb\x66\x77\xda\ +\xe8\x04\xe9\xc7\x59\xf0\x24\x04\x89\xaa\x26\x74\x0d\xc6\x6b\x43\ +\x65\x54\x54\x25\x30\xf2\x38\x8f\x53\x2c\xe3\x0c\x79\x58\x3a\xf6\ +\x76\xf0\xd5\x29\xa8\xcd\x68\x29\x61\xe1\x1a\x4b\xa5\xc4\xd0\xb6\ +\x41\x52\x62\xd2\x10\x2c\x51\xa8\x25\x67\xa6\x90\xfc\x09\x88\xca\ +\x2c\x2e\x23\xbb\xc1\x68\x70\x66\x7a\x0a\x7a\x80\x00\xcd\xa9\x82\ +\xb7\x1c\xfb\x0f\xa8\x93\xbd\x5e\xaf\x2d\x49\x75\xb5\x01\x66\x31\ +\xe1\xa9\xc8\x95\x5e\x1e\x4b\xbf\xfd\x85\xec\x17\xb7\xea\x9d\xe4\ +\x43\xeb\xd6\x88\xdc\x88\x9b\xbd\x09\xdc\x51\xc2\xb3\xb2\x28\xb7\ +\xf7\x53\x6e\x0f\xde\x1e\xbb\x25\xf1\xa3\x98\x21\xac\x20\xe1\x42\ +\x7f\x2e\x87\xe9\xd3\x17\xbf\x3e\xf8\x21\x27\x35\xff\x30\x94\x93\ +\x3c\x05\xa6\xb0\xd2\xdf\x72\x1f\xdc\x20\xe1\xd1\x31\x60\x4f\xfb\ +\xf5\xc1\x5b\x70\x99\xa7\xc7\x00\x7f\x96\x8e\x7d\x10\x45\x82\x19\ +\xa8\x4e\xa4\x5f\xb9\xa1\x5b\xd5\x07\xf3\x59\x11\xbd\x49\x12\xda\ +\x0e\xfc\x6e\x99\x93\xca\xaf\x1f\xa6\x89\x85\x68\xd5\x98\x1d\xa4\ +\xf9\xa3\xf6\x3a\x1a\xea\xd8\xdb\x03\xff\x7e\x05\xf0\x2b\xfd\xfb\ +\xb8\x0a\x6c\xf5\xb3\xa3\xa4\x1a\x72\x85\x59\x94\xe3\x08\x4a\x5a\ +\xd6\x93\x2a\x88\x42\xd0\x66\x12\x65\xbf\x33\x11\x1f\x93\xb8\xcc\ +\xe3\x92\x85\xb0\x19\x22\xbf\xf0\x2f\x3f\xb8\xd4\x7b\xbd\xbd\x45\ +\x2f\x20\x3b\x74\x5f\x5d\x03\xcb\xff\xdb\x0b\xeb\xdb\xbf\xa1\x9f\ +\xf0\x0a\x67\x44\x52\xa1\x86\x09\x27\x95\x98\x5a\x95\x65\x90\x62\ +\x9a\x28\x3e\x1c\xcf\xef\xbd\x5f\xb3\xc9\x9d\x3b\x40\x67\x28\xac\ +\x45\xd7\xaa\x48\x7a\x60\x70\x8a\x53\x71\xe1\xdd\x4c\x1f\x2b\x3b\ +\x64\x04\x0b\xf8\xbc\x13\xe9\xcb\x45\x7b\xf2\x73\x60\x21\xba\xa2\ +\x2c\xee\xcc\xfb\x75\xf3\x1d\x7b\xfb\x23\xf3\x1b\xc5\xa5\x8d\x58\ +\ +" + +qt_resource_name = b"\ +\x00\x15\ +\x0c\xd3\x2e\x3c\ +\x00\x44\ +\x00\x65\x00\x66\x00\x61\x00\x75\x00\x6c\x00\x74\x00\x42\x00\x6f\x00\x6f\x00\x6b\x00\x6d\x00\x61\x00\x72\x00\x6b\x00\x73\x00\x2e\ +\x00\x78\x00\x62\x00\x65\x00\x6c\ +" + +qt_resource_struct = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/NsHtmlReader.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a class to read Netscape HTML bookmark files. +""" + +from __future__ import unicode_literals +try: + str = unicode +except NameError: + pass + +from PyQt5.QtCore import QObject, QIODevice, QFile, QRegExp, Qt, QDateTime + +from .BookmarkNode import BookmarkNode + +import Utilities + + +class NsHtmlReader(QObject): + """ + Class implementing a reader object for Netscape HTML bookmark files. + """ + indentSize = 4 + + def __init__(self): + """ + Constructor + """ + super(NsHtmlReader, self).__init__() + + self.__folderRx = QRegExp("<DT><H3(.*)>(.*)</H3>", Qt.CaseInsensitive) + self.__folderRx.setMinimal(True) + + self.__endFolderRx = QRegExp("</DL>", Qt.CaseInsensitive) + + self.__bookmarkRx = QRegExp("<DT><A(.*)>(.*)</A>", Qt.CaseInsensitive) + self.__bookmarkRx.setMinimal(True) + + self.__descRx = QRegExp("<DD>(.*)", Qt.CaseInsensitive) + + self.__separatorRx = QRegExp("<HR>", Qt.CaseInsensitive) + + self.__urlRx = QRegExp('HREF="(.*)"', Qt.CaseInsensitive) + self.__urlRx.setMinimal(True) + + self.__addedRx = QRegExp('ADD_DATE="(\d*)"', Qt.CaseInsensitive) + self.__addedRx.setMinimal(True) + + self.__modifiedRx = QRegExp( + 'LAST_MODIFIED="(\d*)"', Qt.CaseInsensitive) + self.__modifiedRx.setMinimal(True) + + self.__visitedRx = QRegExp('LAST_VISIT="(\d*)"', Qt.CaseInsensitive) + self.__visitedRx.setMinimal(True) + + self.__foldedRx = QRegExp("FOLDED", Qt.CaseInsensitive) + + def read(self, fileNameOrDevice): + """ + Public method to read a Netscape HTML bookmark file. + + @param fileNameOrDevice name of the file to read (string) + or reference to the device to read (QIODevice) + @return reference to the root node (BookmarkNode) + """ + if isinstance(fileNameOrDevice, QIODevice): + dev = fileNameOrDevice + else: + f = QFile(fileNameOrDevice) + if not f.exists(): + return BookmarkNode(BookmarkNode.Root) + f.open(QFile.ReadOnly) + dev = f + + folders = [] + lastNode = None + + root = BookmarkNode(BookmarkNode.Root) + folders.append(root) + + while not dev.atEnd(): + line = str(dev.readLine(), encoding="utf-8").rstrip() + if self.__folderRx.indexIn(line) != -1: + # folder definition + arguments = self.__folderRx.cap(1) + name = self.__folderRx.cap(2) + node = BookmarkNode(BookmarkNode.Folder, folders[-1]) + node.title = Utilities.html_udecode(name) + node.expanded = self.__foldedRx.indexIn(arguments) == -1 + if self.__addedRx.indexIn(arguments) != -1: + node.added = QDateTime.fromTime_t( + int(self.__addedRx.cap(1))) + folders.append(node) + lastNode = node + + elif self.__endFolderRx.indexIn(line) != -1: + # end of folder definition + folders.pop() + + elif self.__bookmarkRx.indexIn(line) != -1: + # bookmark definition + arguments = self.__bookmarkRx.cap(1) + name = self.__bookmarkRx.cap(2) + node = BookmarkNode(BookmarkNode.Bookmark, folders[-1]) + node.title = Utilities.html_udecode(name) + if self.__urlRx.indexIn(arguments) != -1: + node.url = self.__urlRx.cap(1) + if self.__addedRx.indexIn(arguments) != -1: + node.added = QDateTime.fromTime_t( + int(self.__addedRx.cap(1))) + if self.__modifiedRx.indexIn(arguments) != -1: + node.modified = QDateTime.fromTime_t( + int(self.__modifiedRx.cap(1))) + if self.__visitedRx.indexIn(arguments) != -1: + node.visited = QDateTime.fromTime_t( + int(self.__visitedRx.cap(1))) + lastNode = node + + elif self.__descRx.indexIn(line) != -1: + # description + if lastNode: + lastNode.desc = Utilities.html_udecode( + self.__descRx.cap(1)) + + elif self.__separatorRx.indexIn(line) != -1: + # separator definition + BookmarkNode(BookmarkNode.Separator, folders[-1]) + + return root
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/NsHtmlWriter.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a class to write Netscape HTML bookmark files. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QObject, QIODevice, QFile + +from .BookmarkNode import BookmarkNode + +import Utilities + + +class NsHtmlWriter(QObject): + """ + Class implementing a writer object to generate Netscape HTML bookmark + files. + """ + indentSize = 4 + + def __init__(self): + """ + Constructor + """ + super(NsHtmlWriter, self).__init__() + + def write(self, fileNameOrDevice, root): + """ + Public method to write an Netscape HTML bookmark file. + + @param fileNameOrDevice name of the file to write (string) + or device to write to (QIODevice) + @param root root node of the bookmark tree (BookmarkNode) + @return flag indicating success (boolean) + """ + if isinstance(fileNameOrDevice, QIODevice): + f = fileNameOrDevice + else: + f = QFile(fileNameOrDevice) + if root is None or not f.open(QFile.WriteOnly): + return False + + self.__dev = f + return self.__write(root) + + def __write(self, root): + """ + Private method to write an Netscape HTML bookmark file. + + @param root root node of the bookmark tree (BookmarkNode) + @return flag indicating success (boolean) + """ + self.__dev.write( + "<!DOCTYPE NETSCAPE-Bookmark-file-1>\n" + "<!-- This is an automatically generated file.\n" + " It will be read and overwritten.\n" + " DO NOT EDIT! -->\n" + "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;" + " charset=UTF-8\">\n" + "<TITLE>Bookmarks</TITLE>\n" + "<H1>Bookmarks</H1>\n" + "\n" + "<DL><p>\n") + if root.type() == BookmarkNode.Root: + for child in root.children(): + self.__writeItem(child, self.indentSize) + else: + self.__writeItem(root, self.indentSize) + self.__dev.write("</DL><p>\n") + return True + + def __writeItem(self, node, indent): + """ + Private method to write an entry for a node. + + @param node reference to the node to be written (BookmarkNode) + @param indent size of the indentation (integer) + """ + if node.type() == BookmarkNode.Folder: + self.__writeFolder(node, indent) + elif node.type() == BookmarkNode.Bookmark: + self.__writeBookmark(node, indent) + elif node.type() == BookmarkNode.Separator: + self.__writeSeparator(indent) + + def __writeSeparator(self, indent): + """ + Private method to write a separator. + + @param indent size of the indentation (integer) + """ + self.__dev.write(" " * indent) + self.__dev.write("<HR>\n") + + def __writeBookmark(self, node, indent): + """ + Private method to write a bookmark node. + + @param node reference to the node to be written (BookmarkNode) + @param indent size of the indentation (integer) + """ + if node.added.isValid(): + added = " ADD_DATE=\"{0}\"".format(node.added.toTime_t()) + else: + added = "" + if node.modified.isValid(): + modified = " LAST_MODIFIED=\"{0}\"".format( + node.modified.toTime_t()) + else: + modified = "" + if node.visited.isValid(): + visited = " LAST_VISIT=\"{0}\"".format(node.visited.toTime_t()) + else: + visited = "" + + self.__dev.write(" " * indent) + self.__dev.write("<DT><A HREF=\"{0}\"{1}{2}{3}>{4}</A>\n".format( + node.url, added, modified, visited, + Utilities.html_uencode(node.title) + )) + + if node.desc: + self.__dev.write(" " * indent) + self.__dev.write("<DD>{0}\n".format( + Utilities.html_uencode("".join(node.desc.splitlines())))) + + def __writeFolder(self, node, indent): + """ + Private method to write a bookmark node. + + @param node reference to the node to be written (BookmarkNode) + @param indent size of the indentation (integer) + """ + if node.expanded: + folded = "" + else: + folded = " FOLDED" + + if node.added.isValid(): + added = " ADD_DATE=\"{0}\"".format(node.added.toTime_t()) + else: + added = "" + + self.__dev.write(" " * indent) + self.__dev.write("<DT><H3{0}{1}>{2}</H3>\n".format( + folded, added, Utilities.html_uencode(node.title) + )) + + if node.desc: + self.__dev.write(" " * indent) + self.__dev.write("<DD>{0}\n".format( + "".join(node.desc.splitlines()))) + + self.__dev.write(" " * indent) + self.__dev.write("<DL><p>\n") + + for child in node.children(): + self.__writeItem(child, indent + self.indentSize) + + self.__dev.write(" " * indent) + self.__dev.write("</DL><p>\n")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/XbelReader.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,235 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a class to read XBEL bookmark files. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QXmlStreamReader, QXmlStreamEntityResolver, \ + QIODevice, QFile, QCoreApplication, QXmlStreamNamespaceDeclaration, \ + QDateTime, Qt + +from .BookmarkNode import BookmarkNode + + +class XmlEntityResolver(QXmlStreamEntityResolver): + """ + Class implementing an XML entity resolver for bookmark files. + """ + def resolveUndeclaredEntity(self, entity): + """ + Public method to resolve undeclared entities. + + @param entity entity to be resolved (string) + @return resolved entity (string) + """ + if entity == "nbsp": + return " " + return "" + + +class XbelReader(QXmlStreamReader): + """ + Class implementing a reader object for XBEL bookmark files. + """ + def __init__(self): + """ + Constructor + """ + super(XbelReader, self).__init__() + + self.__resolver = XmlEntityResolver() + self.setEntityResolver(self.__resolver) + + def read(self, fileNameOrDevice): + """ + Public method to read an XBEL bookmark file. + + @param fileNameOrDevice name of the file to read (string) + or reference to the device to read (QIODevice) + @return reference to the root node (BookmarkNode) + """ + if isinstance(fileNameOrDevice, QIODevice): + self.setDevice(fileNameOrDevice) + else: + f = QFile(fileNameOrDevice) + if not f.exists(): + return BookmarkNode(BookmarkNode.Root) + f.open(QFile.ReadOnly) + self.setDevice(f) + + root = BookmarkNode(BookmarkNode.Root) + while not self.atEnd(): + self.readNext() + if self.isStartElement(): + version = self.attributes().value("version") + if self.name() == "xbel" and \ + (not version or version == "1.0"): + self.__readXBEL(root) + else: + self.raiseError(QCoreApplication.translate( + "XbelReader", + "The file is not an XBEL version 1.0 file.")) + + return root + + def __readXBEL(self, node): + """ + Private method to read and parse the XBEL file. + + @param node reference to the node to attach to (BookmarkNode) + """ + if not self.isStartElement() and self.name() != "xbel": + return + + while not self.atEnd(): + self.readNext() + if self.isEndElement(): + break + + if self.isStartElement(): + if self.name() == "folder": + self.__readFolder(node) + elif self.name() == "bookmark": + self.__readBookmarkNode(node) + elif self.name() == "separator": + self.__readSeparator(node) + else: + self.__skipUnknownElement() + + def __readFolder(self, node): + """ + Private method to read and parse a folder subtree. + + @param node reference to the node to attach to (BookmarkNode) + """ + if not self.isStartElement() and self.name() != "folder": + return + + folder = BookmarkNode(BookmarkNode.Folder, node) + folder.expanded = self.attributes().value("folded") == "no" + folder.added = QDateTime.fromString( + self.attributes().value("added"), Qt.ISODate) + + while not self.atEnd(): + self.readNext() + if self.isEndElement(): + break + + if self.isStartElement(): + if self.name() == "title": + self.__readTitle(folder) + elif self.name() == "desc": + self.__readDescription(folder) + elif self.name() == "folder": + self.__readFolder(folder) + elif self.name() == "bookmark": + self.__readBookmarkNode(folder) + elif self.name() == "separator": + self.__readSeparator(folder) + elif self.name() == "info": + self.__readInfo() + else: + self.__skipUnknownElement() + + def __readTitle(self, node): + """ + Private method to read the title element. + + @param node reference to the bookmark node title belongs to + (BookmarkNode) + """ + if not self.isStartElement() and self.name() != "title": + return + + node.title = self.readElementText() + + def __readDescription(self, node): + """ + Private method to read the desc element. + + @param node reference to the bookmark node desc belongs to + (BookmarkNode) + """ + if not self.isStartElement() and self.name() != "desc": + return + + node.desc = self.readElementText() + + def __readSeparator(self, node): + """ + Private method to read a separator element. + + @param node reference to the bookmark node the separator belongs to + (BookmarkNode) + """ + sep = BookmarkNode(BookmarkNode.Separator, node) + sep.added = QDateTime.fromString( + self.attributes().value("added"), Qt.ISODate) + + # empty elements have a start and end element + while not self.atEnd(): + self.readNext() + if self.isEndElement(): + break + + if self.isStartElement(): + if self.name() == "info": + self.__readInfo() + else: + self.__skipUnknownElement() + + def __readBookmarkNode(self, node): + """ + Private method to read and parse a bookmark subtree. + + @param node reference to the node to attach to (BookmarkNode) + """ + if not self.isStartElement() and self.name() != "bookmark": + return + + bookmark = BookmarkNode(BookmarkNode.Bookmark, node) + bookmark.url = self.attributes().value("href") + bookmark.added = QDateTime.fromString( + self.attributes().value("added"), Qt.ISODate) + bookmark.modified = QDateTime.fromString( + self.attributes().value("modified"), Qt.ISODate) + bookmark.visited = QDateTime.fromString( + self.attributes().value("visited"), Qt.ISODate) + + while not self.atEnd(): + self.readNext() + if self.isEndElement(): + break + + if self.isStartElement(): + if self.name() == "title": + self.__readTitle(bookmark) + elif self.name() == "desc": + self.__readDescription(bookmark) + elif self.name() == "info": + self.__readInfo() + else: + self.__skipUnknownElement() + + if not bookmark.title: + bookmark.title = QCoreApplication.translate( + "XbelReader", "Unknown title") + + def __readInfo(self): + """ + Private method to read and parse an info subtree. + """ + self.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration( + "bookmark", "http://www.python.org")) + self.skipCurrentElement() + + def __skipUnknownElement(self): + """ + Private method to skip over all unknown elements. + """ + self.skipCurrentElement()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/XbelWriter.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a class to write XBEL bookmark files. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QXmlStreamWriter, QIODevice, QFile, Qt + +from .BookmarkNode import BookmarkNode + + +class XbelWriter(QXmlStreamWriter): + """ + Class implementing a writer object to generate XBEL bookmark files. + """ + def __init__(self): + """ + Constructor + """ + super(XbelWriter, self).__init__() + + self.setAutoFormatting(True) + + def write(self, fileNameOrDevice, root): + """ + Public method to write an XBEL bookmark file. + + @param fileNameOrDevice name of the file to write (string) + or device to write to (QIODevice) + @param root root node of the bookmark tree (BookmarkNode) + @return flag indicating success (boolean) + """ + if isinstance(fileNameOrDevice, QIODevice): + f = fileNameOrDevice + else: + f = QFile(fileNameOrDevice) + if root is None or not f.open(QFile.WriteOnly): + return False + + self.setDevice(f) + return self.__write(root) + + def __write(self, root): + """ + Private method to write an XBEL bookmark file. + + @param root root node of the bookmark tree (BookmarkNode) + @return flag indicating success (boolean) + """ + self.writeStartDocument() + self.writeDTD("<!DOCTYPE xbel>") + self.writeStartElement("xbel") + self.writeAttribute("version", "1.0") + if root.type() == BookmarkNode.Root: + for child in root.children(): + self.__writeItem(child) + else: + self.__writeItem(root) + + self.writeEndDocument() + return True + + def __writeItem(self, node): + """ + Private method to write an entry for a node. + + @param node reference to the node to be written (BookmarkNode) + """ + if node.type() == BookmarkNode.Folder: + self.writeStartElement("folder") + if node.added.isValid(): + self.writeAttribute("added", node.added.toString(Qt.ISODate)) + self.writeAttribute("folded", node.expanded and "no" or "yes") + self.writeTextElement("title", node.title) + for child in node.children(): + self.__writeItem(child) + self.writeEndElement() + elif node.type() == BookmarkNode.Bookmark: + self.writeStartElement("bookmark") + if node.url: + self.writeAttribute("href", node.url) + if node.added.isValid(): + self.writeAttribute("added", node.added.toString(Qt.ISODate)) + if node.modified.isValid(): + self.writeAttribute( + "modified", node.modified.toString(Qt.ISODate)) + if node.visited.isValid(): + self.writeAttribute( + "visited", node.visited.toString(Qt.ISODate)) + self.writeTextElement("title", node.title) + if node.desc: + self.writeTextElement("desc", node.desc) + self.writeEndElement() + elif node.type() == BookmarkNode.Separator: + self.writeEmptyElement("separator") + if node.added.isValid(): + self.writeAttribute("added", node.added.toString(Qt.ISODate))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Bookmarks/__init__.py Thu Feb 11 20:27:07 2016 +0100 @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package implementing the bookmarks system. +"""
--- a/WebBrowser/Tools/WebIconProvider.py Wed Feb 10 20:00:09 2016 +0100 +++ b/WebBrowser/Tools/WebIconProvider.py Thu Feb 11 20:27:07 2016 +0100 @@ -183,7 +183,7 @@ self.load() urlStr = self.__urlToString(url) - if url in self.__iconsDB: + if urlStr in self.__iconsDB: return self.__iconsDB[urlStr] else: return UI.PixmapCache.getIcon("defaultIcon.png")
--- a/WebBrowser/UrlBar/UrlBar.py Wed Feb 10 20:00:09 2016 +0100 +++ b/WebBrowser/UrlBar/UrlBar.py Thu Feb 11 20:27:07 2016 +0100 @@ -55,10 +55,9 @@ ## self.__privateMode = QWebSettings.globalSettings().testAttribute( ## QWebSettings.PrivateBrowsingEnabled) - # TODO: Bookmarks -## self.__bmActiveIcon = UI.PixmapCache.getIcon("bookmark16.png") -## self.__bmInactiveIcon = QIcon( -## self.__bmActiveIcon.pixmap(16, 16, QIcon.Disabled)) + self.__bmActiveIcon = UI.PixmapCache.getIcon("bookmark16.png") + self.__bmInactiveIcon = QIcon( + self.__bmActiveIcon.pixmap(16, 16, QIcon.Disabled)) self.__favicon = FavIconLabel(self) self.addWidget(self.__favicon, E5LineEdit.LeftSide) @@ -81,18 +80,16 @@ ## self.addWidget(self.__rssButton, E5LineEdit.RightSide) ## self.__rssButton.setVisible(False) - # TODO: Bookmarks -## self.__bookmarkButton = E5LineEditButton(self) -## self.addWidget(self.__bookmarkButton, E5LineEdit.RightSide) -## self.__bookmarkButton.setVisible(False) + self.__bookmarkButton = E5LineEditButton(self) + self.addWidget(self.__bookmarkButton, E5LineEdit.RightSide) + self.__bookmarkButton.setVisible(False) self.__clearButton = E5LineEditButton(self) self.__clearButton.setIcon(UI.PixmapCache.getIcon("clearLeft.png")) self.addWidget(self.__clearButton, E5LineEdit.RightSide) self.__clearButton.setVisible(False) - # TODO: Bookmarks -## self.__bookmarkButton.clicked.connect(self.__showBookmarkInfo) + self.__bookmarkButton.clicked.connect(self.__showBookmarkInfo) # TODO: RSS ## self.__rssButton.clicked.connect(self.__rssClicked) # TODO: Privacy @@ -101,15 +98,14 @@ ## self.__mw.privacyChanged.connect(self.__privacyButton.setVisible) self.textChanged.connect(self.__textChanged) - # TODO: Bookmarks -## Helpviewer.HelpWindow.HelpWindow.bookmarksManager()\ -## .entryChanged.connect(self.__bookmarkChanged) -## Helpviewer.HelpWindow.HelpWindow.bookmarksManager()\ -## .entryAdded.connect(self.__bookmarkChanged) -## Helpviewer.HelpWindow.HelpWindow.bookmarksManager()\ -## .entryRemoved.connect(self.__bookmarkChanged) + self.__mw.bookmarksManager().entryChanged.connect( + self.__bookmarkChanged) + self.__mw.bookmarksManager().entryAdded.connect( + self.__bookmarkChanged) + self.__mw.bookmarksManager().entryRemoved.connect( + self.__bookmarkChanged) # TODO: Speed Dial -## Helpviewer.HelpWindow.HelpWindow.speedDial().pagesChanged.connect( +## self.__mw.speedDial().pagesChanged.connect( ## self.__bookmarkChanged) def setBrowser(self, browser): @@ -159,42 +155,39 @@ pass # TODO: SSL ## self.__sslLabel.setVisible(False) - # TODO: Bookmarks -## self.__bookmarkButton.setVisible(False) + self.__bookmarkButton.setVisible(False) - # TODO: Bookmarks -## def __checkBookmark(self): -## """ -## Private slot to check the current URL for the bookmarked state. -## """ -## manager = Helpviewer.HelpWindow.HelpWindow.bookmarksManager() -## if manager.bookmarkForUrl(self.__browser.url()) is not None: -## self.__bookmarkButton.setIcon(self.__bmActiveIcon) -## bookmarks = manager.bookmarksForUrl(self.__browser.url()) -## from Helpviewer.Bookmarks.BookmarkNode import BookmarkNode -## for bookmark in bookmarks: -## manager.setTimestamp(bookmark, BookmarkNode.TsVisited, -## QDateTime.currentDateTime()) -## elif Helpviewer.HelpWindow.HelpWindow.speedDial()\ + def __checkBookmark(self): + """ + Private slot to check the current URL for the bookmarked state. + """ + manager = self.__mw.bookmarksManager() + if manager.bookmarkForUrl(self.__browser.url()) is not None: + self.__bookmarkButton.setIcon(self.__bmActiveIcon) + bookmarks = manager.bookmarksForUrl(self.__browser.url()) + from Helpviewer.Bookmarks.BookmarkNode import BookmarkNode + for bookmark in bookmarks: + manager.setTimestamp(bookmark, BookmarkNode.TsVisited, + QDateTime.currentDateTime()) + # TODO: SpeedDial +## elif self.__mw.speedDial()\ ## .pageForUrl(self.__browser.url()).url != "": ## self.__bookmarkButton.setIcon(self.__bmActiveIcon) -## else: -## self.__bookmarkButton.setIcon(self.__bmInactiveIcon) -## + else: + self.__bookmarkButton.setIcon(self.__bmInactiveIcon) + def __loadFinished(self, ok): """ Private slot to set some data after the page was loaded. @param ok flag indicating a successful load (boolean) """ - pass ## try: - # TODO: Bookmarks -## if self.__browser.url().scheme() in ["eric", "about"]: -## self.__bookmarkButton.setVisible(False) -## else: -## self.__checkBookmark() -## self.__bookmarkButton.setVisible(True) + if self.__browser.url().scheme() in ["eric", "about"]: + self.__bookmarkButton.setVisible(False) + else: + self.__checkBookmark() + self.__bookmarkButton.setVisible(True) # TODO: RSS ## if ok: @@ -260,38 +253,38 @@ """ self.update() - # TODO: Bookmarks -## def __showBookmarkInfo(self): -## """ -## Private slot to show a dialog with some bookmark info. -## """ -## from .BookmarkActionSelectionDialog import \ -## BookmarkActionSelectionDialog -## url = self.__browser.url() -## dlg = BookmarkActionSelectionDialog(url) -## if dlg.exec_() == QDialog.Accepted: -## action = dlg.getAction() -## if action == BookmarkActionSelectionDialog.AddBookmark: -## self.__browser.addBookmark() -## elif action == BookmarkActionSelectionDialog.EditBookmark: -## bookmark = Helpviewer.HelpWindow.HelpWindow.bookmarksManager()\ -## .bookmarkForUrl(url) -## from .BookmarkInfoDialog import BookmarkInfoDialog -## dlg = BookmarkInfoDialog(bookmark, self.__browser) -## dlg.exec_() + def __showBookmarkInfo(self): + """ + Private slot to show a dialog with some bookmark info. + """ + from .BookmarkActionSelectionDialog import \ + BookmarkActionSelectionDialog + url = self.__browser.url() + dlg = BookmarkActionSelectionDialog(url) + if dlg.exec_() == QDialog.Accepted: + action = dlg.getAction() + if action == BookmarkActionSelectionDialog.AddBookmark: + self.__browser.addBookmark() + elif action == BookmarkActionSelectionDialog.EditBookmark: + bookmark = self.__mw.bookmarksManager()\ + .bookmarkForUrl(url) + from .BookmarkInfoDialog import BookmarkInfoDialog + dlg = BookmarkInfoDialog(bookmark, self.__browser) + dlg.exec_() + # TODO: SpeedDial ## elif action == BookmarkActionSelectionDialog.AddSpeeddial: -## Helpviewer.HelpWindow.HelpWindow.speedDial().addPage( +## self.__mw.speedDial().addPage( ## url, self.__browser.title()) ## elif action == BookmarkActionSelectionDialog.RemoveSpeeddial: -## Helpviewer.HelpWindow.HelpWindow.speedDial().removePage(url) -## -## @pyqtSlot() -## def __bookmarkChanged(self): -## """ -## Private slot to handle bookmark or speed dial changes. -## """ -## self.__checkBookmark() -## +## self.__mw.speedDial().removePage(url) + + @pyqtSlot() + def __bookmarkChanged(self): + """ + Private slot to handle bookmark or speed dial changes. + """ + self.__checkBookmark() + def paintEvent(self, evt): """ Protected method handling a paint event.
--- a/WebBrowser/WebBrowserTabWidget.py Wed Feb 10 20:00:09 2016 +0100 +++ b/WebBrowser/WebBrowserTabWidget.py Thu Feb 11 20:27:07 2016 +0100 @@ -806,10 +806,7 @@ self.setTabIcon( self.indexOf(browser), browser.icon()) - # TODO: Bookmarks -## import WebBrowser.WebBrowserWindow -## WebBrowser.WebBrowserWindow.WebBrowserWindow.bookmarksManager()\ -## .iconChanged(url) + self.__mainWindow.bookmarksManager().iconChanged(browser.url()) def getSourceFileList(self): """
--- a/WebBrowser/WebBrowserView.py Wed Feb 10 20:00:09 2016 +0100 +++ b/WebBrowser/WebBrowserView.py Thu Feb 11 20:27:07 2016 +0100 @@ -656,11 +656,10 @@ ## menu.addAction( ## UI.PixmapCache.getIcon("download.png"), ## self.tr("Save Lin&k"), self.__downloadLink) - # TODO: Bookmarks -## menu.addAction( -## UI.PixmapCache.getIcon("bookmark22.png"), -## self.tr("Bookmark this Link"), self.__bookmarkLink)\ -## .setData(hitTest.linkUrl()) + menu.addAction( + UI.PixmapCache.getIcon("bookmark22.png"), + self.tr("Bookmark this Link"), self.__bookmarkLink)\ + .setData(hitTest.linkUrl()) menu.addSeparator() menu.addAction( UI.PixmapCache.getIcon("editCopy.png"), @@ -849,10 +848,9 @@ ## menu.addAction(self.__mw.saveAsAct) ## menu.addSeparator() - # TODO: Bookmarks -## menu.addAction( -## UI.PixmapCache.getIcon("bookmark22.png"), -## self.tr("Bookmark this Page"), self.addBookmark) + menu.addAction( + UI.PixmapCache.getIcon("bookmark22.png"), + self.tr("Bookmark this Page"), self.addBookmark) menu.addAction( UI.PixmapCache.getIcon("editCopy.png"), self.tr("Copy Page Link"), self.__copyLink).setData(self.url()) @@ -949,20 +947,19 @@ self.setSource(url) self.__ctrlPressed = False - # TODO: Bookmarks -## def __bookmarkLink(self): -## """ -## Private slot to bookmark a link via the context menu. -## """ -## act = self.sender() -## url = act.data() -## if url.isEmpty(): -## return -## -## from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog -## dlg = AddBookmarkDialog() -## dlg.setUrl(bytes(url.toEncoded()).decode()) -## dlg.exec_() + def __bookmarkLink(self): + """ + Private slot to bookmark a link via the context menu. + """ + act = self.sender() + url = act.data() + if url.isEmpty(): + return + + from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog + dlg = AddBookmarkDialog() + dlg.setUrl(bytes(url.toEncoded()).decode()) + dlg.exec_() def __sendLink(self): """ @@ -1108,19 +1105,18 @@ ## self.__inspector.deleteLater() ## self.__inspector = None - # TODO: Bookmarks -## def addBookmark(self): -## """ -## Public slot to bookmark the current page. -## """ -## from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog -## dlg = AddBookmarkDialog() -## dlg.setUrl(bytes(self.url().toEncoded()).decode()) -## dlg.setTitle(self.title()) -## meta = self.page().mainFrame().metaData() -## if "description" in meta: -## dlg.setDescription(meta["description"][0]) -## dlg.exec_() + def addBookmark(self): + """ + Public slot to bookmark the current page. + """ + from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog + dlg = AddBookmarkDialog() + dlg.setUrl(bytes(self.url().toEncoded()).decode()) + dlg.setTitle(self.title()) + meta = self.page().mainFrame().metaData() + if "description" in meta: + dlg.setDescription(meta["description"][0]) + dlg.exec_() def dragEnterEvent(self, evt): """
--- a/WebBrowser/WebBrowserWindow.py Wed Feb 10 20:00:09 2016 +0100 +++ b/WebBrowser/WebBrowserWindow.py Thu Feb 11 20:27:07 2016 +0100 @@ -83,7 +83,7 @@ _networkManager = None ## _cookieJar = None ## _helpEngine = None -## _bookmarksManager = None + _bookmarksManager = None ## _historyManager = None ## _passwordManager = None ## _adblockManager = None @@ -624,37 +624,36 @@ ## self.__saveVisiblePageScreen) ## self.__actions.append(self.saveVisiblePageScreenAct) - # TODO: Bookmarks -## bookmarksManager = self.bookmarksManager() -## self.importBookmarksAct = E5Action( -## self.tr('Import Bookmarks'), -## self.tr('&Import Bookmarks...'), -## 0, 0, self, 'webbrowser_file_import_bookmarks') -## self.importBookmarksAct.setStatusTip( -## self.tr('Import bookmarks from other browsers')) -## self.importBookmarksAct.setWhatsThis(self.tr( -## """<b>Import Bookmarks</b>""" -## """<p>Import bookmarks from other browsers.</p>""" -## )) -## if not self.__initShortcutsOnly: -## self.importBookmarksAct.triggered.connect( -## bookmarksManager.importBookmarks) -## self.__actions.append(self.importBookmarksAct) -## -## self.exportBookmarksAct = E5Action( -## self.tr('Export Bookmarks'), -## self.tr('&Export Bookmarks...'), -## 0, 0, self, 'webbrowser_file_export_bookmarks') -## self.exportBookmarksAct.setStatusTip( -## self.tr('Export the bookmarks into a file')) -## self.exportBookmarksAct.setWhatsThis(self.tr( -## """<b>Export Bookmarks</b>""" -## """<p>Export the bookmarks into a file.</p>""" -## )) -## if not self.__initShortcutsOnly: -## self.exportBookmarksAct.triggered.connect( -## bookmarksManager.exportBookmarks) -## self.__actions.append(self.exportBookmarksAct) + bookmarksManager = self.bookmarksManager() + self.importBookmarksAct = E5Action( + self.tr('Import Bookmarks'), + self.tr('&Import Bookmarks...'), + 0, 0, self, 'webbrowser_file_import_bookmarks') + self.importBookmarksAct.setStatusTip( + self.tr('Import bookmarks from other browsers')) + self.importBookmarksAct.setWhatsThis(self.tr( + """<b>Import Bookmarks</b>""" + """<p>Import bookmarks from other browsers.</p>""" + )) + if not self.__initShortcutsOnly: + self.importBookmarksAct.triggered.connect( + bookmarksManager.importBookmarks) + self.__actions.append(self.importBookmarksAct) + + self.exportBookmarksAct = E5Action( + self.tr('Export Bookmarks'), + self.tr('&Export Bookmarks...'), + 0, 0, self, 'webbrowser_file_export_bookmarks') + self.exportBookmarksAct.setStatusTip( + self.tr('Export the bookmarks into a file')) + self.exportBookmarksAct.setWhatsThis(self.tr( + """<b>Export Bookmarks</b>""" + """<p>Export the bookmarks into a file.</p>""" + )) + if not self.__initShortcutsOnly: + self.exportBookmarksAct.triggered.connect( + bookmarksManager.exportBookmarks) + self.__actions.append(self.exportBookmarksAct) # TODO: print stuff ## self.printAct = E5Action( @@ -996,69 +995,68 @@ self.__searchWidget.findPrevious) self.__actions.append(self.findPrevAct) - # TODO: Bookmarks -## self.bookmarksManageAct = E5Action( -## self.tr('Manage Bookmarks'), -## self.tr('&Manage Bookmarks...'), -## QKeySequence(self.tr("Ctrl+Shift+B", "Help|Manage bookmarks")), -## 0, self, 'webbrowser_bookmarks_manage') -## self.bookmarksManageAct.setStatusTip(self.tr( -## 'Open a dialog to manage the bookmarks.')) -## self.bookmarksManageAct.setWhatsThis(self.tr( -## """<b>Manage Bookmarks...</b>""" -## """<p>Open a dialog to manage the bookmarks.</p>""" -## )) -## if not self.__initShortcutsOnly: -## self.bookmarksManageAct.triggered.connect( -## self.__showBookmarksDialog) -## self.__actions.append(self.bookmarksManageAct) -## -## self.bookmarksAddAct = E5Action( -## self.tr('Add Bookmark'), -## UI.PixmapCache.getIcon("addBookmark.png"), -## self.tr('Add &Bookmark...'), -## QKeySequence(self.tr("Ctrl+D", "Help|Add bookmark")), -## 0, self, 'webbrowser_bookmark_add') -## self.bookmarksAddAct.setIconVisibleInMenu(False) -## self.bookmarksAddAct.setStatusTip(self.tr( -## 'Open a dialog to add a bookmark.')) -## self.bookmarksAddAct.setWhatsThis(self.tr( -## """<b>Add Bookmark</b>""" -## """<p>Open a dialog to add the current URL as a bookmark.</p>""" -## )) -## if not self.__initShortcutsOnly: -## self.bookmarksAddAct.triggered.connect(self.__addBookmark) -## self.__actions.append(self.bookmarksAddAct) -## -## self.bookmarksAddFolderAct = E5Action( -## self.tr('Add Folder'), -## self.tr('Add &Folder...'), -## 0, 0, self, 'webbrowser_bookmark_show_all') -## self.bookmarksAddFolderAct.setStatusTip(self.tr( -## 'Open a dialog to add a new bookmarks folder.')) -## self.bookmarksAddFolderAct.setWhatsThis(self.tr( -## """<b>Add Folder...</b>""" -## """<p>Open a dialog to add a new bookmarks folder.</p>""" -## )) -## if not self.__initShortcutsOnly: -## self.bookmarksAddFolderAct.triggered.connect( -## self.__addBookmarkFolder) -## self.__actions.append(self.bookmarksAddFolderAct) -## -## self.bookmarksAllTabsAct = E5Action( -## self.tr('Bookmark All Tabs'), -## self.tr('Bookmark All Tabs...'), -## 0, 0, self, 'webbrowser_bookmark_all_tabs') -## self.bookmarksAllTabsAct.setStatusTip(self.tr( -## 'Bookmark all open tabs.')) -## self.bookmarksAllTabsAct.setWhatsThis(self.tr( -## """<b>Bookmark All Tabs...</b>""" -## """<p>Open a dialog to add a new bookmarks folder for""" -## """ all open tabs.</p>""" -## )) -## if not self.__initShortcutsOnly: -## self.bookmarksAllTabsAct.triggered.connect(self.bookmarkAll) -## self.__actions.append(self.bookmarksAllTabsAct) + self.bookmarksManageAct = E5Action( + self.tr('Manage Bookmarks'), + self.tr('&Manage Bookmarks...'), + QKeySequence(self.tr("Ctrl+Shift+B", "Help|Manage bookmarks")), + 0, self, 'webbrowser_bookmarks_manage') + self.bookmarksManageAct.setStatusTip(self.tr( + 'Open a dialog to manage the bookmarks.')) + self.bookmarksManageAct.setWhatsThis(self.tr( + """<b>Manage Bookmarks...</b>""" + """<p>Open a dialog to manage the bookmarks.</p>""" + )) + if not self.__initShortcutsOnly: + self.bookmarksManageAct.triggered.connect( + self.__showBookmarksDialog) + self.__actions.append(self.bookmarksManageAct) + + self.bookmarksAddAct = E5Action( + self.tr('Add Bookmark'), + UI.PixmapCache.getIcon("addBookmark.png"), + self.tr('Add &Bookmark...'), + QKeySequence(self.tr("Ctrl+D", "Help|Add bookmark")), + 0, self, 'webbrowser_bookmark_add') + self.bookmarksAddAct.setIconVisibleInMenu(False) + self.bookmarksAddAct.setStatusTip(self.tr( + 'Open a dialog to add a bookmark.')) + self.bookmarksAddAct.setWhatsThis(self.tr( + """<b>Add Bookmark</b>""" + """<p>Open a dialog to add the current URL as a bookmark.</p>""" + )) + if not self.__initShortcutsOnly: + self.bookmarksAddAct.triggered.connect(self.__addBookmark) + self.__actions.append(self.bookmarksAddAct) + + self.bookmarksAddFolderAct = E5Action( + self.tr('Add Folder'), + self.tr('Add &Folder...'), + 0, 0, self, 'webbrowser_bookmark_show_all') + self.bookmarksAddFolderAct.setStatusTip(self.tr( + 'Open a dialog to add a new bookmarks folder.')) + self.bookmarksAddFolderAct.setWhatsThis(self.tr( + """<b>Add Folder...</b>""" + """<p>Open a dialog to add a new bookmarks folder.</p>""" + )) + if not self.__initShortcutsOnly: + self.bookmarksAddFolderAct.triggered.connect( + self.__addBookmarkFolder) + self.__actions.append(self.bookmarksAddFolderAct) + + self.bookmarksAllTabsAct = E5Action( + self.tr('Bookmark All Tabs'), + self.tr('Bookmark All Tabs...'), + 0, 0, self, 'webbrowser_bookmark_all_tabs') + self.bookmarksAllTabsAct.setStatusTip(self.tr( + 'Bookmark all open tabs.')) + self.bookmarksAllTabsAct.setWhatsThis(self.tr( + """<b>Bookmark All Tabs...</b>""" + """<p>Open a dialog to add a new bookmarks folder for""" + """ all open tabs.</p>""" + )) + if not self.__initShortcutsOnly: + self.bookmarksAllTabsAct.triggered.connect(self.bookmarkAll) + self.__actions.append(self.bookmarksAllTabsAct) self.whatsThisAct = E5Action( self.tr('What\'s This?'), @@ -1833,24 +1831,23 @@ ## self.historyMenu.newUrl.connect(self.openUrlNewTab) ## mb.addMenu(self.historyMenu) - # TODO: Bookmarks -## from .Bookmarks.BookmarksMenu import BookmarksMenuBarMenu -## self.bookmarksMenu = BookmarksMenuBarMenu(self) -## self.bookmarksMenu.setTearOffEnabled(True) -## self.bookmarksMenu.setTitle(self.tr('&Bookmarks')) -## self.bookmarksMenu.openUrl.connect(self.openUrl) -## self.bookmarksMenu.newUrl.connect(self.openUrlNewTab) -## mb.addMenu(self.bookmarksMenu) -## -## bookmarksActions = [] -## bookmarksActions.append(self.bookmarksManageAct) -## bookmarksActions.append(self.bookmarksAddAct) -## bookmarksActions.append(self.bookmarksAllTabsAct) -## bookmarksActions.append(self.bookmarksAddFolderAct) -## bookmarksActions.append("--SEPARATOR--") -## bookmarksActions.append(self.importBookmarksAct) -## bookmarksActions.append(self.exportBookmarksAct) -## self.bookmarksMenu.setInitialActions(bookmarksActions) + from .Bookmarks.BookmarksMenu import BookmarksMenuBarMenu + self.bookmarksMenu = BookmarksMenuBarMenu(self) + self.bookmarksMenu.setTearOffEnabled(True) + self.bookmarksMenu.setTitle(self.tr('&Bookmarks')) + self.bookmarksMenu.openUrl.connect(self.openUrl) + self.bookmarksMenu.newUrl.connect(self.openUrlNewTab) + mb.addMenu(self.bookmarksMenu) + + bookmarksActions = [] + bookmarksActions.append(self.bookmarksManageAct) + bookmarksActions.append(self.bookmarksAddAct) + bookmarksActions.append(self.bookmarksAllTabsAct) + bookmarksActions.append(self.bookmarksAddFolderAct) + bookmarksActions.append("--SEPARATOR--") + bookmarksActions.append(self.importBookmarksAct) + bookmarksActions.append(self.exportBookmarksAct) + self.bookmarksMenu.setInitialActions(bookmarksActions) menu = mb.addMenu(self.tr('&Settings')) menu.setTearOffEnabled(True) @@ -2060,15 +2057,15 @@ forwardButton.setMenu(self.forwardMenu) forwardButton.setPopupMode(QToolButton.MenuButtonPopup) -## from .Bookmarks.BookmarksToolBar import BookmarksToolBar -## bookmarksModel = self.bookmarksManager().bookmarksModel() -## self.bookmarksToolBar = BookmarksToolBar(self, bookmarksModel, self) -## self.bookmarksToolBar.setObjectName("BookmarksToolBar") -## self.bookmarksToolBar.setIconSize(UI.Config.ToolBarIconSize) -## self.bookmarksToolBar.openUrl.connect(self.openUrl) -## self.bookmarksToolBar.newUrl.connect(self.openUrlNewTab) -## self.addToolBarBreak() -## self.addToolBar(self.bookmarksToolBar) + from .Bookmarks.BookmarksToolBar import BookmarksToolBar + bookmarksModel = self.bookmarksManager().bookmarksModel() + self.bookmarksToolBar = BookmarksToolBar(self, bookmarksModel, self) + self.bookmarksToolBar.setObjectName("BookmarksToolBar") + self.bookmarksToolBar.setIconSize(UI.Config.ToolBarIconSize) + self.bookmarksToolBar.openUrl.connect(self.openUrl) + self.bookmarksToolBar.newUrl.connect(self.openUrlNewTab) + self.addToolBarBreak() + self.addToolBar(self.bookmarksToolBar) ## self.addToolBarBreak() ## vttb = self.addToolBar(self.tr("VirusTotal")) @@ -2316,74 +2313,74 @@ self.reloadAct.setEnabled(not b) self.stopAct.setEnabled(b) -## def __addBookmark(self): -## """ -## Private slot called to add the displayed file to the bookmarks. -## """ -## view = self.currentBrowser() -## url = bytes(view.url().toEncoded()).decode() -## title = view.title() -## description = "" -## meta = view.page().mainFrame().metaData() -## if "description" in meta: -## description = meta["description"][0] -## -## from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog -## dlg = AddBookmarkDialog() -## dlg.setUrl(url) -## dlg.setTitle(title) -## dlg.setDescription(description) -## menu = self.bookmarksManager().menu() -## idx = self.bookmarksManager().bookmarksModel().nodeIndex(menu) -## dlg.setCurrentIndex(idx) -## dlg.exec_() -## -## def __addBookmarkFolder(self): -## """ -## Private slot to add a new bookmarks folder. -## """ -## from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog -## dlg = AddBookmarkDialog() -## menu = self.bookmarksManager().menu() -## idx = self.bookmarksManager().bookmarksModel().nodeIndex(menu) -## dlg.setCurrentIndex(idx) -## dlg.setFolder(True) -## dlg.exec_() -## -## def __showBookmarksDialog(self): -## """ -## Private slot to show the bookmarks dialog. -## """ -## from .Bookmarks.BookmarksDialog import BookmarksDialog -## self.__bookmarksDialog = BookmarksDialog(self) -## self.__bookmarksDialog.openUrl.connect(self.openUrl) -## self.__bookmarksDialog.newUrl.connect(self.openUrlNewTab) -## self.__bookmarksDialog.show() -## -## def bookmarkAll(self): -## """ -## Public slot to bookmark all open tabs. -## """ -## from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog -## dlg = AddBookmarkDialog() -## dlg.setFolder(True) -## dlg.setTitle(self.tr("Saved Tabs")) -## dlg.exec_() -## -## folder = dlg.addedNode() -## if folder is None: -## return -## -## from .Bookmarks.BookmarkNode import BookmarkNode -## for browser in self.__tabWidget.browsers(): -## bookmark = BookmarkNode(BookmarkNode.Bookmark) -## bookmark.url = bytes(browser.url().toEncoded()).decode() -## bookmark.title = browser.title() -## meta = browser.page().mainFrame().metaData() -## if "description" in meta: -## bookmark.desc = meta["description"][0] -## -## self.bookmarksManager().addBookmark(folder, bookmark) + def __addBookmark(self): + """ + Private slot called to add the displayed file to the bookmarks. + """ + view = self.currentBrowser() + url = bytes(view.url().toEncoded()).decode() + title = view.title() + description = "" + meta = view.page().mainFrame().metaData() + if "description" in meta: + description = meta["description"][0] + + from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog + dlg = AddBookmarkDialog() + dlg.setUrl(url) + dlg.setTitle(title) + dlg.setDescription(description) + menu = self.bookmarksManager().menu() + idx = self.bookmarksManager().bookmarksModel().nodeIndex(menu) + dlg.setCurrentIndex(idx) + dlg.exec_() + + def __addBookmarkFolder(self): + """ + Private slot to add a new bookmarks folder. + """ + from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog + dlg = AddBookmarkDialog() + menu = self.bookmarksManager().menu() + idx = self.bookmarksManager().bookmarksModel().nodeIndex(menu) + dlg.setCurrentIndex(idx) + dlg.setFolder(True) + dlg.exec_() + + def __showBookmarksDialog(self): + """ + Private slot to show the bookmarks dialog. + """ + from .Bookmarks.BookmarksDialog import BookmarksDialog + self.__bookmarksDialog = BookmarksDialog(self) + self.__bookmarksDialog.openUrl.connect(self.openUrl) + self.__bookmarksDialog.newUrl.connect(self.openUrlNewTab) + self.__bookmarksDialog.show() + + def bookmarkAll(self): + """ + Public slot to bookmark all open tabs. + """ + from .Bookmarks.AddBookmarkDialog import AddBookmarkDialog + dlg = AddBookmarkDialog() + dlg.setFolder(True) + dlg.setTitle(self.tr("Saved Tabs")) + dlg.exec_() + + folder = dlg.addedNode() + if folder is None: + return + + from .Bookmarks.BookmarkNode import BookmarkNode + for browser in self.__tabWidget.browsers(): + bookmark = BookmarkNode(BookmarkNode.Bookmark) + bookmark.url = bytes(browser.url().toEncoded()).decode() + bookmark.title = browser.title() + meta = browser.page().mainFrame().metaData() + if "description" in meta: + bookmark.desc = meta["description"][0] + + self.bookmarksManager().addBookmark(folder, bookmark) def __find(self): """ @@ -2440,9 +2437,9 @@ ## ## self.cookieJar().close() ## -## self.bookmarksToolBar.setModel(None) -## self.bookmarksManager().close() -## + self.bookmarksToolBar.setModel(None) + self.bookmarksManager().close() + ## self.historyManager().close() ## ## self.passwordManager().close() @@ -3417,19 +3414,19 @@ """ return WebIconProvider.instance().iconForUrl(url) -## @classmethod -## def bookmarksManager(cls): -## """ -## Class method to get a reference to the bookmarks manager. -## -## @return reference to the bookmarks manager (BookmarksManager) -## """ -## if cls._bookmarksManager is None: -## from .Bookmarks.BookmarksManager import BookmarksManager -## cls._bookmarksManager = BookmarksManager() -## -## return cls._bookmarksManager -## + @classmethod + def bookmarksManager(cls): + """ + Class method to get a reference to the bookmarks manager. + + @return reference to the bookmarks manager (BookmarksManager) + """ + if cls._bookmarksManager is None: + from .Bookmarks.BookmarksManager import BookmarksManager + cls._bookmarksManager = BookmarksManager() + + return cls._bookmarksManager + def openUrl(self, url, title): """ Public slot to load a URL in the current tab. @@ -3438,7 +3435,7 @@ @param title title of the bookmark (string) """ self.__linkActivated(url) - + def openUrlNewTab(self, url, title): """ Public slot to load a URL in a new tab.
--- a/eric6.e4p Wed Feb 10 20:00:09 2016 +0100 +++ b/eric6.e4p Thu Feb 11 20:27:07 2016 +0100 @@ -26,6 +26,54 @@ <Source>DataViews/PyCoverageDialog.py</Source> <Source>DataViews/PyProfileDialog.py</Source> <Source>DataViews/__init__.py</Source> + <Source>DebugClients/Python/AsyncFile.py</Source> + <Source>DebugClients/Python/AsyncIO.py</Source> + <Source>DebugClients/Python/DCTestResult.py</Source> + <Source>DebugClients/Python/DebugBase.py</Source> + <Source>DebugClients/Python/DebugClient.py</Source> + <Source>DebugClients/Python/DebugClientBase.py</Source> + <Source>DebugClients/Python/DebugClientCapabilities.py</Source> + <Source>DebugClients/Python/DebugClientThreads.py</Source> + <Source>DebugClients/Python/DebugConfig.py</Source> + <Source>DebugClients/Python/DebugProtocol.py</Source> + <Source>DebugClients/Python/DebugThread.py</Source> + <Source>DebugClients/Python/FlexCompleter.py</Source> + <Source>DebugClients/Python/PyProfile.py</Source> + <Source>DebugClients/Python/__init__.py</Source> + <Source>DebugClients/Python/coverage/__init__.py</Source> + <Source>DebugClients/Python/coverage/__main__.py</Source> + <Source>DebugClients/Python/coverage/annotate.py</Source> + <Source>DebugClients/Python/coverage/backunittest.py</Source> + <Source>DebugClients/Python/coverage/backward.py</Source> + <Source>DebugClients/Python/coverage/bytecode.py</Source> + <Source>DebugClients/Python/coverage/cmdline.py</Source> + <Source>DebugClients/Python/coverage/collector.py</Source> + <Source>DebugClients/Python/coverage/config.py</Source> + <Source>DebugClients/Python/coverage/control.py</Source> + <Source>DebugClients/Python/coverage/data.py</Source> + <Source>DebugClients/Python/coverage/debug.py</Source> + <Source>DebugClients/Python/coverage/env.py</Source> + <Source>DebugClients/Python/coverage/execfile.py</Source> + <Source>DebugClients/Python/coverage/files.py</Source> + <Source>DebugClients/Python/coverage/html.py</Source> + <Source>DebugClients/Python/coverage/misc.py</Source> + <Source>DebugClients/Python/coverage/monkey.py</Source> + <Source>DebugClients/Python/coverage/parser.py</Source> + <Source>DebugClients/Python/coverage/phystokens.py</Source> + <Source>DebugClients/Python/coverage/pickle2json.py</Source> + <Source>DebugClients/Python/coverage/plugin.py</Source> + <Source>DebugClients/Python/coverage/plugin_support.py</Source> + <Source>DebugClients/Python/coverage/python.py</Source> + <Source>DebugClients/Python/coverage/pytracer.py</Source> + <Source>DebugClients/Python/coverage/report.py</Source> + <Source>DebugClients/Python/coverage/results.py</Source> + <Source>DebugClients/Python/coverage/summary.py</Source> + <Source>DebugClients/Python/coverage/templite.py</Source> + <Source>DebugClients/Python/coverage/test_helpers.py</Source> + <Source>DebugClients/Python/coverage/version.py</Source> + <Source>DebugClients/Python/coverage/xmlreport.py</Source> + <Source>DebugClients/Python/eric6dbgstub.py</Source> + <Source>DebugClients/Python/getpass.py</Source> <Source>DebugClients/Python3/AsyncFile.py</Source> <Source>DebugClients/Python3/AsyncIO.py</Source> <Source>DebugClients/Python3/DCTestResult.py</Source> @@ -75,54 +123,6 @@ <Source>DebugClients/Python3/coverage/xmlreport.py</Source> <Source>DebugClients/Python3/eric6dbgstub.py</Source> <Source>DebugClients/Python3/getpass.py</Source> - <Source>DebugClients/Python/AsyncFile.py</Source> - <Source>DebugClients/Python/AsyncIO.py</Source> - <Source>DebugClients/Python/DCTestResult.py</Source> - <Source>DebugClients/Python/DebugBase.py</Source> - <Source>DebugClients/Python/DebugClient.py</Source> - <Source>DebugClients/Python/DebugClientBase.py</Source> - <Source>DebugClients/Python/DebugClientCapabilities.py</Source> - <Source>DebugClients/Python/DebugClientThreads.py</Source> - <Source>DebugClients/Python/DebugConfig.py</Source> - <Source>DebugClients/Python/DebugProtocol.py</Source> - <Source>DebugClients/Python/DebugThread.py</Source> - <Source>DebugClients/Python/FlexCompleter.py</Source> - <Source>DebugClients/Python/PyProfile.py</Source> - <Source>DebugClients/Python/__init__.py</Source> - <Source>DebugClients/Python/coverage/__init__.py</Source> - <Source>DebugClients/Python/coverage/__main__.py</Source> - <Source>DebugClients/Python/coverage/annotate.py</Source> - <Source>DebugClients/Python/coverage/backunittest.py</Source> - <Source>DebugClients/Python/coverage/backward.py</Source> - <Source>DebugClients/Python/coverage/bytecode.py</Source> - <Source>DebugClients/Python/coverage/cmdline.py</Source> - <Source>DebugClients/Python/coverage/collector.py</Source> - <Source>DebugClients/Python/coverage/config.py</Source> - <Source>DebugClients/Python/coverage/control.py</Source> - <Source>DebugClients/Python/coverage/data.py</Source> - <Source>DebugClients/Python/coverage/debug.py</Source> - <Source>DebugClients/Python/coverage/env.py</Source> - <Source>DebugClients/Python/coverage/execfile.py</Source> - <Source>DebugClients/Python/coverage/files.py</Source> - <Source>DebugClients/Python/coverage/html.py</Source> - <Source>DebugClients/Python/coverage/misc.py</Source> - <Source>DebugClients/Python/coverage/monkey.py</Source> - <Source>DebugClients/Python/coverage/parser.py</Source> - <Source>DebugClients/Python/coverage/phystokens.py</Source> - <Source>DebugClients/Python/coverage/pickle2json.py</Source> - <Source>DebugClients/Python/coverage/plugin.py</Source> - <Source>DebugClients/Python/coverage/plugin_support.py</Source> - <Source>DebugClients/Python/coverage/python.py</Source> - <Source>DebugClients/Python/coverage/pytracer.py</Source> - <Source>DebugClients/Python/coverage/report.py</Source> - <Source>DebugClients/Python/coverage/results.py</Source> - <Source>DebugClients/Python/coverage/summary.py</Source> - <Source>DebugClients/Python/coverage/templite.py</Source> - <Source>DebugClients/Python/coverage/test_helpers.py</Source> - <Source>DebugClients/Python/coverage/version.py</Source> - <Source>DebugClients/Python/coverage/xmlreport.py</Source> - <Source>DebugClients/Python/eric6dbgstub.py</Source> - <Source>DebugClients/Python/getpass.py</Source> <Source>DebugClients/__init__.py</Source> <Source>Debugger/BreakPointModel.py</Source> <Source>Debugger/BreakPointViewer.py</Source> @@ -1264,6 +1264,30 @@ <Source>ViewManager/BookmarkedFilesDialog.py</Source> <Source>ViewManager/ViewManager.py</Source> <Source>ViewManager/__init__.py</Source> + <Source>WebBrowser/Bookmarks/AddBookmarkDialog.py</Source> + <Source>WebBrowser/Bookmarks/BookmarkNode.py</Source> + <Source>WebBrowser/Bookmarks/BookmarkPropertiesDialog.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksDialog.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksImportDialog.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksImporters/BookmarksImporter.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksImporters/ChromeImporter.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksImporters/FirefoxImporter.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksImporters/HtmlImporter.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksImporters/IExplorerImporter.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksImporters/OperaImporter.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksImporters/SafariImporter.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksImporters/XbelImporter.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksImporters/__init__.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksManager.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksMenu.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksModel.py</Source> + <Source>WebBrowser/Bookmarks/BookmarksToolBar.py</Source> + <Source>WebBrowser/Bookmarks/DefaultBookmarks_rc.py</Source> + <Source>WebBrowser/Bookmarks/NsHtmlReader.py</Source> + <Source>WebBrowser/Bookmarks/NsHtmlWriter.py</Source> + <Source>WebBrowser/Bookmarks/XbelReader.py</Source> + <Source>WebBrowser/Bookmarks/XbelWriter.py</Source> + <Source>WebBrowser/Bookmarks/__init__.py</Source> <Source>WebBrowser/JavaScript/AutoFillJsObject.py</Source> <Source>WebBrowser/JavaScript/ExternalJsObject.py</Source> <Source>WebBrowser/JavaScript/__init__.py</Source> @@ -1689,6 +1713,10 @@ <Form>VCS/CommandOptionsDialog.ui</Form> <Form>VCS/RepositoryInfoDialog.ui</Form> <Form>ViewManager/BookmarkedFilesDialog.ui</Form> + <Form>WebBrowser/Bookmarks/AddBookmarkDialog.ui</Form> + <Form>WebBrowser/Bookmarks/BookmarkPropertiesDialog.ui</Form> + <Form>WebBrowser/Bookmarks/BookmarksDialog.ui</Form> + <Form>WebBrowser/Bookmarks/BookmarksImportDialog.ui</Form> <Form>WebBrowser/SearchWidget.ui</Form> <Form>WebBrowser/ZoomManager/ZoomValuesDialog.ui</Form> </Forms> @@ -1722,19 +1750,20 @@ <Resource>Helpviewer/data/icons.qrc</Resource> <Resource>Helpviewer/data/javascript.qrc</Resource> <Resource>IconEditor/cursors/cursors.qrc</Resource> + <Resource>WebBrowser/Bookmarks/DefaultBookmarks.qrc</Resource> <Resource>WebBrowser/data/javascript.qrc</Resource> </Resources> <Interfaces/> <Others> <Other>.hgignore</Other> + <Other>APIs/Python/zope-2.10.7.api</Other> + <Other>APIs/Python/zope-2.11.2.api</Other> + <Other>APIs/Python/zope-3.3.1.api</Other> <Other>APIs/Python3/PyQt4.bas</Other> <Other>APIs/Python3/PyQt5.bas</Other> <Other>APIs/Python3/QScintilla2.bas</Other> <Other>APIs/Python3/eric6.api</Other> <Other>APIs/Python3/eric6.bas</Other> - <Other>APIs/Python/zope-2.10.7.api</Other> - <Other>APIs/Python/zope-2.11.2.api</Other> - <Other>APIs/Python/zope-3.3.1.api</Other> <Other>APIs/QSS/qss.api</Other> <Other>APIs/Ruby/Ruby-1.8.7.api</Other> <Other>APIs/Ruby/Ruby-1.8.7.bas</Other> @@ -1743,8 +1772,8 @@ <Other>CSSs</Other> <Other>CodeTemplates</Other> <Other>DTDs</Other> + <Other>DebugClients/Python/coverage/doc</Other> <Other>DebugClients/Python3/coverage/doc</Other> - <Other>DebugClients/Python/coverage/doc</Other> <Other>DesignerTemplates</Other> <Other>Dictionaries</Other> <Other>Documentation/Help</Other> @@ -1827,6 +1856,7 @@ <Other>ThirdParty/Pygments/pygments/PKG-INFO</Other> <Other>ThirdParty/Send2Trash/LICENSE</Other> <Other>ThirdParty/enum/LICENSE</Other> + <Other>WebBrowser/Bookmarks/DefaultBookmarks.xbel</Other> <Other>WebBrowser/data/javascript/jquery-ui.js</Other> <Other>WebBrowser/data/javascript/jquery.js</Other> <Other>WebBrowser/data/javascript/qwebchannel.js</Other>