Exemple #1
0
    def _getPyutLink(self, obj):
        """
        To extract a PyutLink from an OglLink object.

        @param String obj : Name of the object.
        """
        link = obj.getElementsByTagName("Link")[0]

        aLink = PyutLink()

        aLink.setBidir(bool(link.getAttribute('bidir')))

        # aLink.setDestinationCardinality(link.getAttribute('cardDestination'))
        # aLink.setSourceCardinality(link.getAttribute('cardSrc'))
        aLink.destinationCardinality = link.getAttribute('cardDestination')
        aLink.sourceCardinality = link.getAttribute('cardSrc')

        aLink.setName(link.getAttribute('name'))
        strLinkType: str = link.getAttribute('type')
        linkType: LinkType = LinkType(int(strLinkType))
        aLink.setType(linkType)
        # source and destination will be reconstructed by _getOglLinks

        sourceId = int(link.getAttribute('sourceId'))
        destId = int(link.getAttribute('destId'))

        return sourceId, destId, aLink
    def _pyutLinkToXml(self, pyutLink: PyutLink, xmlDoc: Document) -> Element:
        """
        Exporting a PyutLink to a miniDom Element.

        Args:
            pyutLink:   Link to save
            xmlDoc:     xml document

        Returns:
            A new minidom element
        """
        root: Element = xmlDoc.createElement(
            PyutXmlConstants.ELEMENT_MODEL_LINK)

        root.setAttribute(PyutXmlConstants.ATTR_NAME, pyutLink.getName())
        root.setAttribute(PyutXmlConstants.ATTR_TYPE, pyutLink.getType().name)
        root.setAttribute(PyutXmlConstants.ATTR_CARDINALITY_SOURCE,
                          pyutLink.sourceCardinality)
        root.setAttribute(PyutXmlConstants.ATTR_CARDINALITY_DESTINATION,
                          pyutLink.destinationCardinality)
        root.setAttribute(PyutXmlConstants.ATTR_BIDIRECTIONAL,
                          str(pyutLink.getBidir()))

        srcLinkId: int = self._idFactory.getID(pyutLink.getSource())
        destLinkId: int = self._idFactory.getID(pyutLink.getDestination())

        root.setAttribute(PyutXmlConstants.ATTR_SOURCE_ID, str(srcLinkId))
        root.setAttribute(PyutXmlConstants.ATTR_DESTINATION_ID,
                          str(destLinkId))

        return root
Exemple #3
0
    def _PyutLink2xml(self, pyutLink: PyutLink):
        """
        Convert a PyutLink to an miniDom Element

        Args:
            pyutLink:

        Returns:    An XML element
        """
        # adding links in dictionary
        if pyutLink in self.__savedLinks:
            return None
        self.__savedLinks[pyutLink] = 1

        root = Element('Link')
        # link name
        root.setAttribute('name', pyutLink.getName())

        # link type
        root.setAttribute('type', str(pyutLink.getType()))

        # link cardinality source
        root.setAttribute('cardSrc', pyutLink.sourceCardinality)

        # link cardinality destination
        # root.setAttribute('cardDestination', pyutLink.getDestinationCardinality())
        root.setAttribute('cardDestination', pyutLink.destinationCardinality)

        # link bidir
        root.setAttribute('bidir', str(pyutLink.getBidir()))

        # link destination
        root.setAttribute('destination', pyutLink.getDestination().getName())

        return root
Exemple #4
0
 def setSource(self, src=None, srcTime=-1):
     """
     Define the source
     @param src : Source object
     @param srcTime : Time on the source
     @author C.Dutoit
     """
     if src is not None:
         # self._src = src
         PyutLink.setSource(self, src)
     if srcTime != -1:
         self.logger.debug(f"PyutSDMessage - Setting srcTime to: {srcTime}")
         self.setSrcTime(srcTime)
Exemple #5
0
    def setDestination(self, dst=None, dstTime=-1):
        """
        Define the destination

        Args:
            dst:        destination object
            dstTime:    Time on the destination
        """
        if dst is not None:
            PyutLink.setDestination(self, dst)
        if dstTime != -1:
            self.logger.debug(f"Setting dstTime to {dstTime}")
            self.setDstTime(dstTime)
Exemple #6
0
 def setDestination(self, dst=None, dstTime=-1):
     """
     Define the destination
     @param dst : destination object
     @param dstTime : Time on the destination
     @author C.Dutoit
     """
     if dst is not None:
         PyutLink.setDestination(self, dst)
         # self._dest = dst
     if dstTime != -1:
         print("PyutSDMessage - Setting dstTime to ", dstTime)
         self.setDstTime(dstTime)
    def createInheritanceLink(self, child: OglClass,
                              parent: OglClass) -> OglLink:
        """
        TODO: this is a duplicate of CreateOglLinkCommandCommand._createInheritanceLink (this code adds it to the frame)

        Add a parent link between the child and parent objects.

        Args:
            child:  Child PyutClass
            parent: Parent PyutClass

        Returns:
            The inheritance OglLink
        """
        pyutLink = PyutLink("",
                            linkType=LinkType.INHERITANCE,
                            source=child.getPyutObject(),
                            destination=parent.getPyutObject())
        oglLink = getOglLinkFactory().getOglLink(child, pyutLink, parent,
                                                 LinkType.INHERITANCE)

        child.addLink(oglLink)
        parent.addLink(oglLink)

        # add it to the PyutClass
        # child.getPyutObject().addParent(parent.getPyutObject())
        childPyutClass: PyutClass = child.getPyutObject()
        parentPyutClass: PyutClass = parent.getPyutObject()

        childPyutClass.addParent(parentPyutClass)

        self._diagram.AddShape(oglLink)
        self.Refresh()

        return oglLink
Exemple #8
0
    def _createInheritanceLink(self, child: OglClass,
                               parent: OglClass) -> OglLink:
        """
        Add a parent link between the child and parent objects.

        Args:
            child:  Child PyutClass
            parent: Parent PyutClass

        Returns:
            The inheritance OglLink
        """
        sourceClass: PyutClass = cast(PyutClass, child.pyutObject)
        destinationClass: PyutClass = cast(PyutClass, parent.pyutObject)
        pyutLink: PyutLink = PyutLink("",
                                      linkType=LinkType.INHERITANCE,
                                      source=sourceClass,
                                      destination=destinationClass)
        oglLink: OglLink = getOglLinkFactory().getOglLink(
            child, pyutLink, parent, LinkType.INHERITANCE)

        child.addLink(oglLink)
        parent.addLink(oglLink)

        # add it to the PyutClass
        # child.getPyutObject().addParent(parent.getPyutObject())
        childPyutClass: PyutClass = cast(PyutClass, child.pyutObject)
        parentPyutClass: PyutClass = cast(PyutClass, parent.pyutObject)

        childPyutClass.addParent(parentPyutClass)

        return oglLink
Exemple #9
0
    def createLink(self,
                   src: OglClass,
                   dst: OglClass,
                   linkType: LinkType = LinkType.AGGREGATION):
        """
        Used to create links;  It is still the caller's responsibility to add the created shape to the
        appropriate diagram

        Args:
            src:        The source OglClass
            dst:        The destination OglClass
            linkType:   The type of link
        """
        sourceClass: PyutClass = cast(PyutClass, src.getPyutObject())
        destinationClass: PyutClass = cast(PyutClass, dst.getPyutObject())

        pyutLink: PyutLink = PyutLink("",
                                      linkType=linkType,
                                      source=sourceClass,
                                      destination=destinationClass)

        oglLinkFactory = getOglLinkFactory()
        oglLink = oglLinkFactory.getOglLink(src, pyutLink, dst, linkType)

        src.addLink(oglLink)
        dst.addLink(oglLink)

        # src.getPyutObject().addLink(pyutLink)       # TODO fix this
        pyutClass: PyutClass = cast(PyutClass, src.getPyutObject())
        pyutClass.addLink(pyutLink)

        return oglLink
Exemple #10
0
    def _getPyutLink(self, obj: Element):
        """

        Args:
            obj:  The GraphicLink DOM element

        Returns:
            A tuple of a source ID, destination ID, and a PyutLink object
        """
        link: Element = obj.getElementsByTagName(
            PyutXmlConstants.ELEMENT_MODEL_LINK)[0]

        pyutLink: PyutLink = PyutLink()

        pyutLink.setBidir(
            bool(link.getAttribute(PyutXmlConstants.ATTR_BIDIRECTIONAL)))

        pyutLink.destinationCardinality = link.getAttribute(
            PyutXmlConstants.ATTR_CARDINALITY_DESTINATION)
        pyutLink.sourceCardinality = link.getAttribute(
            PyutXmlConstants.ATTR_CARDINALITY_SOURCE)

        pyutLink.setName(link.getAttribute(PyutXmlConstants.ATTR_NAME))

        strLinkType: str = link.getAttribute(PyutXmlConstants.ATTR_TYPE)
        strLinkType = strLinkType.replace(PyutXmlConstants.V9_LINK_PREFIX, '')
        linkType: LinkType = LinkType.toEnum(strValue=strLinkType)
        pyutLink.setType(linkType)

        # source and destination will be reconstructed by _getOglLinks
        sourceId = int(link.getAttribute(PyutXmlConstants.ATTR_SOURCE_ID))
        destId = int(link.getAttribute(PyutXmlConstants.ATTR_DESTINATION_ID))

        return sourceId, destId, pyutLink
Exemple #11
0
    def createInterfaceLink(self, src: OglClass,
                            dst: OglClass) -> OglInterface:
        """
        Adds an OglInterface link between src and dst.

        Args:
            src:    source of the link
            dst:    destination of the link

        Returns: the created OglInterface link
        """
        sourceClass: PyutClass = cast(PyutClass, src.getPyutObject())
        destinationClass: PyutClass = cast(PyutClass, dst.getPyutObject())

        pyutLink: PyutLink = PyutLink(linkType=LinkType.INTERFACE,
                                      source=sourceClass,
                                      destination=destinationClass)
        oglInterface: OglInterface = OglInterface(srcShape=src,
                                                  pyutLink=pyutLink,
                                                  dstShape=dst)

        src.addLink(oglInterface)
        dst.addLink(oglInterface)

        self._diagram.AddShape(oglInterface)
        self.Refresh()

        return oglInterface
Exemple #12
0
    def testLegacyValidLinkType(self):

        legacyPyutLink: PyutLink = PyutLink(name='ValidLegacyPyutLink')
        legacyValue: LinkType = LinkType.COMPOSITION

        legacyPyutLink.setType(legacyValue)

        expectedLinkType: LinkType = LinkType.COMPOSITION
        actualLinkType: LinkType = legacyPyutLink.getType()

        self.assertEqual(expectedLinkType, actualLinkType,
                         'Incorrect  valid legacy type support')
Exemple #13
0
    def testLegacyInvalidLinkType(self):

        legacyPyutLink: PyutLink = PyutLink(name='InvalidLegacyPyutLink')
        legacyValue: int = LinkType.NOTELINK.value + 99

        # noinspection PyTypeChecker
        legacyPyutLink.setType(legacyValue)

        expectedLinkType: LinkType = LinkType.INHERITANCE
        actualLinkType: LinkType = legacyPyutLink.getType()

        self.assertEqual(expectedLinkType, actualLinkType,
                         'Incorrect legacy invalid type support')
Exemple #14
0
    def testLegacyLinkType(self):

        legacyPyutLink: PyutLink = PyutLink(name='LegacyPyutLink')
        legacyValue: int = LinkType.NOTELINK.value

        # noinspection PyTypeChecker
        legacyPyutLink.setType(legacyValue)

        expectedLinkType: LinkType = LinkType.NOTELINK
        actualLinkType: LinkType = legacyPyutLink.getType()

        self.assertEqual(expectedLinkType, actualLinkType,
                         'Incorrect legacy support')
Exemple #15
0
    def _PyutLink2xml(self, pyutLink: PyutLink):
        """
        Exporting an PyutLink to an miniDom Element

        @since 2.0
        @Deve Roux <*****@*****.**>

        @param pyutLink
        @return Element
        """

        # hadding links in dictionnary
        if pyutLink in self.__savedLinks:
            return None
        self.__savedLinks[pyutLink] = 1

        root = Element('Link')
        # link name
        root.setAttribute('name', pyutLink.getName())

        # link type
        root.setAttribute('type', str(pyutLink.getType()))

        # link cardinality source
        root.setAttribute('cardSrc', pyutLink.sourceCardinality)

        # link cardinality destination
        # root.setAttribute('cardDestination', pyutLink.getDestinationCardinality())
        root.setAttribute('cardDestination', pyutLink.destinationCardinality)

        # link bidir
        root.setAttribute('bidir', str(pyutLink.getBidir()))

        # link destination
        root.setAttribute('destination', pyutLink.getDestination().getName())

        return root
Exemple #16
0
    def _PyutLink2xml(self, pyutLink: PyutLink, xmlDoc):
        """
        Exporting an PyutLink to a miniDom Element.

        @param PyutLink pyutLink : Link to save
        @param xmlDoc : xml document
        @return Element : XML Node
        """

        root = xmlDoc.createElement('Link')
        # link name
        root.setAttribute('name', pyutLink.getName())

        # link type
        root.setAttribute('type', str(pyutLink.getType().value))

        # link cardinality source
        # root.setAttribute('cardSrc', pyutLink.getSourceCardinality())
        root.setAttribute('cardSrc', pyutLink.sourceCardinality)

        # link cardinality destination
        # root.setAttribute('cardDestination', pyutLink.getDestinationCardinality())
        root.setAttribute('cardDestination', pyutLink.destinationCardinality)

        # link bidir
        root.setAttribute('bidir', str(pyutLink.getBidir()))

        # link source
        srcLinkId = self._idFactory.getID(pyutLink.getSource())
        root.setAttribute('sourceId', str(srcLinkId))

        # link destination
        destLinkId = self._idFactory.getID(pyutLink.getDestination())
        root.setAttribute('destId', str(destLinkId))

        return root
Exemple #17
0
    def __createMockLink(self, src: MagicMock, dest: MagicMock) -> MagicMock:
        """
        pyutLink = PyutLink("", linkType=linkType, source=src.getPyutObject(), destination=dst.getPyutObject())

        oglLink = oglLinkFactory.getOglLink(src, pyutLink, dst, linkType)

        src.addLink(oglLink)
        dst.addLink(oglLink)

        src.getPyutObject().addLink(pyutLink)

        Args:
            src:    Mock OglClass
            dest:   Mock OglClass

        Returns:
            Mocked OglLink
        """
        oglLink: MagicMock = MagicMock(spec=OglLink)
        linkId = next(self._linkIDGenerator)
        oglLink.GetID.return_value = linkId

        mockSourceAnchor: MagicMock = MagicMock(spec=AnchorPoint)
        mockDestinationAnchor: MagicMock = MagicMock(spec=AnchorPoint)

        mockSourceAnchor.GetPosition.return_value = (22, 44)
        mockDestinationAnchor.GetPosition.return_value = (1024, 450)

        oglLink.sourceAnchor.return_value = mockSourceAnchor
        oglLink.destinationAnchor.return_value = mockDestinationAnchor

        oglLink.getSourceShape.return_value = src
        oglLink.getDestinationShape.return_value = dest
        #
        # PyutLink object simple enough so create real one
        pyutLink: PyutLink = PyutLink("",
                                      linkType=LinkType.INHERITANCE,
                                      source=src.getPyutObject(),
                                      destination=dest.getPyutObject())

        src.getLinks.return_value = [oglLink]
        dest.getLinks.return_value = [oglLink]

        mockPyutClass = src.getPyutObject()
        mockPyutClass.getLinks.return_value = [pyutLink]

        return oglLink
Exemple #18
0
    def _createLink(self,
                    src,
                    dst,
                    linkType: LinkType = LinkType.INHERITANCE,
                    srcPos=None,
                    dstPos=None):
        """
        Add a link between src and dst without adding it to the frame.

        Args:
            src:        Source of the link
            dst:        Destination of the link
            linkType:   Type of the link
            srcPos:     Position on source
            dstPos:     Position destination

        Returns:    The created link
        """
        if linkType == LinkType.INHERITANCE:
            return self._createInheritanceLink(src, dst)
        elif linkType == LinkType.SD_MESSAGE:
            return self._createSDMessage(src=src,
                                         dest=dst,
                                         srcPos=srcPos,
                                         destPos=dstPos)
        pyutLink = PyutLink("",
                            linkType=linkType,
                            source=src.getPyutObject(),
                            destination=dst.getPyutObject())

        # Call the factory to create OGL Link
        oglLinkFactory = getOglLinkFactory()
        # oglLink = oglLinkFactory.getOglLink(src, pyutLink, dst, linkType)
        oglLink = oglLinkFactory.getOglLink(srcShape=src,
                                            pyutLink=pyutLink,
                                            destShape=dst,
                                            linkType=linkType)

        src.addLink(oglLink)  # add it to the source OglShape
        dst.addLink(oglLink)  # add it to the destination OglShape

        src.getPyutObject().addLink(pyutLink)  # add it to the PyutClass

        return oglLink
Exemple #19
0
    def __init__(self, srcShape, pyutLink, dstShape, srcPos=None, dstPos=None):
        """

        Args:
            srcShape:   Source shape
            pyutLink:   Conceptual links associated with the graphical links.
            dstShape:   Destination shape
            srcPos:     Position of source      Override location of input source
            dstPos:     Position of destination Override location of input destination
        """
        self._srcShape = srcShape
        self._destShape = dstShape

        self.clsLogger.debug(
            f'Input Override positions - srcPos: {srcPos} dstPos: {dstPos}')
        if srcPos is None and dstPos is None:
            srcX, srcY = self._srcShape.GetPosition()
            dstX, dstY = self._destShape.GetPosition()

            orient = getOrient(srcX, srcY, dstX, dstY)

            sw, sh = self._srcShape.GetSize()
            dw, dh = self._destShape.GetSize()
            if orient == AttachmentPoint.NORTH:
                srcX, srcY = sw / 2, 0
                dstX, dstY = dw / 2, dh
            elif orient == AttachmentPoint.SOUTH:
                srcX, srcY = sw / 2, sh
                dstX, dstY = dw / 2, 0
            elif orient == AttachmentPoint.EAST:
                srcX, srcY = sw, sh / 2
                dstX, dstY = 0, dh / 2
            elif orient == AttachmentPoint.WEST:
                srcX, srcY = 0, sh / 2
                dstX, dstY = dw, dh / 2

            # ============== Avoid over-lining; Added by C.Dutoit ================
            # lstAnchorsPoints = [anchor.GetRelativePosition() for anchor in srcShape.GetAnchors()]
            # while (srcX, srcY) in lstAnchorsPoints:
            #     self.clsLogger.warning(f'Over-lining in source shape')
            #     if orient == PyutAttachmentPoint.NORTH or orient == PyutAttachmentPoint.SOUTH:
            #         srcX += 10
            #     else:
            #         srcY += 10
            #
            # lstAnchorsPoints = [anchor.GetRelativePosition() for anchor in dstShape.GetAnchors()]
            # while (dstX, dstY) in lstAnchorsPoints:
            #     from org.pyut.ogl.OglClass import OglClass
            #     dstShape: OglClass = cast(OglClass, dstShape)
            #     self.clsLogger.warning(f'Over-lining in destination shape: {dstShape.getPyutObject}')
            #     if orient == PyutAttachmentPoint.NORTH or orient == PyutAttachmentPoint.SOUTH:
            #         dstX += 10
            #     else:
            #         dstY += 10

            # =========== end avoid over-lining-Added by C.Dutoit ================
        else:
            # Use provided position
            (srcX, srcY) = srcPos
            (dstX, dstY) = dstPos

        srcAnchor: AnchorPoint = self._srcShape.AddAnchor(srcX, srcY)
        dstAnchor: AnchorPoint = self._destShape.AddAnchor(dstX, dstY)
        srcAnchor.SetPosition(srcX, srcY)
        dstAnchor.SetPosition(dstX, dstY)
        srcAnchor.SetVisible(False)
        dstAnchor.SetVisible(False)
        self.clsLogger.debug(
            f'src anchor pos: {srcAnchor.GetPosition()} dst anchor pos {dstAnchor.GetPosition()}'
        )
        srcAnchor.SetDraggable(True)
        dstAnchor.SetDraggable(True)
        # Init
        LineShape.__init__(self, srcAnchor, dstAnchor)
        # Set up painting colors
        self.SetPen(BLACK_PEN)
        # Keep reference to the PyutLink for mouse events, in order
        # to can find back the corresponding link
        if pyutLink is not None:
            self._link = pyutLink
        else:
            self._link = PyutLink()
Exemple #20
0
class OglLink(LineShape, ShapeEventHandler):
    """
    Abstract class for graphical link.
    This class should be the base class for every type of link. It implements
    the following functions :
        - Link between objects position management
        - Control points (2)
        - Data layer link association
        - Source and destination objects

    You can inherit from this class to implement your favorite type of links
    like `OglAssociation`.

    There is a link factory (See `OglLinkFactory`) you can use to build
    the different type of links that exist.

    """
    clsLogger: Logger = getLogger(__name__)

    def __init__(self, srcShape, pyutLink, dstShape, srcPos=None, dstPos=None):
        """

        Args:
            srcShape:   Source shape
            pyutLink:   Conceptual links associated with the graphical links.
            dstShape:   Destination shape
            srcPos:     Position of source      Override location of input source
            dstPos:     Position of destination Override location of input destination
        """
        self._srcShape = srcShape
        self._destShape = dstShape

        self.clsLogger.debug(
            f'Input Override positions - srcPos: {srcPos} dstPos: {dstPos}')
        if srcPos is None and dstPos is None:
            srcX, srcY = self._srcShape.GetPosition()
            dstX, dstY = self._destShape.GetPosition()

            orient = getOrient(srcX, srcY, dstX, dstY)

            sw, sh = self._srcShape.GetSize()
            dw, dh = self._destShape.GetSize()
            if orient == AttachmentPoint.NORTH:
                srcX, srcY = sw / 2, 0
                dstX, dstY = dw / 2, dh
            elif orient == AttachmentPoint.SOUTH:
                srcX, srcY = sw / 2, sh
                dstX, dstY = dw / 2, 0
            elif orient == AttachmentPoint.EAST:
                srcX, srcY = sw, sh / 2
                dstX, dstY = 0, dh / 2
            elif orient == AttachmentPoint.WEST:
                srcX, srcY = 0, sh / 2
                dstX, dstY = dw, dh / 2

            # ============== Avoid over-lining; Added by C.Dutoit ================
            # lstAnchorsPoints = [anchor.GetRelativePosition() for anchor in srcShape.GetAnchors()]
            # while (srcX, srcY) in lstAnchorsPoints:
            #     self.clsLogger.warning(f'Over-lining in source shape')
            #     if orient == PyutAttachmentPoint.NORTH or orient == PyutAttachmentPoint.SOUTH:
            #         srcX += 10
            #     else:
            #         srcY += 10
            #
            # lstAnchorsPoints = [anchor.GetRelativePosition() for anchor in dstShape.GetAnchors()]
            # while (dstX, dstY) in lstAnchorsPoints:
            #     from org.pyut.ogl.OglClass import OglClass
            #     dstShape: OglClass = cast(OglClass, dstShape)
            #     self.clsLogger.warning(f'Over-lining in destination shape: {dstShape.getPyutObject}')
            #     if orient == PyutAttachmentPoint.NORTH or orient == PyutAttachmentPoint.SOUTH:
            #         dstX += 10
            #     else:
            #         dstY += 10

            # =========== end avoid over-lining-Added by C.Dutoit ================
        else:
            # Use provided position
            (srcX, srcY) = srcPos
            (dstX, dstY) = dstPos

        srcAnchor: AnchorPoint = self._srcShape.AddAnchor(srcX, srcY)
        dstAnchor: AnchorPoint = self._destShape.AddAnchor(dstX, dstY)
        srcAnchor.SetPosition(srcX, srcY)
        dstAnchor.SetPosition(dstX, dstY)
        srcAnchor.SetVisible(False)
        dstAnchor.SetVisible(False)
        self.clsLogger.debug(
            f'src anchor pos: {srcAnchor.GetPosition()} dst anchor pos {dstAnchor.GetPosition()}'
        )
        srcAnchor.SetDraggable(True)
        dstAnchor.SetDraggable(True)
        # Init
        LineShape.__init__(self, srcAnchor, dstAnchor)
        # Set up painting colors
        self.SetPen(BLACK_PEN)
        # Keep reference to the PyutLink for mouse events, in order
        # to can find back the corresponding link
        if pyutLink is not None:
            self._link = pyutLink
        else:
            self._link = PyutLink()

    def getSourceShape(self):
        """
        Return the source shape for this link.

        @return OglObject
        @since 1.22
        @author Laurent Burgbacher <*****@*****.**>
        """
        return self._srcShape

    def getDestinationShape(self):
        """
        Return the destination shape for this link.

        @return OglObject
        @since 1.22
        @author Laurent Burgbacher <*****@*****.**>
        """
        return self._destShape

    def getPyutObject(self):
        """
        Returns the associated PyutLink.

        Returns: PyutLink

        """
        return self._link

    def setPyutObject(self, pyutLink):
        """
        Sets the associated PyutLink.

        @param PyutLink pyutLink : link to associate
        """
        self._link = pyutLink

    def getAnchors(self) -> Tuple[AnchorPoint, AnchorPoint]:
        return self._srcAnchor, self._dstAnchor

    def Detach(self):
        """
        Detach the line and all its line points, including src and dst.

        @since 1.0
        @author Laurent Burgbacher <*****@*****.**>
        """
        if self._diagram is not None and not self._protected:
            LineShape.Detach(self)
            self._srcAnchor.SetProtected(False)
            self._dstAnchor.SetProtected(False)
            self._srcAnchor.Detach()
            self._dstAnchor.Detach()
            try:
                self.getSourceShape().getLinks().remove(self)
            except ValueError:
                pass
            try:
                self.getDestinationShape().getLinks().remove(self)
            except ValueError:
                pass
            try:
                self._link.getSource().getLinks().remove(self._link)
            except ValueError:
                pass

    def optimizeLine(self):
        """
        Optimize line, so that the line length is minimized
        """
        # Get elements
        srcAnchor = self.GetSource()
        dstAnchor = self.GetDestination()

        srcX, srcY = self._srcShape.GetPosition()
        dstX, dstY = self._destShape.GetPosition()

        srcSize = self._srcShape.GetSize()
        dstSize = self._destShape.GetSize()

        self.clsLogger.info(
            f"optimizeLine - ({srcX},{srcY}) / ({dstX},{dstY})")
        # Find new positions
        # Little tips
        optimalSrcX, optimalSrcY, optimalDstX, optimalDstY = dstX, dstY, srcX, srcY

        optimalSrcX += dstSize[0] / 2
        optimalSrcY += dstSize[1] / 2
        optimalDstX += srcSize[0] / 2
        optimalDstY += srcSize[1] / 2

        srcAnchor.SetPosition(optimalSrcX, optimalSrcY)
        dstAnchor.SetPosition(optimalDstX, optimalDstY)

    # noinspection PyUnusedLocal
    def OnRightDown(self, event: MouseEvent):
        """
        Handle right clicks on our UML LineShape-  Override base handler;  It does nothing

        Args:
            event:
        """
        menu: Menu = Menu()
        menu.Append(ID_ANY, _('Add Bend'), _('Add Bend at right click point'))

        x: int = event.GetX()
        y: int = event.GetY()
        clickPoint: Tuple[int, int] = (x, y)

        self.clsLogger.debug(f'OglLink - x,y: {x},{y}')
        # Callback
        menu.Bind(EVT_MENU,
                  lambda evt, data=clickPoint: self.onAddBend(evt, data))

        frame = self._diagram.GetPanel()
        frame.PopupMenu(menu, x, y)

    # noinspection PyUnusedLocal
    def onAddBend(self, event: CommandEvent, data):

        self.clsLogger.debug(f'Add a bend.  {data=}')

        x = data[0]
        y = data[1]
        cp = ControlPoint(x, y)

        cp.SetVisible(True)
        #
        # Add it either before the destinationAnchor or the sourceAnchor
        #
        lp: LinePoint = self.GetSource()
        self.AddControl(cp, lp)

        frame = self._diagram.GetPanel()
        frame.GetDiagram().AddShape(cp)
        frame.Refresh()

    def _computeLinkLength(self, srcPosition: Tuple[float, float],
                           destPosition: Tuple[float, float]) -> float:
        """

        Returns:  The length of the link between the source shape and destination shape
        """
        dx, dy = self._computeDxDy(srcPosition, destPosition)
        linkLength = sqrt(dx * dx + dy * dy)
        if linkLength == 0:
            linkLength = 0.01

        return linkLength

    def _computeDxDy(self, srcPosition: Tuple[float, float],
                     destPosition: Tuple[float, float]) -> Tuple[float, float]:
        """

        Args:
            srcPosition:    Tuple x,y source position
            destPosition:   Tuple x,y destination position

        Returns:
            A tuple of deltaX and deltaY of the shape position
        """
        if self._srcShape is None or self._destShape is None:
            raise IllegalOperationException(
                'Either the source or the destination shape is None')

        srcX, srcY = srcPosition
        dstX, dstY = destPosition

        dx = dstX - srcX
        dy = dstY - srcY

        return dx, dy
Exemple #21
0
class OglLink(LineShape, ShapeEventHandler):
    """
    Abstract class for graphical link.
    This class should be the base class for every type of link. It implements
    the following functions :
        - Link between objects position management
        - Control points (2)
        - Data layer link association
        - Source and destination objects

    You can inherit from this class to implement your favorite type of links
    like `OglAssociation`.

    There is a link factory (See `OglLinkFactory`) you can use to build
    the different type of links that exist.

    """
    clsLogger: Logger = getLogger(__name__)

    def __init__(self, srcShape, pyutLink, dstShape, srcPos=None, dstPos=None):
        """

        Args:
            srcShape:   Source shape
            pyutLink:   Conceptual links associated with the graphical links.
            dstShape:   Destination shape
            srcPos:     Position of source      Override location of input source
            dstPos:     Position of destination Override location of input destination
        """
        self._srcShape  = srcShape
        self._destShape = dstShape

        OglLink.clsLogger.debug(f'Input Override positions - srcPos: {srcPos} dstPos: {dstPos}')
        if srcPos is None and dstPos is None:
            srcX, srcY = self._srcShape.GetPosition()
            dstX, dstY = self._destShape.GetPosition()

            orient = OglLink.getOrient(srcX,  srcY, dstX, dstY)

            sw, sh = self._srcShape.GetSize()
            dw, dh = self._destShape.GetSize()
            if orient == AttachmentPoint.NORTH:
                srcX, srcY = sw/2, 0
                dstX, dstY = dw/2, dh
            elif orient == AttachmentPoint.SOUTH:
                srcX, srcY = sw/2, sh
                dstX, dstY = dw/2, 0
            elif orient == AttachmentPoint.EAST:
                srcX, srcY = sw, sh/2
                dstX, dstY = 0, dh/2
            elif orient == AttachmentPoint.WEST:
                srcX, srcY = 0, sh/2
                dstX, dstY = dw, dh/2

            # ============== Avoid over-lining; Added by C.Dutoit ================
            # lstAnchorsPoints = [anchor.GetRelativePosition() for anchor in srcShape.GetAnchors()]
            # while (srcX, srcY) in lstAnchorsPoints:
            #     OglLink.clsLogger.warning(f'Over-lining in source shape')
            #     if orient == PyutAttachmentPoint.NORTH or orient == PyutAttachmentPoint.SOUTH:
            #         srcX += 10
            #     else:
            #         srcY += 10
            #
            # lstAnchorsPoints = [anchor.GetRelativePosition() for anchor in dstShape.GetAnchors()]
            # while (dstX, dstY) in lstAnchorsPoints:
            #     from org.pyut.ogl.OglClass import OglClass
            #     dstShape: OglClass = cast(OglClass, dstShape)
            #     OglLink.clsLogger.warning(f'Over-lining in destination shape: {dstShape.getPyutObject}')
            #     if orient == PyutAttachmentPoint.NORTH or orient == PyutAttachmentPoint.SOUTH:
            #         dstX += 10
            #     else:
            #         dstY += 10

            # =========== end avoid over-lining-Added by C.Dutoit ================
        else:
            # Use provided position
            (srcX, srcY) = srcPos
            (dstX, dstY) = dstPos

        srcAnchor: AnchorPoint = self._srcShape.AddAnchor(srcX, srcY)
        dstAnchor: AnchorPoint = self._destShape.AddAnchor(dstX, dstY)
        srcAnchor.SetPosition(srcX, srcY)
        dstAnchor.SetPosition(dstX, dstY)
        srcAnchor.SetVisible(False)
        dstAnchor.SetVisible(False)
        OglLink.clsLogger.debug(f'src anchor pos: {srcAnchor.GetPosition()} dst anchor pos {dstAnchor.GetPosition()}')
        srcAnchor.SetDraggable(True)
        dstAnchor.SetDraggable(True)
        # Init
        LineShape.__init__(self, srcAnchor, dstAnchor)
        # Set up painting colors
        self.SetPen(BLACK_PEN)
        # Keep reference to the PyutLink for mouse events, in order
        # to can find back the corresponding link
        if pyutLink is not None:
            self._link = pyutLink
        else:
            self._link = PyutLink()

    @staticmethod
    def getOrient(srcX, srcY, destX, destY) -> AttachmentPoint:
        """
        Giving a source and destination, returns where the destination
        is located according to the source.

        @param int srcX  : X pos of src point
        @param int srcY  : Y pos of src point
        @param int destX : X pos of dest point
        @param int destY : Y pos of dest point
        """
        deltaX = srcX - destX
        deltaY = srcY - destY
        if deltaX > 0:  # dest is not east
            if deltaX > abs(deltaY):  # dest is west
                return AttachmentPoint.WEST
            elif deltaY > 0:
                return AttachmentPoint.NORTH
            else:
                return AttachmentPoint.SOUTH
        else:  # dest is not west
            if -deltaX > abs(deltaY):  # dest is east
                return AttachmentPoint.EAST
            elif deltaY > 0:
                return AttachmentPoint.NORTH
            else:
                return AttachmentPoint.SOUTH

    def getSourceShape(self):
        """
        Return the source shape for this link.

        @return OglObject
        @since 1.22
        @author Laurent Burgbacher <*****@*****.**>
        """
        return self._srcShape

    def getDestinationShape(self):
        """
        Return the destination shape for this link.

        @return OglObject
        @since 1.22
        @author Laurent Burgbacher <*****@*****.**>
        """
        return self._destShape

    def getPyutObject(self):
        """
        Returns the associated PyutLink.

        Returns: PyutLink

        """
        return self._link

    def setPyutObject(self, pyutLink):
        """
        Sets the associated PyutLink.

        Args:
            pyutLink: link to associate
        """
        self._link = pyutLink

    def getAnchors(self) -> Tuple[AnchorPoint, AnchorPoint]:
        return self._srcAnchor, self._dstAnchor

    def Detach(self):
        """
        Detach the line and all its line points, including src and dst.

        @since 1.0
        @author Laurent Burgbacher <*****@*****.**>
        """
        if self._diagram is not None and not self._protected:
            LineShape.Detach(self)
            self._srcAnchor.SetProtected(False)
            self._dstAnchor.SetProtected(False)
            self._srcAnchor.Detach()
            self._dstAnchor.Detach()
            try:
                self.getSourceShape().getLinks().remove(self)
            except ValueError:
                pass
            try:
                self.getDestinationShape().getLinks().remove(self)
            except ValueError:
                pass
            try:
                self._link.getSource().getLinks().remove(self._link)
            except ValueError:
                pass

    def optimizeLine(self):
        """
        Optimize line, so that the line length is minimized
        """
        # Get elements
        srcAnchor = self.GetSource()
        dstAnchor = self.GetDestination()

        srcX, srcY = self._srcShape.GetPosition()
        dstX, dstY = self._destShape.GetPosition()

        srcSize = self._srcShape.GetSize()
        dstSize = self._destShape.GetSize()

        OglLink.clsLogger.info(f"optimizeLine - ({srcX},{srcY}) / ({dstX},{dstY})")
        # Find new positions
        # Little tips
        optimalSrcX, optimalSrcY, optimalDstX, optimalDstY = dstX, dstY, srcX, srcY

        optimalSrcX += dstSize[0]/2
        optimalSrcY += dstSize[1]/2
        optimalDstX += srcSize[0]/2
        optimalDstY += srcSize[1]/2

        srcAnchor.SetPosition(optimalSrcX, optimalSrcY)
        dstAnchor.SetPosition(optimalDstX, optimalDstY)

    # noinspection PyUnusedLocal
    def OnRightDown(self, event: MouseEvent):
        """
        Handle right-clicks on our UML LineShape-  Override base handler;  It does nothing

        Args:
            event:
        """
        menu: Menu = Menu()
        menu.Append(MENU_ADD_BEND,      _('Add Bend'),      _('Add Bend at right click point'))
        menu.Append(MENU_REMOVE_BEND,   _('Remove Bend'),   _('Remove Bend closest to click point'))
        menu.Append(MENU_TOGGLE_SPLINE, _('Toggle Spline'), _('Best with at least one bend'))

        if len(self._controls) == 0:
            bendItem: MenuItem = menu.FindItemById(MENU_REMOVE_BEND)
            bendItem.Enable(enable=False)

        x: int = event.GetX()
        y: int = event.GetY()
        clickPoint: Tuple[int, int] = (x, y)

        OglLink.clsLogger.debug(f'OglLink - {clickPoint=}')
        # I hate lambdas -- humberto
        menu.Bind(EVT_MENU, lambda evt, data=clickPoint: self._onMenuItemSelected(evt, data))

        frame = self._diagram.GetPanel()
        frame.PopupMenu(menu, x, y)

    # noinspection PyUnusedLocal
    def _onMenuItemSelected(self, event: CommandEvent, data):

        eventId: int = event.GetId()
        if eventId == MENU_ADD_BEND:
            self._addBend(data)
        elif eventId == MENU_REMOVE_BEND:
            self._removeBend(data)
        elif eventId == MENU_TOGGLE_SPLINE:
            self._toggleSpline()

    def _computeLinkLength(self, srcPosition: OglPosition, destPosition: OglPosition) -> float:
        """

        Returns:  The length of the link between the source shape and destination shape
        """
        dx, dy = self._computeDxDy(srcPosition, destPosition)
        linkLength = sqrt(dx*dx + dy*dy)
        if linkLength == 0:
            linkLength = 0.01

        return linkLength

    def _computeDxDy(self, srcPosition: OglPosition, destPosition: OglPosition) -> Tuple[float, float]:
        """

        Args:
            srcPosition:    source position
            destPosition:   destination position

        Returns:
            A tuple of deltaX and deltaY of the shape position
        """
        if self._srcShape is None or self._destShape is None:
            raise IllegalOperationException('Either the source or the destination shape is None')

        srcX: float = srcPosition.x
        srcY: float = srcPosition.y
        dstX: float = destPosition.x
        dstY: float = destPosition.y

        dx: float = dstX - srcX
        dy: float = dstY - srcY

        return dx, dy

    def _addBend(self, clickPoint: Tuple[int, int]):

        OglLink.clsLogger.debug(f'Add a bend.  {clickPoint=}')

        x = clickPoint[0]
        y = clickPoint[1]
        cp = ControlPoint(x, y)

        cp.SetVisible(True)
        #
        # Add it either before the destinationAnchor or the sourceAnchor
        #
        lp: LinePoint = self.GetSource()
        self.AddControl(control=cp, after=lp)

        frame = self._diagram.GetPanel()
        frame.GetDiagram().AddShape(cp)
        frame.Refresh()

    def _removeBend(self, clickPoint: Tuple[int, int]):

        OglLink.clsLogger.debug(f'Remove a bend.  {clickPoint=}')

        cp: ControlPoint = self._findClosestControlPoint(clickPoint=clickPoint)

        assert cp is not None, 'We should have previously verified there was at least one on the line'

        self._removeControl(control=cp)
        cp.Detach()
        cp.SetVisible(False)    # Work around still on screen but not visible and not saved

        frame = self._diagram.GetPanel()
        frame.Refresh()

    def _toggleSpline(self):

        self.SetSpline(not self.GetSpline())

        frame = self._diagram.GetPanel()
        frame.Refresh()

    def _findClosestControlPoint(self, clickPoint: Tuple[int, int]) -> ControlPoint:

        controlPoints = self.GetControlPoints()

        distance:     float        = 1000.0    # Impossibly long distance
        closestPoint: ControlPoint = cast(ControlPoint, None)
        srcPosition:  OglPosition  = OglPosition(x=clickPoint[0], y=clickPoint[1])

        for controlPoint in controlPoints:
            xy:    Tuple[int, int] = controlPoint.GetPosition()
            destX: int = xy[0]
            destY: int = xy[1]
            destPosition: OglPosition = OglPosition(x=destX, y=destY)

            dx, dy = self._computeDxDy(srcPosition, destPosition)
            currentDistance = sqrt(dx*dx + dy*dy)
            self.clsLogger.debug(f'{currentDistance=}')
            if currentDistance <= distance:
                distance = currentDistance
                closestPoint = cast(ControlPoint, controlPoint)

        return closestPoint
Exemple #22
0
    def getOglLinks(self, xmlOglLinks: NodeList,
                    oglClasses: OglObjects) -> OglLinks:
        """
        Extract the link for the OglClasses

        Args:
            xmlOglLinks:    A DOM node list of links
            oglClasses:  The OglClasses

        Returns:
            The OglLinks list
        """
        oglLinks: OglLinks = cast(OglLinks, [])

        for xmlOglLink in xmlOglLinks:
            # src and dst anchor position
            xmlLink: Element = cast(Element, xmlOglLink)

            sx = PyutUtils.secureFloat(
                xmlLink.getAttribute(
                    PyutXmlConstants.ATTR_LINK_SOURCE_ANCHOR_X))
            sy = PyutUtils.secureFloat(
                xmlLink.getAttribute(
                    PyutXmlConstants.ATTR_LINK_SOURCE_ANCHOR_Y))
            dx = PyutUtils.secureFloat(
                xmlLink.getAttribute(
                    PyutXmlConstants.ATTR_LINK_DESTINATION_ANCHOR_X))
            dy = PyutUtils.secureFloat(
                xmlLink.getAttribute(
                    PyutXmlConstants.ATTR_LINK_DESTINATION_ANCHOR_Y))

            spline: bool = PyutUtils.secureBoolean(
                xmlLink.getAttribute(PyutXmlConstants.ATTR_SPLINE))

            # get the associated PyutLink
            srcId, dstId, assocPyutLink = self._getPyutLink(xmlLink)

            try:
                src: OglClass = oglClasses[srcId]
                dst: OglClass = oglClasses[dstId]
            except KeyError as ke:
                self.logger.error(
                    f'Developer Error -- srcId: {srcId} - dstId: {dstId}  error: {ke}'
                )
                continue

            linkType: LinkType = assocPyutLink.getType()
            pyutLink: PyutLink = PyutLink(
                name=assocPyutLink.getName(),
                linkType=linkType,
                cardSrc=assocPyutLink.sourceCardinality,
                cardDest=assocPyutLink.destinationCardinality,
                source=src.getPyutObject(),
                destination=dst.getPyutObject())

            oglLinkFactory = getOglLinkFactory()
            oglLink = oglLinkFactory.getOglLink(src, pyutLink, dst, linkType)
            src.addLink(oglLink)
            dst.addLink(oglLink)

            oglLinks.append(oglLink)

            oglLink.SetSpline(spline)

            # put the anchors at the right position
            srcAnchor = oglLink.GetSource()
            dstAnchor = oglLink.GetDestination()
            srcAnchor.SetPosition(sx, sy)
            dstAnchor.SetPosition(dx, dy)

            # add the control points to the line
            line = srcAnchor.GetLines()[0]  # only 1 line per anchor in pyut
            parent = line.GetSource().GetParent()
            selfLink = parent is line.GetDestination().GetParent()

            controlPoints: ControlPoints = self._generateControlPoints(xmlLink)
            for controlPoint in controlPoints:
                line.AddControl(controlPoint)
                if selfLink:
                    x, y = controlPoint.GetPosition()
                    controlPoint.SetParent(parent)
                    controlPoint.SetPosition(x, y)

            if isinstance(oglLink, OglAssociation):
                self.__furtherCustomizeAssociationLink(xmlLink, oglLink)
            self._reconstituteLinkDataModel(oglLink)

        return oglLinks
Exemple #23
0
    def _getLinks(self, obj):
        """
        To extract links form an OGL object.

        @param String obj : Name of the object.
        @since 1.0
        @author Deve Roux <*****@*****.**>
        @changed Philippe Waelti <*****@*****.**> : Refactoring campaign
        """
        allLinks = []
        for link in obj.getElementsByTagName("Link"):

            aLink = PyutLink()

            aLink.setBidir(bool(link.getAttribute('bidir')))

            # aLink.setDestinationCardinality(link.getAttribute('cardDestination'))
            # aLink.setSourceCardinality(link.getAttribute('cardSrc'))

            aLink.destinationCardinality = link.getAttribute('cardDestination')
            aLink.sourceCardinality = link.getAttribute('cardSrc')

            aLink.setName(link.getAttribute('name'))
            aLink.setType(link.getAttribute('type'))
            aLink.setDestination(link.getAttribute('destination'))

            # Backward compatibility
            if link.hasAttribute('destId'):
                destId = int(link.getAttribute('destId'))
            else:
                destId = 0

            allLinks.append([destId, aLink])

        return allLinks
Exemple #24
0
    def _getOglLinks(self, xmlOglLinks, dicoOglObjects, dicoLink, dicoFather,
                     umlFrame):
        """
        To extract the links from an OGL object.
        """
        def secure_float(floatX):
            if floatX is not None:
                return float(floatX)
            return 0.0

        def secure_spline_int(splineX):
            if splineX is None:
                return 0
            elif splineX == "_DeprecatedNonBool: False" or splineX == "False":
                return 0
            elif splineX == "_DeprecatedNonBool: True" or splineX == "True":
                return 1
            else:
                return int(splineX)

        for link in xmlOglLinks:
            # src and dst anchor position
            sx = secure_float(link.getAttribute("srcX"))
            sy = secure_float(link.getAttribute("srcY"))
            dx = secure_float(link.getAttribute("dstX"))
            dy = secure_float(link.getAttribute("dstY"))
            spline = secure_spline_int(link.getAttribute("spline"))

            # create a list of ControlPoints
            ctrlpts = []
            for ctrlpt in link.getElementsByTagName("ControlPoint"):
                x = secure_float(ctrlpt.getAttribute("x"))
                y = secure_float(ctrlpt.getAttribute("y"))
                ctrlpts.append(ControlPoint(x, y))

            # get the associated PyutLink
            srcId, dstId, pyutLink = self._getPyutLink(link)

            # CD 20060218
            src = dicoOglObjects[srcId]
            dst = dicoOglObjects[dstId]
            linkType = pyutLink.getType()
            pyutLink = PyutLink("",
                                linkType=linkType,
                                source=src.getPyutObject(),
                                destination=dst.getPyutObject())

            oglLinkFactory = getOglLinkFactory()
            oglLink = oglLinkFactory.getOglLink(src, pyutLink, dst, linkType)
            src.addLink(oglLink)
            dst.addLink(oglLink)
            umlFrame.GetDiagram().AddShape(oglLink, withModelUpdate=False)

            # create the OglLink
            oglLink.SetSpline(spline)

            # give it the PyutLink
            newPyutLink = pyutLink

            # copy the good information from the read link
            newPyutLink.setBidir(pyutLink.getBidir())
            # newPyutLink.setDestinationCardinality(pyutLink.getDestinationCardinality())
            # newPyutLink.setSourceCardinality(pyutLink.getSourceCardinality())
            newPyutLink.destinationCardinality = pyutLink.destinationCardinality
            newPyutLink.sourceCardinality = pyutLink.sourceCardinality

            newPyutLink.setName(pyutLink.getName())

            # put the anchors at the right position
            srcAnchor = oglLink.GetSource()
            dstAnchor = oglLink.GetDestination()
            srcAnchor.SetPosition(sx, sy)
            dstAnchor.SetPosition(dx, dy)

            # add the control points to the line
            line = srcAnchor.GetLines()[0]  # only 1 line per anchor in pyut
            parent = line.GetSource().GetParent()
            selfLink = parent is line.GetDestination().GetParent()

            for ctrl in ctrlpts:
                line.AddControl(ctrl)
                if selfLink:
                    x, y = ctrl.GetPosition()
                    ctrl.SetParent(parent)
                    ctrl.SetPosition(x, y)

            if isinstance(oglLink, OglAssociation):
                # center = oglLink.getLabels()[CENTER]
                # src = oglLink.getLabels()[SRC_CARD]
                # dst = oglLink.getLabels()[DEST_CARD]

                label = link.getElementsByTagName("LabelCenter")[0]
                x = float(label.getAttribute("x"))
                y = float(label.getAttribute("y"))
                # center.SetPosition(x, y)
                oglLink.centerLabel.oglPosition.x = x
                oglLink.centerLabel.oglPosition.y = y

                label = link.getElementsByTagName("LabelSrc")[0]
                x = float(label.getAttribute("x"))
                y = float(label.getAttribute("y"))
                # src.SetPosition(x, y)
                oglLink.sourceCardinality.oglPosition.x = x
                oglLink.sourceCardinality.oglPosition.y = y

                label = link.getElementsByTagName("LabelDst")[0]
                x = float(label.getAttribute("x"))
                y = float(label.getAttribute("y"))
                dst.SetPosition(x, y)