Continued porting the web browser. QtWebEngine

Thu, 11 Feb 2016 20:27:07 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Thu, 11 Feb 2016 20:27:07 +0100
branch
QtWebEngine
changeset 4732
5ac4fc1dfc20
parent 4731
67d861d9e492
child 4733
ae291a307ea6

Continued porting the web browser.

- added the bookmarks stuff

WebBrowser/Bookmarks/AddBookmarkDialog.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/AddBookmarkDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarkNode.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarkPropertiesDialog.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarkPropertiesDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksDialog.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImportDialog.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImportDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImporters/BookmarksImporter.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImporters/ChromeImporter.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImporters/FirefoxImporter.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImporters/HtmlImporter.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImporters/IExplorerImporter.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImporters/OperaImporter.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImporters/SafariImporter.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImporters/XbelImporter.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksImporters/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksManager.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksMenu.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksModel.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/BookmarksToolBar.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/DefaultBookmarks.qrc file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/DefaultBookmarks.xbel file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/DefaultBookmarks_rc.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/NsHtmlReader.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/NsHtmlWriter.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/XbelReader.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/XbelWriter.py file | annotate | diff | comparison | revisions
WebBrowser/Bookmarks/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/Tools/WebIconProvider.py file | annotate | diff | comparison | revisions
WebBrowser/UrlBar/UrlBar.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserTabWidget.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserView.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserWindow.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
--- /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>&amp;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 &amp;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 &gt;</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 + '&amp;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>

eric ide

mercurial