{"id":102,"date":"2008-03-01T19:42:14","date_gmt":"2008-03-01T17:42:14","guid":{"rendered":"http:\/\/www.ticklishtechs.net\/2008\/03\/01\/connectors-between-compartment-shape-entries-with-dsl-tools-part-3\/"},"modified":"2020-08-13T20:46:56","modified_gmt":"2020-08-13T18:46:56","slug":"connectors-between-compartment-shape-entries-with-dsl-tools-part-3","status":"publish","type":"post","link":"https:\/\/www.ticklishtechs.net\/2008\/03\/01\/connectors-between-compartment-shape-entries-with-dsl-tools-part-3\/","title":{"rendered":"Connectors between compartment shape entries with DSL Tools – part 3"},"content":{"rendered":"
[Update (2008-05-21): <\/strong>This code is now hosted at CodePlex as part of JaDAL<\/a>. And a follow-up article<\/a> was published.]<\/p>\n This article is part of a series. The table of contents can be found at the end of the first article<\/a>. In that article you can also find a brief overview. In the second part<\/a> there is a short user guide and a download link of the source code and binaries.<\/p>\n I don’t want to explain every single detail of my code. If you want to go that deep, you have to read the source code yourself and maybe you will find some comments. I will only show you the fundamental parts of the CompartmentMapping library.<\/p>\n There are a few things you have to consider to achieve the aim of the library:<\/p>\n There is the concept of Connection Builders<\/em> used by the DSL Tools. While your day to day use of DSL, you don’t have to worry about Connection Builders<\/em> since they will be generated by the DSL Tools code generator. But you can turn this generation off and provide your implementation of a Connection Builder <\/em>for a certain relationship. (see number 5 in the user guide<\/a>). <\/p>\n A Connection Builder<\/em> is a static class and will be assigned to a connection toolbar item of your editor. This class contains four interesting methods:<\/p>\n The first two methods are used to determine if a particular With Last but not least with the In such a Connection Builder<\/em> I will add the logic to check not only the model elements but also the selected entry inside the Compartment Shape<\/em>. At this point I will mix the model representation (containing of Domain Classes<\/em> and Relationships<\/em>) and the graphical appearance (containing of Shapes <\/em>and Connectors<\/em>) but there is no better way at this time since the DSL Tools can only create connectors from shape to shape.<\/p>\n The first problem I ran into: How to get the shape of the model element in the Connection Builder<\/em> if the only parameter is the After holding the shape in my hand I need to know something about the selected Compartment Entry<\/em>. This becomes a little bit complicated, too: Sometimes I need the entry right below the mouse cursor (for With all these new information my With the Connection Builder<\/em> one can create relationships in the domain model but the connector inside the visual representation of your model will still be routed from shape to shape and won’t give you a proper understanding of the entry to entry relationship. So we have to change the routing in a way that the start and endpoints of the connector will be glued near to the entry on one side of the shape.<\/p>\n This will be done with an AddRule<\/a> ( After determination the favored points on the shape outline you can set them to the connector with the FromEndPoint<\/a> and ToEndPoint<\/a> properties. Don’t forget to change the FixedFrom<\/a> and FixedTo<\/a> to If you change the start and endpoints of a connector in the AddRule<\/u><\/em> these values aren’t set forever. The user could collapse and expand the compartment shape or use the "Reroute" command that is visible in the context menu of every connector. He could also move the connector or only the start and endpoints on the shape outline. If he deletes one entry that was shown above an entry with a connection this entry moves closer to the top and the connection should do the same.<\/p>\n With a few lines of code, we can forbid the user to change the routing of a connectors. In the connector class the Every time the size of the shape changes (see OnAbsoluteBoundsChanged event<\/a>) I will recalculate the connection points of all connectors assigned to this shape. This event will handle a bunch of cases for me: insertion and deletion of other entries, expanding and collapsing of the whole shape and singe compartment lists and renaming of entries which can cause reordering of the compartment list.<\/p>\n The delete propagation is an easy requirement. I just added a DeletingRule<\/a> that keep track of the deletion of certain Compartment Entries<\/em> and if one is deleted it looks for Compartment Mapping Relationships<\/em> and deletes them. <\/p>\n It is a little bit challenging to find the relationships coming from the entry. If you want to know more details take a look at the Previously on…<\/h3>\n
How does it all work?<\/h3>\n
\n
The Connection Builder<\/h3>\n
\n
bool <\/span>CanAcceptSource(ModelElement<\/span>)<\/pre>\n<\/li>\n
bool <\/span>CanAcceptTarget(ModelElement<\/span>)<\/pre>\n<\/li>\n
bool <\/span>CanAcceptSourceAndTarget(ModelElement<\/span>, ModelElement<\/span>)<\/pre>\n<\/li>\n
ElementLink <\/span>Connect(ModelElement<\/span>, ModelElement<\/span>)<\/pre>\n<\/li>\n<\/ol>\n
ModelElement<\/code> can act as source or target of you connection. For example you can check the
ModelElement<\/code> for a certain property to be set and only allow elements with this property as source and with another property as target, or whatever. <\/p>\n
CanAcceptSourceAndTarget()<\/code> you can check whenever a concrete combination of source and target
ModelElements<\/code> is allowed to be connected by your relationship. <\/p>\n
Connect()<\/code> method you have to create this new relationship for the two selected
ModelElements<\/code>.<\/p>\n
ModelElement?<\/code> I used the PresentationViewsSubject.GetPresentation()<\/a> method and I’m hoping it will always work. The architecture is build in such a way, that one
ModelElement<\/code> can have multiple shapes, but I didn’t saw such a configuration until now, so I assume there will be only one shape.<\/p>\n
CanAcceptSource()<\/code>) and sometimes the entry that was below the mouse when the user pressed the mouse button. Of course a Compartment Shape<\/em> doesn’t provide any of that information. Take a look at
CompartmentMouseTrack<\/code> and
ICompartmentMouseActionTrackable<\/code> in the CompartmentMapping library and you will see in which way I handle mouse events of the shape to track all these mouse actions for the Compartment Shapes<\/em> that are under the control of my library.<\/p>\n
CompartmentMappingBuilderBase<\/code> can decide to allow or permit the creation of a connection. With some
virtual<\/code> methods, it can delegate more details of this decision to your code (see the advanced options here<\/a>).<\/p>\n
<\/a><\/a><\/a><\/ol>\n
How to trick the routing algorithm of DSL Tools<\/h3>\n
CompartmentMappingAddRuleBase<\/code>) every time a new connector will be added to the diagram (and when opening a saved diagram). <\/p>\n
VGFixedCode.Caller<\/code> as well.<\/p>\n
Don’t get tricked by the routing algorithm<\/h3>\n
CanManuallyRoute<\/code> property simply have to return
false<\/code>.<\/p>\n
Delete propagation<\/h3>\n
CompartmentEntryDeletingRuleBase<\/code> source code.<\/p>\n
Upcoming article<\/h3>\n