Thu, 28 Jan 2021 13:19:22 +0100
Implemented the JSON based templates files.
--- 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