Help Viewer eric7

Wed, 05 Jan 2022 14:26:11 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 05 Jan 2022 14:26:11 +0100
branch
eric7
changeset 8902
ba9b8c6e4928
parent 8901
adc47f306e51
child 8903
171bf310cc4c

Help Viewer
- added import and export capability to the bookmarks widget

eric7.epj file | annotate | diff | comparison | revisions
eric7/HelpViewer/HelpBookmarkPropertiesDialog.py file | annotate | diff | comparison | revisions
eric7/HelpViewer/HelpBookmarksImportDialog.py file | annotate | diff | comparison | revisions
eric7/HelpViewer/HelpBookmarksImportDialog.ui file | annotate | diff | comparison | revisions
eric7/HelpViewer/HelpBookmarksWidget.py file | annotate | diff | comparison | revisions
eric7/HelpViewer/HelpViewerWidget.py file | annotate | diff | comparison | revisions
--- a/eric7.epj	Wed Jan 05 11:53:28 2022 +0100
+++ b/eric7.epj	Wed Jan 05 14:26:11 2022 +0100
@@ -716,7 +716,8 @@
       "eric7/JediInterface/RefactoringPreviewDialog.ui",
       "eric7/QScintilla/EditorOutlineSizesDialog.ui",
       "eric7/Preferences/ConfigurationPages/InterfaceLightPage.ui",
-      "eric7/HelpViewer/HelpBookmarkPropertiesDialog.ui"
+      "eric7/HelpViewer/HelpBookmarkPropertiesDialog.ui",
+      "eric7/HelpViewer/HelpBookmarksImportDialog.ui"
     ],
     "HASH": "df7daa8781250f7664e6ecaeaf1361fa2efd39ee",
     "IDLPARAMS": {
@@ -2308,7 +2309,8 @@
       "eric7/Preferences/ThemeManager.py",
       "eric7/Preferences/ConfigurationPages/InterfaceLightPage.py",
       "eric7/HelpViewer/HelpBookmarksWidget.py",
-      "eric7/HelpViewer/HelpBookmarkPropertiesDialog.py"
+      "eric7/HelpViewer/HelpBookmarkPropertiesDialog.py",
+      "eric7/HelpViewer/HelpBookmarksImportDialog.py"
     ],
     "SPELLEXCLUDES": "Dictionaries/excludes.dic",
     "SPELLLANGUAGE": "en_US",
--- a/eric7/HelpViewer/HelpBookmarkPropertiesDialog.py	Wed Jan 05 11:53:28 2022 +0100
+++ b/eric7/HelpViewer/HelpBookmarkPropertiesDialog.py	Wed Jan 05 14:26:11 2022 +0100
@@ -52,7 +52,7 @@
     
     def getData(self):
         """
-        Public method to retrieve the entered data
+        Public method to retrieve the entered data.
         
         @return tuple containing the title and URL for the bookmark
         @rtype tuple of (str, str)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/HelpViewer/HelpBookmarksImportDialog.py	Wed Jan 05 14:26:11 2022 +0100
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to enter the bookmarks import parameters.
+"""
+
+from PyQt6.QtCore import pyqtSlot
+from PyQt6.QtWidgets import QDialog, QDialogButtonBox
+
+from EricWidgets.EricPathPicker import EricPathPickerModes
+
+from .Ui_HelpBookmarksImportDialog import Ui_HelpBookmarksImportDialog
+
+
+class HelpBookmarksImportDialog(QDialog, Ui_HelpBookmarksImportDialog):
+    """
+    Class implementing a dialog to enter the bookmarks import parameters.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (defaults to None)
+        @type QWidget (optional)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+        
+        self.bookmarksPicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
+        self.bookmarksPicker.setFilters(
+            self.tr("eric Bookmarks Files (*.json);;All Files (*)"))
+        self.bookmarksPicker.textChanged.connect(self.__updateOkButton)
+        
+        msh = self.minimumSizeHint()
+        self.resize(max(self.width(), msh.width()), msh.height())
+        
+        self.__updateOkButton()
+    
+    @pyqtSlot()
+    def __updateOkButton(self):
+        """
+        Private method to update the state of the OK button.
+        """
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(
+            bool(self.bookmarksPicker.text()))
+    
+    def getData(self):
+        """
+        Public method to retrieve the entered data.
+        
+        @return tuple containing a flag indicating to replace the existing
+            bookmarks and the path of the bookmarks file to be imported
+        @rtype tuple of (bool, str)
+        """
+        return (
+            self.replaceCheckBox.isChecked(),
+            self.bookmarksPicker.path(),
+        )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/HelpViewer/HelpBookmarksImportDialog.ui	Wed Jan 05 14:26:11 2022 +0100
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>HelpBookmarksImportDialog</class>
+ <widget class="QDialog" name="HelpBookmarksImportDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>500</width>
+    <height>98</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Import Bookmarks</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0" colspan="2">
+    <widget class="QCheckBox" name="replaceCheckBox">
+     <property name="toolTip">
+      <string>Select to replace the existing bookmarks</string>
+     </property>
+     <property name="text">
+      <string>Replace Existing Bookmarks</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Bookmarks:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="EricPathPicker" name="bookmarksPicker" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="focusPolicy">
+      <enum>Qt::WheelFocus</enum>
+     </property>
+     <property name="toolTip">
+      <string>Enter the path of the bookmarks file</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" 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>EricPathPicker</class>
+   <extends>QWidget</extends>
+   <header>EricWidgets/EricPathPicker.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>HelpBookmarksImportDialog</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>HelpBookmarksImportDialog</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>
--- a/eric7/HelpViewer/HelpBookmarksWidget.py	Wed Jan 05 11:53:28 2022 +0100
+++ b/eric7/HelpViewer/HelpBookmarksWidget.py	Wed Jan 05 14:26:11 2022 +0100
@@ -3,19 +3,29 @@
 # Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de>
 #
 
+"""
+Module implementing a widget showing the list of bookmarks.
+"""
+
 import contextlib
+import datetime
 import json
+import os
 
 from PyQt6.QtCore import pyqtSignal, pyqtSlot, Qt, QPoint, QUrl
 from PyQt6.QtGui import QClipboard, QGuiApplication
 from PyQt6.QtWidgets import (
-    QAbstractItemView, QApplication, QDialog, QListWidget, QListWidgetItem, QMenu
+    QAbstractItemView, QApplication, QDialog, QListWidget, QListWidgetItem,
+    QMenu
 )
 
+from EricWidgets import EricFileDialog, EricMessageBox
+
 import Preferences
 
 from .HelpBookmarkPropertiesDialog import HelpBookmarkPropertiesDialog
 
+
 class HelpBookmarksWidget(QListWidget):
     """
     Class implementing a widget showing the list of bookmarks.
@@ -94,7 +104,10 @@
         newBookmark = menu.addAction(self.tr("New Bookmark"))
         addBookmark = menu.addAction(self.tr("Bookmark Page"))
         menu.addSeparator()
-        deleteBookmarks = menu.addAction(self.tr("Delete All Bookmark"))
+        deleteBookmarks = menu.addAction(self.tr("Delete All Bookmarks"))
+        menu.addSeparator()
+        exportBookmarks = menu.addAction(self.tr("Export All Bookmarks"))
+        importBookmarks = menu.addAction(self.tr("Import Bookmarks"))
         
         act = menu.exec(self.mapToGlobal(point))
         if act == openBookmarks:
@@ -107,6 +120,10 @@
             self.__deleteBookmarks([
                 self.item(row) for row in range(self.count())
             ])
+        elif act == exportBookmarks:
+            self.__exportBookmarks(selected=False)
+        elif act == importBookmarks:
+            self.__importBookmarks()
     
     @pyqtSlot(QPoint)
     def __showBookmarkContextMenu(self, point):
@@ -140,6 +157,9 @@
         editBookmark = menu.addAction(self.tr("Edit Bookmark"))
         menu.addSeparator()
         deleteBookmark = menu.addAction(self.tr("Delete Bookmark"))
+        menu.addSeparator()
+        exportBookmarks = menu.addAction(self.tr("Export All Bookmarks"))
+        importBookmarks = menu.addAction(self.tr("Import Bookmarks"))
         
         act = menu.exec(self.mapToGlobal(point))
         if act == curPage:
@@ -162,6 +182,10 @@
             self.__editBookmark(itm)
         elif act == deleteBookmark:
             self.__deleteBookmarks([itm])
+        elif act == exportBookmarks:
+            self.__exportBookmarks(selected=False)
+        elif act == importBookmarks:
+            self.__importBookmarks()
     
     @pyqtSlot(QPoint)
     def __showBookmarksContextMenu(self, point):
@@ -175,12 +199,22 @@
         openBookmarks = menu.addAction(self.tr("Open Selected Bookmarks"))
         menu.addSeparator()
         deleteBookmarks = menu.addAction(self.tr("Delete Selected Bookmarks"))
+        menu.addSeparator()
+        exportBookmarks = menu.addAction(self.tr("Export Selected Bookmarks"))
+        exportAllBookmarks = menu.addAction(self.tr("Export All Bookmarks"))
+        importBookmarks = menu.addAction(self.tr("Import Bookmarks"))
         
         act = menu.exec(self.mapToGlobal(point))
         if act == openBookmarks:
             self.__openBookmarks(selected=True)
         elif act == deleteBookmarks:
             self.__deleteBookmarks(self.selectedItems())
+        elif act == exportBookmarks:
+            self.__exportBookmarks(selected=True)
+        elif act == exportAllBookmarks:
+            self.__exportBookmarks(selected=False)
+        elif act == importBookmarks:
+            self.__importBookmarks()
     
     @pyqtSlot(str, str)
     def __addBookmark(self, title, url):
@@ -358,17 +392,143 @@
             })
         Preferences.setHelp("Bookmarks", json.dumps(bookmarks))
     
-    def __exportBookmarks(self):
+    @pyqtSlot()
+    def __exportBookmarks(self, selected=False):
+        """
+        Private slot to export the bookmarks into a JSON file.
+        
+        @param selected flag indicating to export the selected bookmarks
+            (defaults to False)
+        @type bool (optional)
         """
-        Private method to export the bookmarks into a JSON file.
-        """
-        # TODO: not yet implemented
+        filename, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
+            self,
+            self.tr("Export Bookmarks"),
+            "",
+            self.tr("eric Bookmarks Files (*.json);;All Files (*)"),
+            None,
+            EricFileDialog.DontConfirmOverwrite
+        )
+        if filename:
+            ext = os.path.splitext(filename)[1]
+            if not ext:
+                ex = selectedFilter.split("(*")[1].split(")")[0]
+                if ex:
+                    filename += ex
+            
+            if os.path.exists(filename):
+                ok = EricMessageBox.yesNo(
+                    self,
+                    self.tr("Export Bookmarks"),
+                    self.tr("""The file <b>{0}</b> already exists. Do you"""
+                            """ want to overwrite it?""").format(filename))
+                if not ok:
+                    return
+            
+            bookmarksDict = {
+                "creator": "eric7",
+                "version": 1,
+                "created": datetime.datetime.now().isoformat(
+                    sep=" ", timespec="seconds"),
+                "bookmarks": []
+            }
+            bookmarkItems = (
+                self.selectedItems()
+                if selected else
+                [self.item(row) for row in range(self.count())]
+            )
+            for bookmarkItem in bookmarkItems:
+                bookmarksDict["bookmarks"].append({
+                    "type": "url",
+                    "title": bookmarkItem.text(),
+                    "url": bookmarkItem.data(self.UrlRole).toString(),
+                })
+            
+            jsonStr = json.dumps(bookmarksDict, indent=2, sort_keys=True)
+            try:
+                with open(filename, "w") as f:
+                    f.write(jsonStr)
+            except OSError as err:
+                EricMessageBox.critical(
+                    self,
+                    self.tr("Export Bookmarks"),
+                    self.tr("""<p>The bookmarks could not be exported"""
+                            """ to <b>{0}</b>.</p><p>Reason: {1}</p>""")
+                    .format(filename, str(err)))
     
+    @pyqtSlot()
     def __importBookmarks(self):
         """
-        Private method to import bookmarks from a JSON file.
+        Private slot to import bookmarks from a JSON file.
         """
-        # TODO: not yet implemented
-        #       1. read file
-        #       2. check, if exported from eric and compatible format version
-        #       3. process each entry
+        from .HelpBookmarksImportDialog import HelpBookmarksImportDialog
+        
+        dlg = HelpBookmarksImportDialog(self)
+        if dlg.exec() == QDialog.DialogCode.Accepted:
+            replace, filename = dlg.getData()
+            
+            try:
+                with open(filename, "r") as f:
+                    jsonStr = f.read()
+                    bookmarks = json.loads(jsonStr)
+            except (OSError, json.JSONDecodeError) as err:
+                EricMessageBox.critical(
+                    self,
+                    self.tr("Import Bookmarks"),
+                    self.tr(
+                        "<p>The bookmarks file <b>{0}</b> could not be "
+                        "read.</p><p>Reason: {1}</p>"
+                    ).format(filename, str(err))
+                )
+                return
+            
+            if not isinstance(bookmarks, dict):
+                EricMessageBox.critical(
+                    self,
+                    self.tr("Import Bookmarks"),
+                    self.tr(
+                        "The bookmarks file <b>{0}</b> has invalid contents."
+                    ).format(filename)
+                )
+                return
+            
+            try:
+                if bookmarks["creator"] != "eric7":
+                    EricMessageBox.critical(
+                        self,
+                        self.tr("Import Bookmarks"),
+                        self.tr(
+                            "The bookmarks file <b>{0}</b> was not created"
+                            " with 'eric7'."
+                        ).format(filename)
+                    )
+                    return
+                
+                if bookmarks["version"] != 1:
+                    EricMessageBox.critical(
+                        self,
+                        self.tr("Import Bookmarks"),
+                        self.tr(
+                            "The bookmarks file <b>{0}</b> has an unsupported"
+                            " format version."
+                        ).format(filename)
+                    )
+                    return
+                
+                if replace:
+                    self.clear()
+                
+                for bookmark in bookmarks["bookmarks"]:
+                    if bookmark["type"] == "url":
+                        self.__addBookmark(bookmark["title"], bookmark["url"])
+                self.sortItems()
+                self.__saveBookmarks()
+            
+            except KeyError:
+                EricMessageBox.critical(
+                    self,
+                    self.tr("Import Bookmarks"),
+                    self.tr(
+                        "The bookmarks file <b>{0}</b> has invalid contents."
+                    ).format(filename)
+                )
--- a/eric7/HelpViewer/HelpViewerWidget.py	Wed Jan 05 11:53:28 2022 +0100
+++ b/eric7/HelpViewer/HelpViewerWidget.py	Wed Jan 05 14:26:11 2022 +0100
@@ -262,7 +262,6 @@
             "documentFind", self.tr("Show the help search window"))
         self.__bookmarksButton = self.__addNavigationButton(
             "bookmark22", self.tr("Show list of bookmarks"))
-#        self.__openPagesButton.setChecked(True)
         
         self.__buttonLayout.addStretch()
         

eric ide

mercurial