Fri, 21 May 2021 18:01:11 +0200
Renamed the E5Graphics stuff to EricGraphics.
--- a/eric7.epj Fri May 21 17:54:15 2021 +0200 +++ b/eric7.epj Fri May 21 18:01:11 2021 +0200 @@ -1072,9 +1072,6 @@ "eric7/DocumentationTools/TemplatesListsStyle.py", "eric7/DocumentationTools/TemplatesListsStyleCSS.py", "eric7/DocumentationTools/__init__.py", - "eric7/E5Graphics/E5ArrowItem.py", - "eric7/E5Graphics/E5GraphicsView.py", - "eric7/E5Graphics/__init__.py", "eric7/E5Gui/E5Action.py", "eric7/E5Gui/E5AnimatedLabel.py", "eric7/E5Gui/E5AnimatedWidget.py", @@ -2278,7 +2275,10 @@ "eric7/eric7_unittest.py", "eric7/eric7_unittest.pyw", "eric7/eric7config.py", - "eric7/DebugClients/Python/eric7dbgstub.py" + "eric7/DebugClients/Python/eric7dbgstub.py", + "eric7/EricGraphics/__init__.py", + "eric7/EricGraphics/EricArrowItem.py", + "eric7/EricGraphics/EricGraphicsView.py" ], "SPELLEXCLUDES": "Dictionaries/excludes.dic", "SPELLLANGUAGE": "en_US",
--- a/eric7/E5Graphics/E5ArrowItem.py Fri May 21 17:54:15 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2007 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Module implementing a graphics item subclass for an arrow. -""" - -import enum -import math - -from PyQt6.QtCore import QPointF, QRectF, QSizeF, QLineF, Qt -from PyQt6.QtGui import QPen, QPolygonF, QColor -from PyQt6.QtWidgets import QAbstractGraphicsShapeItem, QGraphicsItem, QStyle - -ArrowheadAngleFactor = 0.26179938779914941 -# That is: 0.5 * math.atan(math.sqrt(3.0) / 3.0) - - -class E5ArrowType(enum.Enum): - """ - Class defining the arrow types. - """ - NORMAL = 1 - WIDE = 2 - - -class E5ArrowItem(QAbstractGraphicsShapeItem): - """ - Class implementing an arrow graphics item subclass. - """ - def __init__(self, origin=None, end=None, - filled=False, arrowType=E5ArrowType.NORMAL, colors=None, - parent=None): - """ - Constructor - - @param origin origin of the arrow - @type QPointF - @param end end point of the arrow - @type QPointF - @param filled flag indicating a filled arrow head - @type bool - @param arrowType arrow type - @type E5ArrowType - @param colors tuple containing the foreground and background colors - @type tuple of (QColor, QColor) - @param parent reference to the parent object - @type QGraphicsItem - """ - super().__init__(parent) - - self._origin = QPointF() if origin is None else QPointF(origin) - self._end = QPointF() if end is None else QPointF(end) - self._filled = filled - self.__type = arrowType - - if colors is None: - self._colors = (QColor(Qt.GlobalColor.black), - QColor(Qt.GlobalColor.white)) - else: - self._colors = colors - - self._halfLength = 13.0 - - self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable, True) - self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable, True) - - def setPoints(self, xa, ya, xb, yb): - """ - Public method to set the start and end points of the line. - - <b>Note:</b> This method does not redraw the item. - - @param xa x-coordinate of the start point (float) - @param ya y-coordinate of the start point (float) - @param xb x-coordinate of the end point (float) - @param yb y-coordinate of the end point (float) - """ - self._origin = QPointF(xa, ya) - self._end = QPointF(xb, yb) - - def setStartPoint(self, x, y): - """ - Public method to set the start point. - - <b>Note:</b> This method does not redraw the item. - - @param x x-coordinate of the start point (float) - @param y y-coordinate of the start point (float) - """ - self._origin = QPointF(x, y) - - def setEndPoint(self, x, y): - """ - Public method to set the end point. - - <b>Note:</b> This method does not redraw the item. - - @param x x-coordinate of the end point (float) - @param y y-coordinate of the end point (float) - """ - self._end = QPointF(x, y) - - def boundingRect(self): - """ - Public method to return the bounding rectangle. - - @return bounding rectangle (QRectF) - """ - extra = self._halfLength / 2.0 - return QRectF(self._origin, QSizeF(self._end.x() - self._origin.x(), - self._end.y() - self._origin.y()) - ).normalized().adjusted(-extra, -extra, extra, extra) - - def paint(self, painter, option, widget=None): - """ - Public method to paint the item in local coordinates. - - @param painter reference to the painter object (QPainter) - @param option style options (QStyleOptionGraphicsItem) - @param widget optional reference to the widget painted on (QWidget) - """ - width = 2 if ( - (option.state & QStyle.StateFlag.State_Selected) == - QStyle.State(QStyle.StateFlag.State_Selected) - ) else 1 - - # draw the line first - line = QLineF(self._origin, self._end) - painter.setPen( - QPen(self._colors[0], width, Qt.PenStyle.SolidLine, - Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.MiterJoin)) - painter.drawLine(line) - - # draw the arrow head - arrowAngle = ( - ArrowheadAngleFactor - if self.__type == E5ArrowType.NORMAL else - 2 * ArrowheadAngleFactor - ) - slope = math.atan2(line.dy(), line.dx()) - - # Calculate left arrow point - arrowSlope = slope + arrowAngle - a1 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope), - self._end.y() - self._halfLength * math.sin(arrowSlope)) - - # Calculate right arrow point - arrowSlope = slope - arrowAngle - a2 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope), - self._end.y() - self._halfLength * math.sin(arrowSlope)) - - if self._filled: - painter.setBrush(self._colors[0]) - else: - painter.setBrush(self._colors[1]) - polygon = QPolygonF() - polygon.append(line.p2()) - polygon.append(a1) - polygon.append(a2) - painter.drawPolygon(polygon)
--- a/eric7/E5Graphics/E5GraphicsView.py Fri May 21 17:54:15 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,411 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2007 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Module implementing a canvas view class. -""" - -import sys - -from PyQt6.QtCore import pyqtSignal, QRectF, QSize, QSizeF, Qt -from PyQt6.QtGui import QBrush, QPainter, QPixmap, QFont, QColor -from PyQt6.QtWidgets import QGraphicsView - -from E5Gui.E5Application import e5App - -import Preferences - - -class E5GraphicsView(QGraphicsView): - """ - Class implementing a graphics view. - - @signal zoomValueChanged(int) emitted to signal a change of the zoom value - """ - zoomValueChanged = pyqtSignal(int) - - ZoomLevels = [ - 1, 3, 5, 7, 9, - 10, 20, 30, 50, 67, 80, 90, - 100, - 110, 120, 133, 150, 170, 200, 240, 300, 400, - 500, 600, 700, 800, 900, 1000, - ] - ZoomLevelDefault = 100 - - def __init__(self, scene, parent=None): - """ - Constructor - - @param scene reference to the scene object (QGraphicsScene) - @param parent parent widget (QWidget) - """ - super().__init__(scene, parent) - self.setObjectName("E5GraphicsView") - - self.__initialSceneSize = self.scene().sceneRect().size() - self.setBackgroundBrush(QBrush(self.getBackgroundColor())) - self.setRenderHint(QPainter.RenderHint.Antialiasing, True) - self.setDragMode(QGraphicsView.DragMode.RubberBandDrag) - self.setAlignment( - Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop) - self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn) - self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn) - self.setViewportUpdateMode( - QGraphicsView.ViewportUpdateMode.SmartViewportUpdate) - - self.setWhatsThis(self.tr( - "<b>Graphics View</b>\n" - "<p>This graphics view is used to show a diagram. \n" - "There are various actions available to manipulate the \n" - "shown items.</p>\n" - "<ul>\n" - "<li>Clicking on an item selects it.</li>\n" - "<li>Ctrl-clicking adds an item to the selection.</li>\n" - "<li>Ctrl-clicking a selected item deselects it.</li>\n" - "<li>Clicking on an empty spot of the canvas resets the selection." - "</li>\n" - "<li>Dragging the mouse over the canvas spans a rubberband to \n" - "select multiple items.</li>\n" - "<li>Dragging the mouse over a selected item moves the \n" - "whole selection.</li>\n" - "</ul>\n" - )) - - def getDrawingColors(self): - """ - Public method to get the configured drawing colors. - - @return tuple containing the foreground and background colors - @rtype tuple of (QColor, QColor) - """ - drawingMode = Preferences.getGraphics("DrawingMode") - if drawingMode == "automatic": - if e5App().usesDarkPalette(): - drawingMode = "white_black" - else: - drawingMode = "black_white" - - if drawingMode == "white_black": - return (QColor("#ffffff"), QColor("#262626")) - else: - return (QColor("#000000"), QColor("#ffffff")) - - def getForegroundColor(self): - """ - Public method to get the configured foreground color. - - @return foreground color - @rtype QColor - """ - return self.getDrawingColors()[0] - - def getBackgroundColor(self): - """ - Public method to get the configured background color. - - @return background color - @rtype QColor - """ - return self.getDrawingColors()[1] - - def __levelForZoom(self, zoom): - """ - Private method determining the zoom level index given a zoom factor. - - @param zoom zoom factor (integer) - @return index of zoom factor (integer) - """ - try: - index = E5GraphicsView.ZoomLevels.index(zoom) - except ValueError: - for index in range(len(E5GraphicsView.ZoomLevels)): - if zoom <= E5GraphicsView.ZoomLevels[index]: - break - return index - - def zoomIn(self): - """ - Public method to zoom in. - """ - index = self.__levelForZoom(self.zoom()) - if index < len(E5GraphicsView.ZoomLevels) - 1: - self.setZoom(E5GraphicsView.ZoomLevels[index + 1]) - - def zoomOut(self): - """ - Public method to zoom out. - """ - index = self.__levelForZoom(self.zoom()) - if index > 0: - self.setZoom(E5GraphicsView.ZoomLevels[index - 1]) - - def zoomReset(self): - """ - Public method to handle the reset the zoom value. - """ - self.setZoom( - E5GraphicsView.ZoomLevels[E5GraphicsView.ZoomLevelDefault]) - - def setZoom(self, value): - """ - Public method to set the zoom value in percent. - - @param value zoom value in percent (integer) - """ - if value != self.zoom(): - self.resetTransform() - factor = value / 100.0 - self.scale(factor, factor) - self.zoomValueChanged.emit(value) - - def zoom(self): - """ - Public method to get the current zoom factor in percent. - - @return current zoom factor in percent (integer) - """ - return int(self.transform().m11() * 100.0) - - def resizeScene(self, amount, isWidth=True): - """ - Public method to resize the scene. - - @param amount size increment (integer) - @param isWidth flag indicating width is to be resized (boolean) - """ - sceneRect = self.scene().sceneRect() - width = sceneRect.width() - height = sceneRect.height() - if isWidth: - width += amount - else: - height += amount - rect = self._getDiagramRect(10) - if width < rect.width(): - width = rect.width() - if height < rect.height(): - height = rect.height() - - self.setSceneSize(width, height) - - def setSceneSize(self, width, height): - """ - Public method to set the scene size. - - @param width width for the scene (real) - @param height height for the scene (real) - """ - rect = self.scene().sceneRect() - rect.setHeight(height) - rect.setWidth(width) - self.scene().setSceneRect(rect) - - def autoAdjustSceneSize(self, limit=False): - """ - Public method to adjust the scene size to the diagram size. - - @param limit flag indicating to limit the scene to the - initial size (boolean) - """ - size = self._getDiagramSize(10) - if limit: - newWidth = max(size.width(), self.__initialSceneSize.width()) - newHeight = max(size.height(), self.__initialSceneSize.height()) - else: - newWidth = size.width() - newHeight = size.height() - self.setSceneSize(newWidth, newHeight) - - def _getDiagramRect(self, border=0): - """ - Protected method to calculate the minimum rectangle fitting the - diagram. - - @param border border width to include in the calculation (integer) - @return the minimum rectangle (QRectF) - """ - startx = sys.maxsize - starty = sys.maxsize - endx = 0 - endy = 0 - items = self.filteredItems(list(self.scene().items())) - for itm in items: - rect = itm.sceneBoundingRect() - itmEndX = rect.x() + rect.width() - itmEndY = rect.y() + rect.height() - itmStartX = rect.x() - itmStartY = rect.y() - if startx >= itmStartX: - startx = itmStartX - if starty >= itmStartY: - starty = itmStartY - if endx <= itmEndX: - endx = itmEndX - if endy <= itmEndY: - endy = itmEndY - if border: - startx -= border - starty -= border - endx += border - endy += border - - return QRectF(startx, starty, endx - startx + 1, endy - starty + 1) - - def _getDiagramSize(self, border=0): - """ - Protected method to calculate the minimum size fitting the diagram. - - @param border border width to include in the calculation (integer) - @return the minimum size (QSizeF) - """ - endx = 0 - endy = 0 - items = self.filteredItems(list(self.scene().items())) - for itm in items: - rect = itm.sceneBoundingRect() - itmEndX = rect.x() + rect.width() - itmEndY = rect.y() + rect.height() - if endx <= itmEndX: - endx = itmEndX - if endy <= itmEndY: - endy = itmEndY - if border: - endx += border - endy += border - - return QSizeF(endx + 1, endy + 1) - - def __getDiagram(self, rect, imageFormat="PNG", filename=None): - """ - Private method to retrieve the diagram from the scene fitting it - in the minimum rectangle. - - @param rect minimum rectangle fitting the diagram - @type QRectF - @param imageFormat format for the image file - @type str - @param filename name of the file for non pixmaps - str - @return paint device containing the diagram - @rtype QPixmap or QSvgGenerator - """ - selectedItems = self.scene().selectedItems() - - # step 1: deselect all widgets - if selectedItems: - for item in selectedItems: - item.setSelected(False) - - # step 2: grab the diagram - if imageFormat == "PNG": - paintDevice = QPixmap(int(rect.width()), int(rect.height())) - paintDevice.fill(self.backgroundBrush().color()) - else: - from PyQt6.QtSvg import QSvgGenerator - paintDevice = QSvgGenerator() - paintDevice.setResolution(100) # 100 dpi - paintDevice.setSize(QSize(int(rect.width()), int(rect.height()))) - paintDevice.setViewBox(rect) - paintDevice.setFileName(filename) - painter = QPainter(paintDevice) - painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) - self.scene().render(painter, QRectF(), rect) - - # step 3: reselect the widgets - if selectedItems: - for item in selectedItems: - item.setSelected(True) - - return paintDevice - - def saveImage(self, filename, imageFormat="PNG"): - """ - Public method to save the scene to a file. - - @param filename name of the file to write the image to (string) - @param imageFormat format for the image file (string) - @return flag indicating success (boolean) - """ - rect = self._getDiagramRect(self.border) - if imageFormat == "SVG": - self.__getDiagram(rect, imageFormat=imageFormat, filename=filename) - return True - else: - pixmap = self.__getDiagram(rect) - return pixmap.save(filename, imageFormat) - - def printDiagram(self, printer, diagramName=""): - """ - Public method to print the diagram. - - @param printer reference to a ready configured printer object - (QPrinter) - @param diagramName name of the diagram (string) - """ - painter = QPainter(printer) - - font = QFont(["times"], 10) - painter.setFont(font) - fm = painter.fontMetrics() - fontHeight = fm.lineSpacing() - marginX = ( - printer.pageLayout().paintRectPixels(printer.resolution()).x() - - printer.pageLayout().fullRectPixels(printer.resolution()).x() - ) - marginX = ( - Preferences.getPrinter("LeftMargin") * - int(printer.resolution() / 2.54) - marginX - ) - marginY = ( - printer.pageLayout().paintRectPixels(printer.resolution()).y() - - printer.pageLayout().fullRectPixels(printer.resolution()).y() - ) - marginY = ( - Preferences.getPrinter("TopMargin") * - int(printer.resolution() / 2.54) - marginY - ) - - width = ( - printer.width() - marginX - - Preferences.getPrinter("RightMargin") * - int(printer.resolution() / 2.54) - ) - height = ( - printer.height() - fontHeight - 4 - marginY - - Preferences.getPrinter("BottomMargin") * - int(printer.resolution() / 2.54) - ) - - self.scene().render(painter, - target=QRectF(marginX, marginY, width, height)) - - # write a foot note - tc = QColor(50, 50, 50) - painter.setPen(tc) - painter.drawRect(marginX, marginY, width, height) - painter.drawLine(marginX, marginY + height + 2, - marginX + width, marginY + height + 2) - painter.setFont(font) - painter.drawText(marginX, marginY + height + 4, width, - fontHeight, Qt.AlignmentFlag.AlignRight, diagramName) - - painter.end() - - ########################################################################### - ## The methods below should be overridden by subclasses to get special - ## behavior. - ########################################################################### - - def filteredItems(self, items): - """ - Public method to filter a list of items. - - @param items list of items as returned by the scene object - (QGraphicsItem) - @return list of interesting collision items (QGraphicsItem) - """ - # just return the list unchanged - return items
--- a/eric7/E5Graphics/__init__.py Fri May 21 17:54:15 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright (c) 2007 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> -# - -""" -Package implementing some QGraphicsView related general purpoe classes. -"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/EricGraphics/EricArrowItem.py Fri May 21 18:01:11 2021 +0200 @@ -0,0 +1,164 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2007 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a graphics item subclass for an arrow. +""" +# TODO: rename this module to EricArrowItem + +import enum +import math + +from PyQt6.QtCore import QPointF, QRectF, QSizeF, QLineF, Qt +from PyQt6.QtGui import QPen, QPolygonF, QColor +from PyQt6.QtWidgets import QAbstractGraphicsShapeItem, QGraphicsItem, QStyle + +ArrowheadAngleFactor = 0.26179938779914941 +# That is: 0.5 * math.atan(math.sqrt(3.0) / 3.0) + + +class EricArrowType(enum.Enum): + """ + Class defining the arrow types. + """ + NORMAL = 1 + WIDE = 2 + + +class EricArrowItem(QAbstractGraphicsShapeItem): + """ + Class implementing an arrow graphics item subclass. + """ + def __init__(self, origin=None, end=None, + filled=False, arrowType=EricArrowType.NORMAL, colors=None, + parent=None): + """ + Constructor + + @param origin origin of the arrow + @type QPointF + @param end end point of the arrow + @type QPointF + @param filled flag indicating a filled arrow head + @type bool + @param arrowType arrow type + @type EricArrowType + @param colors tuple containing the foreground and background colors + @type tuple of (QColor, QColor) + @param parent reference to the parent object + @type QGraphicsItem + """ + super().__init__(parent) + + self._origin = QPointF() if origin is None else QPointF(origin) + self._end = QPointF() if end is None else QPointF(end) + self._filled = filled + self.__type = arrowType + + if colors is None: + self._colors = (QColor(Qt.GlobalColor.black), + QColor(Qt.GlobalColor.white)) + else: + self._colors = colors + + self._halfLength = 13.0 + + self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable, True) + self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable, True) + + def setPoints(self, xa, ya, xb, yb): + """ + Public method to set the start and end points of the line. + + <b>Note:</b> This method does not redraw the item. + + @param xa x-coordinate of the start point (float) + @param ya y-coordinate of the start point (float) + @param xb x-coordinate of the end point (float) + @param yb y-coordinate of the end point (float) + """ + self._origin = QPointF(xa, ya) + self._end = QPointF(xb, yb) + + def setStartPoint(self, x, y): + """ + Public method to set the start point. + + <b>Note:</b> This method does not redraw the item. + + @param x x-coordinate of the start point (float) + @param y y-coordinate of the start point (float) + """ + self._origin = QPointF(x, y) + + def setEndPoint(self, x, y): + """ + Public method to set the end point. + + <b>Note:</b> This method does not redraw the item. + + @param x x-coordinate of the end point (float) + @param y y-coordinate of the end point (float) + """ + self._end = QPointF(x, y) + + def boundingRect(self): + """ + Public method to return the bounding rectangle. + + @return bounding rectangle (QRectF) + """ + extra = self._halfLength / 2.0 + return QRectF(self._origin, QSizeF(self._end.x() - self._origin.x(), + self._end.y() - self._origin.y()) + ).normalized().adjusted(-extra, -extra, extra, extra) + + def paint(self, painter, option, widget=None): + """ + Public method to paint the item in local coordinates. + + @param painter reference to the painter object (QPainter) + @param option style options (QStyleOptionGraphicsItem) + @param widget optional reference to the widget painted on (QWidget) + """ + width = 2 if ( + (option.state & QStyle.StateFlag.State_Selected) == + QStyle.State(QStyle.StateFlag.State_Selected) + ) else 1 + + # draw the line first + line = QLineF(self._origin, self._end) + painter.setPen( + QPen(self._colors[0], width, Qt.PenStyle.SolidLine, + Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.MiterJoin)) + painter.drawLine(line) + + # draw the arrow head + arrowAngle = ( + ArrowheadAngleFactor + if self.__type == EricArrowType.NORMAL else + 2 * ArrowheadAngleFactor + ) + slope = math.atan2(line.dy(), line.dx()) + + # Calculate left arrow point + arrowSlope = slope + arrowAngle + a1 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope), + self._end.y() - self._halfLength * math.sin(arrowSlope)) + + # Calculate right arrow point + arrowSlope = slope - arrowAngle + a2 = QPointF(self._end.x() - self._halfLength * math.cos(arrowSlope), + self._end.y() - self._halfLength * math.sin(arrowSlope)) + + if self._filled: + painter.setBrush(self._colors[0]) + else: + painter.setBrush(self._colors[1]) + polygon = QPolygonF() + polygon.append(line.p2()) + polygon.append(a1) + polygon.append(a2) + painter.drawPolygon(polygon)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/EricGraphics/EricGraphicsView.py Fri May 21 18:01:11 2021 +0200 @@ -0,0 +1,412 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2007 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a canvas view class. +""" +# TODO: rename this module to EricGraphicsView + +import sys + +from PyQt6.QtCore import pyqtSignal, QRectF, QSize, QSizeF, Qt +from PyQt6.QtGui import QBrush, QPainter, QPixmap, QFont, QColor +from PyQt6.QtWidgets import QGraphicsView + +from E5Gui.E5Application import e5App + +import Preferences + + +class EricGraphicsView(QGraphicsView): + """ + Class implementing a graphics view. + + @signal zoomValueChanged(int) emitted to signal a change of the zoom value + """ + zoomValueChanged = pyqtSignal(int) + + ZoomLevels = [ + 1, 3, 5, 7, 9, + 10, 20, 30, 50, 67, 80, 90, + 100, + 110, 120, 133, 150, 170, 200, 240, 300, 400, + 500, 600, 700, 800, 900, 1000, + ] + ZoomLevelDefault = 100 + + def __init__(self, scene, parent=None): + """ + Constructor + + @param scene reference to the scene object (QGraphicsScene) + @param parent parent widget (QWidget) + """ + super().__init__(scene, parent) + self.setObjectName("EricGraphicsView") + + self.__initialSceneSize = self.scene().sceneRect().size() + self.setBackgroundBrush(QBrush(self.getBackgroundColor())) + self.setRenderHint(QPainter.RenderHint.Antialiasing, True) + self.setDragMode(QGraphicsView.DragMode.RubberBandDrag) + self.setAlignment( + Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignTop) + self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn) + self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn) + self.setViewportUpdateMode( + QGraphicsView.ViewportUpdateMode.SmartViewportUpdate) + + self.setWhatsThis(self.tr( + "<b>Graphics View</b>\n" + "<p>This graphics view is used to show a diagram. \n" + "There are various actions available to manipulate the \n" + "shown items.</p>\n" + "<ul>\n" + "<li>Clicking on an item selects it.</li>\n" + "<li>Ctrl-clicking adds an item to the selection.</li>\n" + "<li>Ctrl-clicking a selected item deselects it.</li>\n" + "<li>Clicking on an empty spot of the canvas resets the selection." + "</li>\n" + "<li>Dragging the mouse over the canvas spans a rubberband to \n" + "select multiple items.</li>\n" + "<li>Dragging the mouse over a selected item moves the \n" + "whole selection.</li>\n" + "</ul>\n" + )) + + def getDrawingColors(self): + """ + Public method to get the configured drawing colors. + + @return tuple containing the foreground and background colors + @rtype tuple of (QColor, QColor) + """ + drawingMode = Preferences.getGraphics("DrawingMode") + if drawingMode == "automatic": + if e5App().usesDarkPalette(): + drawingMode = "white_black" + else: + drawingMode = "black_white" + + if drawingMode == "white_black": + return (QColor("#ffffff"), QColor("#262626")) + else: + return (QColor("#000000"), QColor("#ffffff")) + + def getForegroundColor(self): + """ + Public method to get the configured foreground color. + + @return foreground color + @rtype QColor + """ + return self.getDrawingColors()[0] + + def getBackgroundColor(self): + """ + Public method to get the configured background color. + + @return background color + @rtype QColor + """ + return self.getDrawingColors()[1] + + def __levelForZoom(self, zoom): + """ + Private method determining the zoom level index given a zoom factor. + + @param zoom zoom factor (integer) + @return index of zoom factor (integer) + """ + try: + index = EricGraphicsView.ZoomLevels.index(zoom) + except ValueError: + for index in range(len(EricGraphicsView.ZoomLevels)): + if zoom <= EricGraphicsView.ZoomLevels[index]: + break + return index + + def zoomIn(self): + """ + Public method to zoom in. + """ + index = self.__levelForZoom(self.zoom()) + if index < len(EricGraphicsView.ZoomLevels) - 1: + self.setZoom(EricGraphicsView.ZoomLevels[index + 1]) + + def zoomOut(self): + """ + Public method to zoom out. + """ + index = self.__levelForZoom(self.zoom()) + if index > 0: + self.setZoom(EricGraphicsView.ZoomLevels[index - 1]) + + def zoomReset(self): + """ + Public method to handle the reset the zoom value. + """ + self.setZoom( + EricGraphicsView.ZoomLevels[EricGraphicsView.ZoomLevelDefault]) + + def setZoom(self, value): + """ + Public method to set the zoom value in percent. + + @param value zoom value in percent (integer) + """ + if value != self.zoom(): + self.resetTransform() + factor = value / 100.0 + self.scale(factor, factor) + self.zoomValueChanged.emit(value) + + def zoom(self): + """ + Public method to get the current zoom factor in percent. + + @return current zoom factor in percent (integer) + """ + return int(self.transform().m11() * 100.0) + + def resizeScene(self, amount, isWidth=True): + """ + Public method to resize the scene. + + @param amount size increment (integer) + @param isWidth flag indicating width is to be resized (boolean) + """ + sceneRect = self.scene().sceneRect() + width = sceneRect.width() + height = sceneRect.height() + if isWidth: + width += amount + else: + height += amount + rect = self._getDiagramRect(10) + if width < rect.width(): + width = rect.width() + if height < rect.height(): + height = rect.height() + + self.setSceneSize(width, height) + + def setSceneSize(self, width, height): + """ + Public method to set the scene size. + + @param width width for the scene (real) + @param height height for the scene (real) + """ + rect = self.scene().sceneRect() + rect.setHeight(height) + rect.setWidth(width) + self.scene().setSceneRect(rect) + + def autoAdjustSceneSize(self, limit=False): + """ + Public method to adjust the scene size to the diagram size. + + @param limit flag indicating to limit the scene to the + initial size (boolean) + """ + size = self._getDiagramSize(10) + if limit: + newWidth = max(size.width(), self.__initialSceneSize.width()) + newHeight = max(size.height(), self.__initialSceneSize.height()) + else: + newWidth = size.width() + newHeight = size.height() + self.setSceneSize(newWidth, newHeight) + + def _getDiagramRect(self, border=0): + """ + Protected method to calculate the minimum rectangle fitting the + diagram. + + @param border border width to include in the calculation (integer) + @return the minimum rectangle (QRectF) + """ + startx = sys.maxsize + starty = sys.maxsize + endx = 0 + endy = 0 + items = self.filteredItems(list(self.scene().items())) + for itm in items: + rect = itm.sceneBoundingRect() + itmEndX = rect.x() + rect.width() + itmEndY = rect.y() + rect.height() + itmStartX = rect.x() + itmStartY = rect.y() + if startx >= itmStartX: + startx = itmStartX + if starty >= itmStartY: + starty = itmStartY + if endx <= itmEndX: + endx = itmEndX + if endy <= itmEndY: + endy = itmEndY + if border: + startx -= border + starty -= border + endx += border + endy += border + + return QRectF(startx, starty, endx - startx + 1, endy - starty + 1) + + def _getDiagramSize(self, border=0): + """ + Protected method to calculate the minimum size fitting the diagram. + + @param border border width to include in the calculation (integer) + @return the minimum size (QSizeF) + """ + endx = 0 + endy = 0 + items = self.filteredItems(list(self.scene().items())) + for itm in items: + rect = itm.sceneBoundingRect() + itmEndX = rect.x() + rect.width() + itmEndY = rect.y() + rect.height() + if endx <= itmEndX: + endx = itmEndX + if endy <= itmEndY: + endy = itmEndY + if border: + endx += border + endy += border + + return QSizeF(endx + 1, endy + 1) + + def __getDiagram(self, rect, imageFormat="PNG", filename=None): + """ + Private method to retrieve the diagram from the scene fitting it + in the minimum rectangle. + + @param rect minimum rectangle fitting the diagram + @type QRectF + @param imageFormat format for the image file + @type str + @param filename name of the file for non pixmaps + str + @return paint device containing the diagram + @rtype QPixmap or QSvgGenerator + """ + selectedItems = self.scene().selectedItems() + + # step 1: deselect all widgets + if selectedItems: + for item in selectedItems: + item.setSelected(False) + + # step 2: grab the diagram + if imageFormat == "PNG": + paintDevice = QPixmap(int(rect.width()), int(rect.height())) + paintDevice.fill(self.backgroundBrush().color()) + else: + from PyQt6.QtSvg import QSvgGenerator + paintDevice = QSvgGenerator() + paintDevice.setResolution(100) # 100 dpi + paintDevice.setSize(QSize(int(rect.width()), int(rect.height()))) + paintDevice.setViewBox(rect) + paintDevice.setFileName(filename) + painter = QPainter(paintDevice) + painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) + self.scene().render(painter, QRectF(), rect) + + # step 3: reselect the widgets + if selectedItems: + for item in selectedItems: + item.setSelected(True) + + return paintDevice + + def saveImage(self, filename, imageFormat="PNG"): + """ + Public method to save the scene to a file. + + @param filename name of the file to write the image to (string) + @param imageFormat format for the image file (string) + @return flag indicating success (boolean) + """ + rect = self._getDiagramRect(self.border) + if imageFormat == "SVG": + self.__getDiagram(rect, imageFormat=imageFormat, filename=filename) + return True + else: + pixmap = self.__getDiagram(rect) + return pixmap.save(filename, imageFormat) + + def printDiagram(self, printer, diagramName=""): + """ + Public method to print the diagram. + + @param printer reference to a ready configured printer object + (QPrinter) + @param diagramName name of the diagram (string) + """ + painter = QPainter(printer) + + font = QFont(["times"], 10) + painter.setFont(font) + fm = painter.fontMetrics() + fontHeight = fm.lineSpacing() + marginX = ( + printer.pageLayout().paintRectPixels(printer.resolution()).x() - + printer.pageLayout().fullRectPixels(printer.resolution()).x() + ) + marginX = ( + Preferences.getPrinter("LeftMargin") * + int(printer.resolution() / 2.54) - marginX + ) + marginY = ( + printer.pageLayout().paintRectPixels(printer.resolution()).y() - + printer.pageLayout().fullRectPixels(printer.resolution()).y() + ) + marginY = ( + Preferences.getPrinter("TopMargin") * + int(printer.resolution() / 2.54) - marginY + ) + + width = ( + printer.width() - marginX - + Preferences.getPrinter("RightMargin") * + int(printer.resolution() / 2.54) + ) + height = ( + printer.height() - fontHeight - 4 - marginY - + Preferences.getPrinter("BottomMargin") * + int(printer.resolution() / 2.54) + ) + + self.scene().render(painter, + target=QRectF(marginX, marginY, width, height)) + + # write a foot note + tc = QColor(50, 50, 50) + painter.setPen(tc) + painter.drawRect(marginX, marginY, width, height) + painter.drawLine(marginX, marginY + height + 2, + marginX + width, marginY + height + 2) + painter.setFont(font) + painter.drawText(marginX, marginY + height + 4, width, + fontHeight, Qt.AlignmentFlag.AlignRight, diagramName) + + painter.end() + + ########################################################################### + ## The methods below should be overridden by subclasses to get special + ## behavior. + ########################################################################### + + def filteredItems(self, items): + """ + Public method to filter a list of items. + + @param items list of items as returned by the scene object + (QGraphicsItem) + @return list of interesting collision items (QGraphicsItem) + """ + # just return the list unchanged + return items
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/EricGraphics/__init__.py Fri May 21 18:01:11 2021 +0200 @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2007 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package implementing some QGraphicsView related general purpoe classes. +""" +# TODO: rename this package to EricGraphics
--- a/eric7/Graphics/ApplicationDiagramBuilder.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/ApplicationDiagramBuilder.py Fri May 21 18:01:11 2021 +0200 @@ -388,16 +388,6 @@ colors=self.umlView.getDrawingColors()) self.scene.addItem(assoc) - def getPersistenceData(self): - """ - Public method to get a string for data to be persisted. - - @return persisted data string - @rtype str - """ - return "project={0}, no_modules={1}".format( - self.project.getProjectFile(), self.noModules) - def parsePersistenceData(self, version, data): """ Public method to parse persisted data.
--- a/eric7/Graphics/AssociationItem.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/AssociationItem.py Fri May 21 18:01:11 2021 +0200 @@ -12,7 +12,7 @@ from PyQt6.QtCore import QPointF, QRectF, QLineF from PyQt6.QtWidgets import QGraphicsItem -from E5Graphics.E5ArrowItem import E5ArrowItem, E5ArrowType +from EricGraphics.EricArrowItem import EricArrowItem, EricArrowType import Utilities @@ -42,7 +42,7 @@ CENTER = 9 -class AssociationItem(E5ArrowItem): +class AssociationItem(EricArrowItem): """ Class implementing a graphics item for an association between two items. @@ -69,13 +69,13 @@ @type QGraphicsItem """ if assocType in (AssociationType.NORMAL, AssociationType.IMPORTS): - arrowType = E5ArrowType.NORMAL + arrowType = EricArrowType.NORMAL arrowFilled = True elif assocType == AssociationType.GENERALISATION: - arrowType = E5ArrowType.WIDE + arrowType = EricArrowType.WIDE arrowFilled = False - E5ArrowItem.__init__(self, QPointF(0, 0), QPointF(100, 100), + EricArrowItem.__init__(self, QPointF(0, 0), QPointF(100, 100), arrowFilled, arrowType, colors, parent) self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable, False) @@ -555,24 +555,6 @@ self.itemA.removeAssociation(self) self.itemB.removeAssociation(self) - def buildAssociationItemDataString(self): - """ - Public method to build a string to persist the specific item data. - - This string should be built like "attribute=value" with pairs separated - by ", ". value must not contain ", " or newlines. - - @return persistence data - @rtype str - """ - entries = [ - "src={0}".format(self.itemA.getId()), - "dst={0}".format(self.itemB.getId()), - "type={0}".format(self.assocType.value), - "topToBottom={0}".format(self.topToBottom) - ] - return ", ".join(entries) - @classmethod def parseAssociationItemDataString(cls, data): """
--- a/eric7/Graphics/ClassItem.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/ClassItem.py Fri May 21 18:01:11 2021 +0200 @@ -316,37 +316,6 @@ """ return self.external - def buildItemDataString(self): - """ - Public method to build a string to persist the specific item data. - - This string must start with ", " and should be built like - "attribute=value" with pairs separated by ", ". value must not - contain ", " or newlines. - - @return persistence data - @rtype str - """ - entries = [ - "is_external={0}".format(self.external), - "no_attributes={0}".format(self.noAttrs), - "name={0}".format(self.model.getName()), - ] - instanceAttributes = self.model.getInstanceAttributes() - if instanceAttributes: - entries.append("attributes={0}".format( - "||".join(instanceAttributes))) - methods = self.model.getMethods() - if methods: - entries.append("methods={0}".format( - "||".join(methods))) - classAttributes = self.model.getClassAttributes() - if classAttributes: - entries.append("class_attributes={0}".format( - "||".join(classAttributes))) - - return ", " + ", ".join(entries) - def parseItemDataString(self, version, data): """ Public method to parse the given persistence data.
--- a/eric7/Graphics/ImportsDiagramBuilder.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/ImportsDiagramBuilder.py Fri May 21 18:01:11 2021 +0200 @@ -328,16 +328,6 @@ colors=self.umlView.getDrawingColors()) self.scene.addItem(assoc) - def getPersistenceData(self): - """ - Public method to get a string for data to be persisted. - - @return persisted data string - @rtype str - """ - return "package={0}, show_external={1}".format( - self.packagePath, self.showExternalImports) - def parsePersistenceData(self, version, data): """ Public method to parse persisted data.
--- a/eric7/Graphics/ModuleItem.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/ModuleItem.py Fri May 21 18:01:11 2021 +0200 @@ -176,26 +176,6 @@ self.adjustAssociations() - def buildItemDataString(self): - """ - Public method to build a string to persist the specific item data. - - This string must start with ", " and should be built like - "attribute=value" with pairs separated by ", ". value must not - contain ", " or newlines. - - @return persistence data - @rtype str - """ - entries = [ - "name={0}".format(self.model.getName()), - ] - classes = self.model.getClasses() - if classes: - entries.append("classes={0}".format("||".join(classes))) - - return ", " + ", ".join(entries) - def parseItemDataString(self, version, data): """ Public method to parse the given persistence data.
--- a/eric7/Graphics/PackageDiagramBuilder.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/PackageDiagramBuilder.py Fri May 21 18:01:11 2021 +0200 @@ -474,16 +474,6 @@ colors=self.umlView.getDrawingColors()) self.scene.addItem(assoc) - def getPersistenceData(self): - """ - Public method to get a string for data to be persisted. - - @return persisted data string - @rtype str - """ - return "package={0}, no_attributes={1}".format( - self.package, self.noAttrs) - def parsePersistenceData(self, version, data): """ Public method to parse persisted data.
--- a/eric7/Graphics/PackageItem.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/PackageItem.py Fri May 21 18:01:11 2021 +0200 @@ -202,27 +202,6 @@ self.adjustAssociations() - def buildItemDataString(self): - """ - Public method to build a string to persist the specific item data. - - This string must start with ", " and should be built like - "attribute=value" with pairs separated by ", ". value must not - contain ", " or newlines. - - @return persistence data - @rtype str - """ - entries = [ - "no_modules={0}".format(self.noModules), - "name={0}".format(self.model.getName()), - ] - modules = self.model.getModules() - if modules: - entries.append("modules={0}".format("||".join(modules))) - - return ", " + ", ".join(entries) - def parseItemDataString(self, version, data): """ Public method to parse the given persistence data.
--- a/eric7/Graphics/UMLClassDiagramBuilder.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/UMLClassDiagramBuilder.py Fri May 21 18:01:11 2021 +0200 @@ -314,15 +314,6 @@ colors=self.umlView.getDrawingColors()) self.scene.addItem(assoc) - def getPersistenceData(self): - """ - Public method to get a string for data to be persisted. - - @return persisted data string - @rtype str - """ - return "file={0}, no_attributes={1}".format(self.file, self.noAttrs) - def parsePersistenceData(self, version, data): """ Public method to parse persisted data.
--- a/eric7/Graphics/UMLDiagramBuilder.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/UMLDiagramBuilder.py Fri May 21 18:01:11 2021 +0200 @@ -65,15 +65,6 @@ raise NotImplementedError( "Method 'buildDiagram' must be implemented in subclasses.") - def getPersistenceData(self): - """ - Public method to get a string for data to be persisted. - - @return persisted data string - @rtype str - """ - return "" - def parsePersistenceData(self, version, data): """ Public method to parse persisted data.
--- a/eric7/Graphics/UMLDialog.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/UMLDialog.py Fri May 21 18:01:11 2021 +0200 @@ -265,18 +265,13 @@ return filename = fname - res = ( - self.__writeLineBasedGraphicsFile(filename) - if filename.endswith(".e5g") else - # JSON format is the default - self.__writeJsonGraphicsFile(filename) - ) + res = self.__writeJsonGraphicsFile(filename) if res: # save the file name only in case of success self.__fileName = filename - # TODO: eric7: delete the current one + # Note: remove loading of eric6 line based diagram format after 22.6 def load(self, filename=""): """ Public method to load a diagram from a file. @@ -406,42 +401,42 @@ 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 __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.
--- a/eric7/Graphics/UMLGraphicsView.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/UMLGraphicsView.py Fri May 21 18:01:11 2021 +0200 @@ -4,7 +4,7 @@ # """ -Module implementing a subclass of E5GraphicsView for our diagrams. +Module implementing a subclass of EricGraphicsView for our diagrams. """ from PyQt6.QtCore import ( @@ -14,7 +14,7 @@ from PyQt6.QtWidgets import QGraphicsView, QToolBar, QDialog from PyQt6.QtPrintSupport import QPrinter, QPrintDialog -from E5Graphics.E5GraphicsView import E5GraphicsView +from EricGraphics.EricGraphicsView import EricGraphicsView from E5Gui import E5MessageBox, E5FileDialog from E5Gui.E5ZoomWidget import E5ZoomWidget @@ -27,9 +27,9 @@ import Preferences -class UMLGraphicsView(E5GraphicsView): +class UMLGraphicsView(EricGraphicsView): """ - Class implementing a specialized E5GraphicsView for our diagrams. + Class implementing a specialized EricGraphicsView for our diagrams. @signal relayout() emitted to indicate a relayout of the diagram is requested @@ -45,7 +45,7 @@ @param parent parent widget of the view @type QWidget """ - E5GraphicsView.__init__(self, scene, parent) + EricGraphicsView.__init__(self, scene, parent) self.setObjectName("UMLGraphicsView") self.setViewportUpdateMode( QGraphicsView.ViewportUpdateMode.FullViewportUpdate) @@ -62,7 +62,7 @@ UI.PixmapCache.getPixmap("zoomReset"), self) parent.statusBar().addPermanentWidget(self.__zoomWidget) self.__zoomWidget.setMapping( - E5GraphicsView.ZoomLevels, E5GraphicsView.ZoomLevelDefault) + EricGraphicsView.ZoomLevels, EricGraphicsView.ZoomLevelDefault) self.__zoomWidget.valueChanged.connect(self.setZoom) self.zoomValueChanged.connect(self.__zoomWidget.setValue) @@ -734,29 +734,6 @@ return None - def getPersistenceData(self): - """ - Public method to get a list of data to be persisted. - - @return list of data to be persisted - @rtype list of str - """ - lines = [ - "diagram_name: {0}".format(self.diagramName), - ] - - for item in self.filteredItems(self.scene().items(), UMLItem): - lines.append("item: id={0}, x={1}, y={2}, item_type={3}{4}".format( - item.getId(), item.x(), item.y(), item.getItemType(), - item.buildItemDataString())) - - from .AssociationItem import AssociationItem - for item in self.filteredItems(self.scene().items(), AssociationItem): - lines.append("association: {0}".format( - item.buildAssociationItemDataString())) - - return lines - def parsePersistenceData(self, version, data): """ Public method to parse persisted data.
--- a/eric7/Graphics/UMLItem.py Fri May 21 17:54:15 2021 +0200 +++ b/eric7/Graphics/UMLItem.py Fri May 21 18:01:11 2021 +0200 @@ -253,19 +253,6 @@ """ return self.ItemType - def buildItemDataString(self): - """ - Public method to build a string to persist the specific item data. - - This string must start with ", " and should be built like - "attribute=value" with pairs separated by ", ". value must not - contain ", " or newlines. - - @return persistence data - @rtype str - """ - return "" - def parseItemDataString(self, version, data): """ Public method to parse the given persistence data.