--- a/eric6/Graphics/UMLDialog.py Wed May 05 17:29:41 2021 +0200 +++ b/eric6/Graphics/UMLDialog.py Wed May 05 18:17:24 2021 +0200 @@ -8,8 +8,9 @@ """ import enum +import json -from PyQt5.QtCore import pyqtSlot, Qt, QFileInfo +from PyQt5.QtCore import pyqtSlot, Qt, QFileInfo, QCoreApplication from PyQt5.QtWidgets import QAction, QToolBar, QGraphicsScene from E5Gui import E5MessageBox, E5FileDialog @@ -36,6 +37,17 @@ """ FileVersions = ("1.0") + UMLDialogType2String = { + UMLDialogType.CLASS_DIAGRAM: + QCoreApplication.translate("UMLDialog", "Class Diagram"), + UMLDialogType.PACKAGE_DIAGRAM: + QCoreApplication.translate("UMLDialog", "Package Diagram"), + UMLDialogType.IMPORTS_DIAGRAM: + QCoreApplication.translate("UMLDialog", "Imports Diagram"), + UMLDialogType.APPLICATION_DIAGRAM: + QCoreApplication.translate("UMLDialog", "Application Diagram"), + } + def __init__(self, diagramType, project, path="", parent=None, initBuilder=True, **kwargs): """ @@ -60,12 +72,6 @@ self.__project = project self.__diagramType = diagramType - self.__diagramTypeString = { - UMLDialogType.CLASS_DIAGRAM: "Class Diagram", - UMLDialogType.PACKAGE_DIAGRAM: "Package Diagram", - UMLDialogType.IMPORTS_DIAGRAM: "Imports Diagram", - UMLDialogType.APPLICATION_DIAGRAM: "Application Diagram", - }.get(diagramType, "Illegal Diagram Type") from .UMLGraphicsView import UMLGraphicsView self.scene = QGraphicsScene(0.0, 0.0, 800.0, 600.0) @@ -84,7 +90,20 @@ self.umlView.relayout.connect(self.__relayout) - self.setWindowTitle(self.__diagramTypeString) + self.setWindowTitle(self.__getDiagramTitel(self.__diagramType)) + + def __getDiagramTitel(self, diagramType): + """ + Private method to get a textual description for the diagram type. + + @param diagramType diagram type string + @type str + @return titel of the diagram + @rtype str + """ + return UMLDialog.UMLDialogType2String.get( + diagramType, self.tr("Illegal Diagram Type") + ) def __initActions(self): """ @@ -208,7 +227,6 @@ """ self.__saveAs(self.__fileName) - # TODO: change this to save file in JSON format @pyqtSlot() def __saveAs(self, filename=""): """ @@ -222,7 +240,9 @@ self, self.tr("Save Diagram"), "", - self.tr("Eric Graphics File (*.e5g);;All Files (*)"), + self.tr("Eric Graphics File (*.egj);;" + "Eric Text Graphics File (*.e5g);;" + "All Files (*)"), "", E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) if not fname: @@ -243,31 +263,16 @@ return filename = fname - lines = [ - "version: 1.0", - "diagram_type: {0} ({1})".format( - self.__diagramType.value, self.__diagramTypeString), - "scene_size: {0};{1}".format(self.scene.width(), - self.scene.height()), - ] - persistenceData = self.builder.getPersistenceData() - if persistenceData: - lines.append("builder_data: {0}".format(persistenceData)) - lines.extend(self.umlView.getPersistenceData()) + res = ( + self.__writeLineBasedGraphicsFile(filename) + if filename.endswith(".e5g") else + # JSON format is the default + self.__writeJsonGraphicsFile(filename) + ) - try: - with open(filename, "w", encoding="utf-8") as f: - f.write("\n".join(lines)) - except OSError as err: - E5MessageBox.critical( - self, - self.tr("Save Diagram"), - self.tr( - """<p>The file <b>{0}</b> could not be saved.</p>""" - """<p>Reason: {1}</p>""").format(filename, str(err))) - return - - self.__fileName = filename + if res: + # save the file name only in case of success + self.__fileName = filename # TODO: add loading of file in JSON format # TODO: eric7: delete the current one @@ -290,6 +295,26 @@ # Canceled by user return False + if filename.endswith(".e5g"): + return self.__readLineBasedGraphicsFile(filename) + else: + return False + + ####################################################################### + ## Methods to read and write eric graphics files of the old line + ## based file format. + ####################################################################### + + def __readLineBasedGraphicsFile(self, filename): + """ + Private method to read an eric graphics file using the old line + based file format. + + @param filename name of the file to be read + @type str + @return flag indicating success + @rtype bool + """ try: with open(filename, "r", encoding="utf-8") as f: data = f.read() @@ -327,10 +352,8 @@ self.__showInvalidDataMessage(filename, linenum) return False try: - diagramType, diagramTypeString = value.strip().split(None, 1) + diagramType = value.strip().split(None, 1)[0] self.__diagramType = UMLDialogType(int(diagramType)) - self.__diagramTypeString = diagramTypeString[1:-1] - # remove opening and closing bracket except ValueError: self.__showInvalidDataMessage(filename, linenum) return False @@ -373,11 +396,47 @@ # everything worked fine, so remember the file name and set the # window title - self.setWindowTitle(self.__diagramTypeString) + self.setWindowTitle(self.__getDiagramTitel(self.__diagramType)) self.__fileName = filename return True + def __writeLineBasedGraphicsFile(self, filename): + """ + Private method to write an eric graphics file using the old line + based file format. + + @param filename name of the file to write to + @type str + @return flag indicating a successful write + @rtype bool + """ + lines = [ + "version: 1.0", + "diagram_type: {0} ({1})".format( + self.__diagramType.value, + self.__getDiagramTitel(self.__diagramType)), + "scene_size: {0};{1}".format(self.scene.width(), + self.scene.height()), + ] + persistenceData = self.builder.getPersistenceData() + if persistenceData: + lines.append("builder_data: {0}".format(persistenceData)) + lines.extend(self.umlView.getPersistenceData()) + + try: + with open(filename, "w", encoding="utf-8") as f: + f.write("\n".join(lines)) + return True + except OSError as err: + E5MessageBox.critical( + self, + self.tr("Save Diagram"), + self.tr( + """<p>The file <b>{0}</b> could not be saved.</p>""" + """<p>Reason: {1}</p>""").format(filename, str(err))) + return False + def __showInvalidDataMessage(self, filename, linenum=-1): """ Private slot to show a message dialog indicating an invalid data file. @@ -396,3 +455,42 @@ ).format(filename, linenum + 1) ) E5MessageBox.critical(self, self.tr("Load Diagram"), msg) + + ####################################################################### + ## Methods to read and write eric graphics files of the JSON based + ## file format. + ####################################################################### + + def __writeJsonGraphicsFile(self, filename): + """ + Private method to write an eric graphics file using the JSON based + file format. + + @param filename name of the file to write to + @type str + @return flag indicating a successful write + @rtype bool + """ + data = { + "version": "1.0", + "type": self.__diagramType.value, + "title": self.__getDiagramTitel(self.__diagramType), + "width": self.scene.width(), + "height": self.scene.height(), + "builder": self.builder.toDict(), + "view": self.umlView.toDict(), + } + + try: + jsonString = json.dumps(data, indent=2) + with open(filename, "w") as f: + f.write(jsonString) + return True + except (TypeError, OSError) as err: + E5MessageBox.critical( + self, + self.tr("Save Diagram"), + self.tr( + """<p>The file <b>{0}</b> could not be saved.</p>""" + """<p>Reason: {1}</p>""").format(filename, str(err))) + return False