eric6/Graphics/UMLGraphicsView.py

branch
maintenance
changeset 8400
b3eefd7e58d1
parent 8273
698ae46f40a4
parent 8295
3f5e8b0a338e
equal deleted inserted replaced
8274:197414ba11cc 8400:b3eefd7e58d1
37 37
38 def __init__(self, scene, parent=None): 38 def __init__(self, scene, parent=None):
39 """ 39 """
40 Constructor 40 Constructor
41 41
42 @param scene reference to the scene object (QGraphicsScene) 42 @param scene reference to the scene object
43 @param parent parent widget of the view (QWidget) 43 @type QGraphicsScene
44 @param parent parent widget of the view
45 @type QWidget
44 """ 46 """
45 E5GraphicsView.__init__(self, scene, parent) 47 E5GraphicsView.__init__(self, scene, parent)
46 self.setObjectName("UMLGraphicsView") 48 self.setObjectName("UMLGraphicsView")
47 self.setViewportUpdateMode( 49 self.setViewportUpdateMode(
48 QGraphicsView.ViewportUpdateMode.FullViewportUpdate) 50 QGraphicsView.ViewportUpdateMode.FullViewportUpdate)
167 UI.PixmapCache.getIcon("shapesAlignBottom"), 169 UI.PixmapCache.getIcon("shapesAlignBottom"),
168 self.tr("Align Bottom"), self) 170 self.tr("Align Bottom"), self)
169 self.alignMapper.setMapping( 171 self.alignMapper.setMapping(
170 self.alignBottomAct, Qt.AlignmentFlag.AlignBottom) 172 self.alignBottomAct, Qt.AlignmentFlag.AlignBottom)
171 self.alignBottomAct.triggered.connect(self.alignMapper.map) 173 self.alignBottomAct.triggered.connect(self.alignMapper.map)
172 174
175 def setLayoutActionsEnabled(self, enable):
176 """
177 Public method to enable or disable the layout related actions.
178
179 @param enable flag indicating the desired enable state
180 @type bool
181 """
182 self.rescanAct.setEnabled(enable)
183 self.relayoutAct.setEnabled(enable)
184
173 def __checkSizeActions(self): 185 def __checkSizeActions(self):
174 """ 186 """
175 Private slot to set the enabled state of the size actions. 187 Private slot to set the enabled state of the size actions.
176 """ 188 """
177 diagramSize = self._getDiagramSize(10) 189 diagramSize = self._getDiagramSize(10)
187 199
188 def __sceneChanged(self, areas): 200 def __sceneChanged(self, areas):
189 """ 201 """
190 Private slot called when the scene changes. 202 Private slot called when the scene changes.
191 203
192 @param areas list of rectangles that contain changes (list of QRectF) 204 @param areas list of rectangles that contain changes
205 @type list of QRectF
193 """ 206 """
194 if len(self.scene().selectedItems()) > 0: 207 if len(self.scene().selectedItems()) > 0:
195 self.deleteShapeAct.setEnabled(True) 208 self.deleteShapeAct.setEnabled(True)
196 else: 209 else:
197 self.deleteShapeAct.setEnabled(False) 210 self.deleteShapeAct.setEnabled(False)
212 225
213 def initToolBar(self): 226 def initToolBar(self):
214 """ 227 """
215 Public method to populate a toolbar with our actions. 228 Public method to populate a toolbar with our actions.
216 229
217 @return the populated toolBar (QToolBar) 230 @return the populated toolBar
231 @rtype QToolBar
218 """ 232 """
219 toolBar = QToolBar(self.tr("Graphics"), self) 233 toolBar = QToolBar(self.tr("Graphics"), self)
220 toolBar.setIconSize(UI.Config.ToolBarIconSize) 234 toolBar.setIconSize(UI.Config.ToolBarIconSize)
221 toolBar.addAction(self.deleteShapeAct) 235 toolBar.addAction(self.deleteShapeAct)
222 toolBar.addSeparator() 236 toolBar.addSeparator()
241 def filteredItems(self, items, itemType=UMLItem): 255 def filteredItems(self, items, itemType=UMLItem):
242 """ 256 """
243 Public method to filter a list of items. 257 Public method to filter a list of items.
244 258
245 @param items list of items as returned by the scene object 259 @param items list of items as returned by the scene object
246 (QGraphicsItem) 260 @type QGraphicsItem
247 @param itemType type to be filtered (class) 261 @param itemType type to be filtered
248 @return list of interesting collision items (QGraphicsItem) 262 @type class
263 @return list of interesting collision items
264 @rtype QGraphicsItem
249 """ 265 """
250 return [itm for itm in items if isinstance(itm, itemType)] 266 return [itm for itm in items if isinstance(itm, itemType)]
251 267
252 def selectItems(self, items): 268 def selectItems(self, items):
253 """ 269 """
254 Public method to select the given items. 270 Public method to select the given items.
255 271
256 @param items list of items to be selected (list of QGraphicsItemItem) 272 @param items list of items to be selected
273 @type list of QGraphicsItemItem
257 """ 274 """
258 # step 1: deselect all items 275 # step 1: deselect all items
259 self.unselectItems() 276 self.unselectItems()
260 277
261 # step 2: select all given items 278 # step 2: select all given items
265 282
266 def selectItem(self, item): 283 def selectItem(self, item):
267 """ 284 """
268 Public method to select an item. 285 Public method to select an item.
269 286
270 @param item item to be selected (QGraphicsItemItem) 287 @param item item to be selected
288 @type QGraphicsItemItem
271 """ 289 """
272 if isinstance(item, UMLItem): 290 if isinstance(item, UMLItem):
273 item.setSelected(not item.isSelected()) 291 item.setSelected(not item.isSelected())
274 292
275 def __deleteShape(self): 293 def __deleteShape(self):
327 def autoAdjustSceneSize(self, limit=False): 345 def autoAdjustSceneSize(self, limit=False):
328 """ 346 """
329 Public method to adjust the scene size to the diagram size. 347 Public method to adjust the scene size to the diagram size.
330 348
331 @param limit flag indicating to limit the scene to the 349 @param limit flag indicating to limit the scene to the
332 initial size (boolean) 350 initial size
351 @type bool
333 """ 352 """
334 super().autoAdjustSceneSize(limit=limit) 353 super().autoAdjustSceneSize(limit=limit)
335 self.__checkSizeActions() 354 self.__checkSizeActions()
336 355
337 def saveImage(self): 356 def saveImage(self):
409 428
410 def printDiagram(self): 429 def printDiagram(self):
411 """ 430 """
412 Public slot called to print the diagram. 431 Public slot called to print the diagram.
413 """ 432 """
414 printer = QPrinter(mode=QPrinter.PrinterMode.ScreenResolution) 433 printer = QPrinter(mode=QPrinter.PrinterMode.PrinterResolution)
415 printer.setFullPage(True) 434 printer.setFullPage(True)
416 if Preferences.getPrinter("ColorMode"): 435 if Preferences.getPrinter("ColorMode"):
417 printer.setColorMode(QPrinter.ColorMode.Color) 436 printer.setColorMode(QPrinter.ColorMode.Color)
418 else: 437 else:
419 printer.setColorMode(QPrinter.ColorMode.GrayScale) 438 printer.setColorMode(QPrinter.ColorMode.GrayScale)
441 """ 460 """
442 Public slot called to show a print preview of the diagram. 461 Public slot called to show a print preview of the diagram.
443 """ 462 """
444 from PyQt5.QtPrintSupport import QPrintPreviewDialog 463 from PyQt5.QtPrintSupport import QPrintPreviewDialog
445 464
446 printer = QPrinter(mode=QPrinter.PrinterMode.ScreenResolution) 465 printer = QPrinter(mode=QPrinter.PrinterMode.PrinterResolution)
447 printer.setFullPage(True) 466 printer.setFullPage(True)
448 if Preferences.getPrinter("ColorMode"): 467 if Preferences.getPrinter("ColorMode"):
449 printer.setColorMode(QPrinter.ColorMode.Color) 468 printer.setColorMode(QPrinter.ColorMode.Color)
450 else: 469 else:
451 printer.setColorMode(QPrinter.ColorMode.GrayScale) 470 printer.setColorMode(QPrinter.ColorMode.GrayScale)
470 489
471 def __printPreviewPrint(self, printer): 490 def __printPreviewPrint(self, printer):
472 """ 491 """
473 Private slot to generate a print preview. 492 Private slot to generate a print preview.
474 493
475 @param printer reference to the printer object (QPrinter) 494 @param printer reference to the printer object
495 @type QPrinter
476 """ 496 """
477 super().printDiagram(printer, self.diagramName) 497 super().printDiagram(printer, self.diagramName)
478 498
479 def setDiagramName(self, name): 499 def setDiagramName(self, name):
480 """ 500 """
481 Public slot to set the diagram name. 501 Public slot to set the diagram name.
482 502
483 @param name diagram name (string) 503 @param name diagram name
504 @type str
484 """ 505 """
485 self.diagramName = name 506 self.diagramName = name
486 507
487 def __alignShapes(self, alignment): 508 def __alignShapes(self, alignment):
488 """ 509 """
489 Private slot to align the selected shapes. 510 Private slot to align the selected shapes.
490 511
491 @param alignment alignment type (Qt.AlignmentFlag) 512 @param alignment alignment type
513 @type Qt.AlignmentFlag
492 """ 514 """
493 # step 1: get all selected items 515 # step 1: get all selected items
494 items = self.scene().selectedItems() 516 items = self.scene().selectedItems()
495 if len(items) <= 1: 517 if len(items) <= 1:
496 return 518 return
562 584
563 def __itemsBoundingRect(self, items): 585 def __itemsBoundingRect(self, items):
564 """ 586 """
565 Private method to calculate the bounding rectangle of the given items. 587 Private method to calculate the bounding rectangle of the given items.
566 588
567 @param items list of items to operate on (list of UMLItem) 589 @param items list of items to operate on
568 @return bounding rectangle (QRectF) 590 @type list of UMLItem
591 @return bounding rectangle
592 @rtype QRectF
569 """ 593 """
570 rect = self.scene().sceneRect() 594 rect = self.scene().sceneRect()
571 right = rect.left() 595 right = rect.left()
572 bottom = rect.top() 596 bottom = rect.top()
573 left = rect.right() 597 left = rect.right()
582 606
583 def keyPressEvent(self, evt): 607 def keyPressEvent(self, evt):
584 """ 608 """
585 Protected method handling key press events. 609 Protected method handling key press events.
586 610
587 @param evt reference to the key event (QKeyEvent) 611 @param evt reference to the key event
612 @type QKeyEvent
588 """ 613 """
589 key = evt.key() 614 key = evt.key()
590 if key in [Qt.Key.Key_Up, Qt.Key.Key_Down, Qt.Key.Key_Left, 615 if key in [Qt.Key.Key_Up, Qt.Key.Key_Down, Qt.Key.Key_Left,
591 Qt.Key.Key_Right]: 616 Qt.Key.Key_Right]:
592 items = self.filteredItems(self.scene().selectedItems()) 617 items = self.filteredItems(self.scene().selectedItems())
616 641
617 def wheelEvent(self, evt): 642 def wheelEvent(self, evt):
618 """ 643 """
619 Protected method to handle wheel events. 644 Protected method to handle wheel events.
620 645
621 @param evt reference to the wheel event (QWheelEvent) 646 @param evt reference to the wheel event
647 @type QWheelEvent
622 """ 648 """
623 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier: 649 if evt.modifiers() & Qt.KeyboardModifier.ControlModifier:
624 delta = evt.angleDelta().y() 650 delta = evt.angleDelta().y()
625 if delta < 0: 651 if delta < 0:
626 self.zoomOut() 652 self.zoomOut()
633 659
634 def event(self, evt): 660 def event(self, evt):
635 """ 661 """
636 Public method handling events. 662 Public method handling events.
637 663
638 @param evt reference to the event (QEvent) 664 @param evt reference to the event
639 @return flag indicating, if the event was handled (boolean) 665 @type QEvent
666 @return flag indicating, if the event was handled
667 @rtype bool
640 """ 668 """
641 if evt.type() == QEvent.Type.Gesture: 669 if evt.type() == QEvent.Type.Gesture:
642 self.gestureEvent(evt) 670 self.gestureEvent(evt)
643 return True 671 return True
644 672
646 674
647 def gestureEvent(self, evt): 675 def gestureEvent(self, evt):
648 """ 676 """
649 Protected method handling gesture events. 677 Protected method handling gesture events.
650 678
651 @param evt reference to the gesture event (QGestureEvent 679 @param evt reference to the gesture event
680 @type QGestureEvent
652 """ 681 """
653 pinch = evt.gesture(Qt.GestureType.PinchGesture) 682 pinch = evt.gesture(Qt.GestureType.PinchGesture)
654 if pinch: 683 if pinch:
655 if pinch.state() == Qt.GestureState.GestureStarted: 684 if pinch.state() == Qt.GestureState.GestureStarted:
656 pinch.setTotalScaleFactor(self.zoom() / 100.0) 685 pinch.setTotalScaleFactor(self.zoom() / 100.0)
660 689
661 def getItemId(self): 690 def getItemId(self):
662 """ 691 """
663 Public method to get the ID to be assigned to an item. 692 Public method to get the ID to be assigned to an item.
664 693
665 @return item ID (integer) 694 @return item ID
695 @rtype int
666 """ 696 """
667 self.__itemId += 1 697 self.__itemId += 1
668 return self.__itemId 698 return self.__itemId
669 699
670 def findItem(self, itemId): 700 def findItem(self, itemId):
671 """ 701 """
672 Public method to find an UML item based on the ID. 702 Public method to find an UML item based on the ID.
673 703
674 @param itemId of the item to search for (integer) 704 @param itemId of the item to search for
675 @return item found (UMLItem) or None 705 @type int
706 @return item found or None
707 @rtype UMLItem
676 """ 708 """
677 for item in self.scene().items(): 709 for item in self.scene().items():
678 try: 710 try:
679 if item.getId() == itemId: 711 if item.getId() == itemId:
680 return item 712 return item
685 717
686 def findItemByName(self, name): 718 def findItemByName(self, name):
687 """ 719 """
688 Public method to find an UML item based on its name. 720 Public method to find an UML item based on its name.
689 721
690 @param name name to look for (string) 722 @param name name to look for
691 @return item found (UMLItem) or None 723 @type str
724 @return item found or None
725 @rtype UMLItem
692 """ 726 """
693 for item in self.scene().items(): 727 for item in self.scene().items():
694 try: 728 try:
695 if item.getName() == name: 729 if item.getName() == name:
696 return item 730 return item
701 735
702 def getPersistenceData(self): 736 def getPersistenceData(self):
703 """ 737 """
704 Public method to get a list of data to be persisted. 738 Public method to get a list of data to be persisted.
705 739
706 @return list of data to be persisted (list of strings) 740 @return list of data to be persisted
741 @rtype list of str
707 """ 742 """
708 lines = [ 743 lines = [
709 "diagram_name: {0}".format(self.diagramName), 744 "diagram_name: {0}".format(self.diagramName),
710 ] 745 ]
711 746
723 758
724 def parsePersistenceData(self, version, data): 759 def parsePersistenceData(self, version, data):
725 """ 760 """
726 Public method to parse persisted data. 761 Public method to parse persisted data.
727 762
728 @param version version of the data (string) 763 @param version version of the data
729 @param data persisted data to be parsed (list of string) 764 @type str
765 @param data persisted data to be parsed
766 @type list of str
730 @return tuple of flag indicating success (boolean) and faulty line 767 @return tuple of flag indicating success (boolean) and faulty line
731 number (integer) 768 number
769 @rtype int
732 """ 770 """
733 umlItems = {} 771 umlItems = {}
734 772
735 if not data[0].startswith("diagram_name:"): 773 if not data[0].startswith("diagram_name:"):
736 return False, 0 774 return False, 0
752 itemId = int(itemId.split("=", 1)[1].strip()) 790 itemId = int(itemId.split("=", 1)[1].strip())
753 x = float(x.split("=", 1)[1].strip()) 791 x = float(x.split("=", 1)[1].strip())
754 y = float(y.split("=", 1)[1].strip()) 792 y = float(y.split("=", 1)[1].strip())
755 itemType = itemType.split("=", 1)[1].strip() 793 itemType = itemType.split("=", 1)[1].strip()
756 if itemType == ClassItem.ItemType: 794 if itemType == ClassItem.ItemType:
757 itm = ClassItem(x=x, y=y, scene=self.scene(), 795 itm = ClassItem(x=0, y=0, scene=self.scene(),
758 colors=self.getDrawingColors()) 796 colors=self.getDrawingColors())
759 elif itemType == ModuleItem.ItemType: 797 elif itemType == ModuleItem.ItemType:
760 itm = ModuleItem(x=x, y=y, scene=self.scene(), 798 itm = ModuleItem(x=0, y=0, scene=self.scene(),
761 colors=self.getDrawingColors()) 799 colors=self.getDrawingColors())
762 elif itemType == PackageItem.ItemType: 800 elif itemType == PackageItem.ItemType:
763 itm = PackageItem(x=x, y=y, scene=self.scene(), 801 itm = PackageItem(x=0, y=0, scene=self.scene(),
764 colors=self.getDrawingColors()) 802 colors=self.getDrawingColors())
803 itm.setPos(x, y)
765 itm.setId(itemId) 804 itm.setId(itemId)
766 umlItems[itemId] = itm 805 umlItems[itemId] = itm
767 if not itm.parseItemDataString(version, itemData): 806 if not itm.parseItemDataString(version, itemData):
768 return False, linenum 807 return False, linenum
769 except ValueError: 808 except ValueError:
776 assoc = AssociationItem(umlItems[srcId], umlItems[dstId], 815 assoc = AssociationItem(umlItems[srcId], umlItems[dstId],
777 assocType, topToBottom) 816 assocType, topToBottom)
778 self.scene().addItem(assoc) 817 self.scene().addItem(assoc)
779 818
780 return True, -1 819 return True, -1
820
821 def toDict(self):
822 """
823 Public method to collect data to be persisted.
824
825 @return dictionary containing data to be persisted
826 @rtype dict
827 """
828 items = [
829 item.toDict()
830 for item in self.filteredItems(self.scene().items(), UMLItem)
831 ]
832
833 from .AssociationItem import AssociationItem
834 associations = [
835 assoc.toDict()
836 for assoc in self.filteredItems(self.scene().items(),
837 AssociationItem)
838 ]
839
840 data = {
841 "diagram_name": self.diagramName,
842 "items": items,
843 "associations": associations,
844 }
845
846 return data
847
848 def fromDict(self, version, data):
849 """
850 Public method to populate the class with data persisted by 'toDict()'.
851
852 @param version version of the data
853 @type str
854 @param data dictionary containing the persisted data
855 @type dict
856 @return flag indicating success
857 @rtype bool
858 """
859 from .UMLItem import UMLItem
860 from .ClassItem import ClassItem
861 from .ModuleItem import ModuleItem
862 from .PackageItem import PackageItem
863 from .AssociationItem import AssociationItem
864
865 umlItems = {}
866
867 try:
868 self.diagramName = data["diagram_name"]
869 for itemData in data["items"]:
870 if itemData["type"] == UMLItem.ItemType:
871 itm = UMLItem.fromDict(
872 itemData, colors=self.getDrawingColors())
873 elif itemData["type"] == ClassItem.ItemType:
874 itm = ClassItem.fromDict(
875 itemData, colors=self.getDrawingColors())
876 elif itemData["type"] == ModuleItem.ItemType:
877 itm = ModuleItem.fromDict(
878 itemData, colors=self.getDrawingColors())
879 elif itemData["type"] == PackageItem.ItemType:
880 itm = PackageItem.fromDict(
881 itemData, colors=self.getDrawingColors())
882 if itm is not None:
883 umlItems[itm.getId()] = itm
884 self.scene().addItem(itm)
885
886 for assocData in data["associations"]:
887 assoc = AssociationItem.fromDict(
888 assocData, umlItems, colors=self.getDrawingColors())
889 self.scene().addItem(assoc)
890
891 return True
892 except KeyError:
893 return False

eric ide

mercurial