Implemented the JSON based templates files. jsonfiles

Thu, 28 Jan 2021 13:19:22 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Thu, 28 Jan 2021 13:19:22 +0100
branch
jsonfiles
changeset 8018
641c7c312f26
parent 8017
7ec108389fde
child 8019
5fb467ac4233

Implemented the JSON based templates files.

eric6.e4p file | annotate | diff | comparison | revisions
eric6/QScintilla/Lexers/__init__.py file | annotate | diff | comparison | revisions
eric6/Templates/TemplateViewer.py file | annotate | diff | comparison | revisions
eric6/Templates/TemplatesFile.py file | annotate | diff | comparison | revisions
--- a/eric6.e4p	Thu Jan 28 13:18:55 2021 +0100
+++ b/eric6.e4p	Thu Jan 28 13:19:22 2021 +0100
@@ -939,6 +939,7 @@
     <Source>eric6/Templates/TemplatePropertiesDialog.py</Source>
     <Source>eric6/Templates/TemplateSingleVariableDialog.py</Source>
     <Source>eric6/Templates/TemplateViewer.py</Source>
+    <Source>eric6/Templates/TemplatesFile.py</Source>
     <Source>eric6/Templates/__init__.py</Source>
     <Source>eric6/ThirdParty/CharDet/__init__.py</Source>
     <Source>eric6/ThirdParty/CharDet/chardet/__init__.py</Source>
--- a/eric6/QScintilla/Lexers/__init__.py	Thu Jan 28 13:18:55 2021 +0100
+++ b/eric6/QScintilla/Lexers/__init__.py	Thu Jan 28 13:19:22 2021 +0100
@@ -842,6 +842,7 @@
         '*.m': "Matlab",
         '*.m.matlab': "Matlab",
         '*.m.octave': "Octave",
+        '*.e4c': "XML",
         '*.e4d': "XML",
         '*.e4k': "XML",
         '*.e4m': "XML",
@@ -863,6 +864,7 @@
         '*.e6q': "XML",
         '*.e6s': "XML",
         '*.e6t': "XML",
+        '*.ecj': "JSON",
         '*.edj': "JSON",
         '*.ekj': "JSON",
         '*.emj': "JSON",
--- a/eric6/Templates/TemplateViewer.py	Thu Jan 28 13:18:55 2021 +0100
+++ b/eric6/Templates/TemplateViewer.py	Thu Jan 28 13:19:22 2021 +0100
@@ -24,6 +24,8 @@
 import UI.PixmapCache
 import Utilities
 
+from .TemplatesFile import TemplatesFile
+
 
 class TemplateGroup(QTreeWidgetItem):
     """
@@ -432,6 +434,8 @@
         self.__activating = False
         self.__dirty = False
         
+        self.__templatesFile = TemplatesFile(self)
+        
         self.setContextMenuPolicy(Qt.CustomContextMenu)
         self.customContextMenuRequested.connect(self.__showContextMenu)
         self.itemActivated.connect(self.__templateItemActivated)
@@ -563,7 +567,9 @@
             self,
             self.tr("Import Templates"),
             "",
-            self.tr("Templates Files (*.e4c);; All Files (*)"))
+            self.tr("Templates Files (*.ecj);;"
+                    "XML Templates Files (*.e4c);;"
+                    "All Files (*)"))
         
         if fn:
             self.readTemplates(fn)
@@ -577,7 +583,9 @@
             self,
             self.tr("Export Templates"),
             "",
-            self.tr("Templates Files (*.e4c);; All Files (*)"),
+            self.tr("Templates Files (*.ecj);;"
+                    "XML Templates Files (*.e4c);;"
+                    "All Files (*)"),
             "",
             E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
         
@@ -949,61 +957,77 @@
         tmpl.setTemplateText(template)
         self.__resort()
     
-    # TODO: do the JSON templates
     def writeTemplates(self, filename=None):
         """
-        Public method to write the templates data to an XML file (.e4c).
+        Public method to write the templates data to a JSON file (.ecj).
         
-        @param filename name of a templates file to read (string)
-        @return flag indicating success (boolean)
+        @param filename name of a templates file to write
+        @type str
+        @return flag indicating success
+        @rtype bool
         """
         if filename is None:
             filename = os.path.join(
-                Utilities.getConfigDir(), "eric6templates.e4c")
-        f = QFile(filename)
-        ok = f.open(QIODevice.WriteOnly)
-        if not ok:
-            E5MessageBox.critical(
-                self,
-                self.tr("Save templates"),
-                self.tr(
-                    "<p>The templates file <b>{0}</b> could not be"
-                    " written.</p>")
-                .format(filename))
-            return False
+                Utilities.getConfigDir(), "eric6templates.ecj")
+        if filename.endswith(".ecj"):
+            # new JSON based file
+            res = self.__templatesFile.writeFile(filename)
+        else:
+            # old XML based file
+            f = QFile(filename)
+            ok = f.open(QIODevice.WriteOnly)
+            if not ok:
+                E5MessageBox.critical(
+                    self,
+                    self.tr("Save Templates"),
+                    self.tr(
+                        "<p>The templates file <b>{0}</b> could not be"
+                        " written.</p>")
+                    .format(filename))
+                res = False
+            else:
+                from E5XML.TemplatesWriter import TemplatesWriter
+                TemplatesWriter(f, self).writeXML()
+                f.close()
+                res = True
         
-        from E5XML.TemplatesWriter import TemplatesWriter
-        TemplatesWriter(f, self).writeXML()
-        f.close()
-        
-        return True
+        return res
     
-    # TODO: do the JSON templates
     def readTemplates(self, filename=None):
         """
         Public method to read in the templates file (.e4c).
         
-        @param filename name of a templates file to read (string)
+        @param filename name of a templates file to read
+        @type str
         """
         if filename is None:
+            # new JSON based file first
             filename = os.path.join(
-                Utilities.getConfigDir(), "eric6templates.e4c")
+                Utilities.getConfigDir(), "eric6templates.ecj")
             if not os.path.exists(filename):
-                return
+                # old XML based file second
+                filename = os.path.join(
+                    Utilities.getConfigDir(), "eric6templates.e4c")
+                if not os.path.exists(filename):
+                    return
         
-        f = QFile(filename)
-        if f.open(QIODevice.ReadOnly):
-            from E5XML.TemplatesReader import TemplatesReader
-            reader = TemplatesReader(f, viewer=self)
-            reader.readXML()
-            f.close()
+        if filename.endswith(".ecj"):
+            self.__templatesFile.readFile(filename)
         else:
-            E5MessageBox.critical(
-                self,
-                self.tr("Read templates"),
-                self.tr(
-                    "<p>The templates file <b>{0}</b> could not be read.</p>")
-                .format(filename))
+            f = QFile(filename)
+            if f.open(QIODevice.ReadOnly):
+                from E5XML.TemplatesReader import TemplatesReader
+                reader = TemplatesReader(f, viewer=self)
+                reader.readXML()
+                f.close()
+            else:
+                E5MessageBox.critical(
+                    self,
+                    self.tr("Read Templates"),
+                    self.tr(
+                        "<p>The templates file <b>{0}</b> could not be read."
+                        "</p>")
+                    .format(filename))
     
     def __configure(self):
         """
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Templates/TemplatesFile.py	Thu Jan 28 13:19:22 2021 +0100
@@ -0,0 +1,127 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2021 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a class representing the templates JSON file.
+"""
+
+import json
+import time
+import typing
+
+from PyQt5.QtCore import QObject
+
+from E5Gui import E5MessageBox
+from E5Gui.E5OverrideCursor import E5OverridenCursor
+
+
+TemplateViewer = typing.TypeVar("TemplateViewer")
+
+
+class TemplatesFile(QObject):
+    """
+    Class representing the templates JSON file.
+    """
+    def __init__(self, viewer: TemplateViewer, parent: QObject = None):
+        """
+        Constructor
+        
+        @param viewer reference to the template viewer object
+        @type TemplateViewer
+        @param parent reference to the parent object (defaults to None)
+        @type QObject (optional)
+        """
+        super(TemplatesFile, self).__init__(parent)
+        self.__viewer = viewer
+    
+    def writeFile(self, filename: str) -> bool:
+        """
+        Public method to write the templates data to a templates JSON file.
+        
+        @param filename name of the templates file
+        @type str
+        @return flag indicating a successful write
+        @rtype bool
+        """
+        templatesDict = {}
+        # step 0: header
+        templatesDict["header"] = {
+            "comment": "eric templates file",
+            "saved": time.strftime('%Y-%m-%d, %H:%M:%S'),
+            "warning": (
+                "This file was generated automatically, do not edit."
+            ),
+        }
+        
+        # step 1: template groups and templates
+        templateGroups = []
+        for group in self.__viewer.getAllGroups():
+            templates = []
+            for template in group.getAllEntries():
+                templates.append({
+                    "name": template.getName(),
+                    "description": template.getDescription().strip(),
+                    "text": template.getTemplateText()
+                })
+            templateGroups.append({
+                "name": group.getName(),
+                "language": group.getLanguage(),
+                "templates": templates,
+            })
+        templatesDict["template_groups"] = templateGroups
+        
+        try:
+            jsonString = json.dumps(templatesDict, indent=2)
+            with open(filename, "w") as f:
+                f.write(jsonString)
+        except (TypeError, EnvironmentError) as err:
+            with E5OverridenCursor():
+                E5MessageBox.critical(
+                    None,
+                    self.tr("Save Templates"),
+                    self.tr(
+                        "<p>The templates file <b>{0}</b> could not be"
+                        " written.</p><p>Reason: {1}</p>"
+                    ).format(filename, str(err))
+                )
+                return False
+        
+        return True
+    
+    def readFile(self, filename: str) -> bool:
+        """
+        Public method to read the templates data from a templates JSON file.
+        
+        @param filename name of the project file
+        @type str
+        @return flag indicating a successful read
+        @rtype bool
+        """
+        try:
+            with open(filename, "r") as f:
+                jsonString = f.read()
+            templatesDict = json.loads(jsonString)
+        except (EnvironmentError, json.JSONDecodeError) as err:
+            E5MessageBox.critical(
+                None,
+                self.tr("Read Templates"),
+                self.tr(
+                    "<p>The templates file <b>{0}</b> could not be read.</p>"
+                    "<p>Reason: {1}</p>"
+                ).format(filename, str(err))
+            )
+            return False
+        
+        for templateGroup in templatesDict["template_groups"]:
+            self.__viewer.addGroup(templateGroup["name"],
+                                   templateGroup["language"])
+            for template in templateGroup["templates"]:
+                self.__viewer.addEntry(templateGroup["name"],
+                                       template["name"],
+                                       template["description"],
+                                       template["text"],
+                                       quiet=True)
+        
+        return True

eric ide

mercurial