Selecting, Copying, Duplicating and Merging - archimatetool/archi GitHub Wiki
This page contains some thoughts about how copying and pasting elements in Archi currently works, how I think it could be improved, and how this could be implemented. This page is meant to be temporary, but may eventually become the basis of the documentation for these processes in Archi, if Phil agrees that the changes are desirable.
The focus is on supporting the user, both such that the actions are not surprising, and such that one gets a few more possibilities when copy-paste than is currently supported. (However, this page is not meant to be read by users, but only by developers).
Relevant issues currently are https://github.com/Phillipus/archi/issues/60 and https://github.com/Phillipus/archi/issues/26. More may be relevant.
Overview of the Archi model
For the sake of the discussion, it is probably beneficial to consider how Archi works, with respect to the Archimate model tree and the views. The following is my understanding, which is surely simplific, but hopefully close enough to be usable.
The Archimate standard uses "Concepts" and "Relations". In this text, Concept will be called objects, relations will be either relations or connections, and "Elements" will be used to cover both types (concepts and relations).
Manipulating elements as seen from the users perspective
The user have two main ways to manipulate elements: The model tree, or a given view on the model. If the model tree and the view is linked, a click on an element in the view will highlight an element in the model tree. A click on an element in the model tree, will highligth an element in the current active view, if the element is present in that view.
From the users point of view, elements can be part of several views, but the element can have e.g. different appearence properties in different views. Elements can even be present several times in the same view, and all instances will highlight when the element is selected in the model view (in the linked case).
Archimate elements and Diagram elements
Although it appears to the user that the elements in the model tree and in the views are "the same", to Archi, there is (and must be) a difference.
First a note about naming: Archi internally categories code related to the tree model, as "view" code, and code related to the views as "diagram" codes. I believe this is because the Archi code bases follows the conventions from the Eclipse RCF - but obviously this can be the source of some confusion for the newcomer to the code base (cough), and I might even risk using the terms confusingly in this text. Hopefully it is clear from the context.
So, Archi internally differs between Archimate elements, and Diagram elements. Archimate elements are elements (objects and relations) that are part of the Archimate model that the user works on. These elements are part of the model tree in the Archi GUI. Diagram elements are the representation of these elements in different views. They, obviously, appears in the views, but have no direct representation in the model tree.
Every Diagram element have an associated Archimate element, but Archimate elements can exist without any associated Diagram elements. Several Diagram elements can be associated with the same Archimate element.
When the user manipulates elements in views, he is manipulating Diagram elements. For some operations, such as naming, the associated Archimate element will be manipulated too, for others, such as the color, only the Diagram element is affected. When the user manipulates elements in the model tree, he is manipulating Archimate elements, and for many operations, the associated elements will not be affected. For others, such as a delete, the associated elements will absolutely be affected.
Notation for elements, objects and relation
In the following, assume the following notation:
- An Archimate Element is shorthanded to AE, this can be either an
- Archimate Object = AO or
- Archimate Relation = AR
- A Diagram Element is shorthanded to DE, this can be either a
- Diagram Object = DO or
- Diagram Element = DE (comment by SJ: Do you mean "Diagram Relation" or is "Diagram Relation" missing?)
- If one needs to explicitly indicate which AE a DE is associated with, the AE is put in ()
- DO_0(AO_0) indicates that the Diagram Element 0 is associated with the Archimate Object 0.
- DR_4(AR_7) indicates that Diagram Relation 4 is associated with the Archimate Relation 7.
- If one needs to indicate what Objects a relation refers to, the Objects are put in ()
- DR_4(DO_0, DO_1) indicates that the Diagram Relation 4, has Digram Object 0 as a source, and Diagram Object 1 as a target
- AR_7(AO_4, AO_9) indidates that the Archimate Relation 7, has Archimate Object 4 as a source, and Archimate Object 9 as a target.
- For DR relations, AR and DO references can be combined:
- DR_4(AR_2,DO_0, DO_1) indicates that the Diagram Relation 4 is associated with Archimate Relation 2, and in the Digram, has Digram Object 0 as a source, and Diagram Object 1 as a target
- S notes a selection, which can be one of or a combination of
- SM notes a selection of Archimate Elements from the model tree
- SD notes a selection of Diagram Elements from a diagram (view)
Selecting elements
When selecting in the model tree, AEs from the model are selected, and worked upon. A selection therefore contains a set (possibly with duplicates?) of AEs, which we can write like this S = SM = {AE_0, AE_1, ...} = {AO_0, AO_1, ..., AR_0, AR_1, ...}.
When selecting in the views (diagrams), DEs are selected and worked upon. In this case, we can write S = SD = {DE_0, DE_1, ...} = {DO_0, DO_1, ..., DR_0, DR_1, ...}. (Again, duplicates may be a possibility?)
In some cases, when selecting a DE, the visual feedback is different from the actual selection that archimate gives. This is true when the DE is a container where other DE's are nested inside. Assume that DO_0 is an object that have an aggregation relation DR_0 to DO_1. If DO_1 is nested inside DO_0, a selection of DO_0, followed by a delete (from the view) operation, will mean that the SD' = {DO_0, DO_1}. (Note, that DR_0 is not part of the selection, because it is actually not present in the diagram model when nesting. Might need some clarification here). If, however, DO_1 is not nested in DO_0, then SD' becomes {DO_0, DR_0}. Note, that in both cases, the delete operation works on something different from the users visual feedback.
Also, for some operations, the set of associated archimate elements may be relevant to the selection. For e.g. delete on the model tree, if SM = {AO_0}, the delete operation actually have to work on the set SM', that contains {AO_0, AR_0, AR_1, ...} where AR_0, AR_1, ... are the relations in the archimate model that have AO_0 as a source or taget. And, because all diagram elements DE that refers to a given AE must also be deleted, the delete operation needs to work on both SM' and SD', where SD' is the set of associated DE that matches the set of AE in SM'. Hence, the total set S to work on, becomes the combination of these sets of different elements.
Copying elements
There are two places to support copying elements. One is in the model tree, the other in the views. (I don't think there is a way to copy between these to representations, at least not currently).
For both, a special consideration must be given to the case where the elements to copy gets deleted either during the copy (cut) operation, or between the copy and paste operations.
Copying elements in the diagram
Copying elements in the diagram is probably done by the user to either get a copy of the elements in the same diagram, or a copy in another diagram. However, because of the association between AE and DE, the semantics of the operation can be discussed: Is a copy a copy of the DE's with new AE's, or is it a copy of the DE's while maintaining the association to the existing AE's? In the following this is discussed with a starting point in the current Archi behaviour, then a few suggestions for additional operations.
Current behaviour
The current behavour has some "quirks", that give some interessting/suprising results.
Overview
When the user have made a selection SD in the diagram, and chooses the Copy action, Archi first filters SD to SD' where only the DO's of SD is kept. DR's are not kept. Then a CopySnapshot is made from SD', but only from the toplevel elements in SD'. Then a number of connections are added, based not on the selection (because the selection now does not contain any DR's), but on the relations present between the various DE's in the selection.
When pasting, the DE's from SD is pasted, but also recursed, so any elements they contain, gets pasted too. Then the connections are pasted.
To complicate matters a bit: when pasting, if an associated AE has been deleted, OR, the target diagram contains a DE that is associated with an AE, the paste operation creates new AE's for the entire selection and associate them with the DE's, before pasting them (each gets marked "(copy)").
Quirks
- If a container DO_p contains two elements DO_c_0 and DO_c_1 (nested) and the user makes a selection S = {DO_p, DO_c_1} and pastes it to an empty view, all of {DO_p, DO_c_1, DO_c_1} is pasted.
- Likewise, if two elements DO_0, DO_1 are connected by two different DR's: DR_0, DR_1, and the user selects both DO's, but only one of the DR's, all are copied anyway.
Details of the operation
Assume the user have made a selection SD and chooses the Copy action.
Archi first filters SD to SD' where only the DO's of SD is kept. DR's are not passed on to the CopySnapshot created afterwards (com.archimatetool.editor.diagram.actions.CopyAction.run
)
Then a CopySnapshot is made from SD', but only from the toplevel elements in SD'.(CopySnapshot.getTopLevelObjectsToCopy()
, .createSnapshotObjects()
). This is the "snapshot".
Lets refer to the snapshot of objects as SS_Obj. Conceptually, it sort of a selection, based on SD' (which again was based on SD). But, SS_Obj does not contain references to the objects in SD', but rather copies. A 1-to-1 mapping between the objects is created, that is, from SS_Obj to objects in SD' (fOriginalToSnapshotObjectsMapping
). Lets call the objects that matches SS_Obj in the original model for SS_Obj_Org.
Then a number of relations are added. The relations are found by looking at all the elements in SS_Obj_Org, look at all source connections, and check if the target of the relation is part of SS_Obj_Org. (getConnectionsToCopy()
). If it is, it is added to a list of relations (SS_Rel_Org), that are then traversed. For each relation in SS_Rel_org, it is checked if SS_Obj contains both the target and source object (which, I believe, it should, as we got the relations from the 1-to-1 mapping fOriginalToSnapshotObjectsMapping
!). If the source and target objects are present, a new relation is created, based on the relation from SS_Rel_Org, and inserted into the set of relations in the snapshot SS_Rel. A 1-to-1 map between SS_Rel_Org and SS_Rel is maintained in the fOriginalToSnapshotConnectionsMapping
variable.
(Phew).
When it is time for pasting, it goes somewhat like this:
The main method is getPasteCommand
- the purpose of this method is to create a command that does the pasting of the individual DE into the view/diagram in question.
The first thing the method does, is to determine if the AE's that SS_Org and SS_Rel_Org points to, are to be reused for the paste operation, or if new ones are to be created. (needsCopiedArchimateElements()
). (This is a global consideration, which I would like to challenge, but for now, I am just describing what it does. The way it does it is slightly complicated, actually).
The paste command creates a new set of objects and relations from the existing sets SS_Obj and SS_Obj_Rel. This is (probably) because you should be able to paste several times, to different views, etc, so the snapshot can't be pasted, it has to be a copy of the set that gets pasted.
The paste command has to do some bookkeeping for mouse coordinates, and for making sure that the new DO's that is created on the basis of SS_Obj, gets new DR's that matches the source and targets, and that if new AE's are needed, these are created and set up correspondingly. But aside from this, it is a pretty straight forward process, where the sets are traversed (recursively for DO's that are containers) and instances of an internal command (PasteDiagramObjectCommand
) are created to do the actual inserting of DE's and AE's into the diagram and model respectively. (And support removal during undo, if needed, and so on).
Example
An example might be needed?
Suggested behaviour of copy and paste
TODO: Write this.
Something about that it might be good if there was a greate correspondance between what the users sees as selected, and what gets copy/pasted?
For containers that are nested, it makes sense. But, perhaps not so much for other stuff? The selection tool explicitly does not select relations - but they get copied and pasted anyway? I think that is confusing.
Duplicate
There are probably two ways to understand duplicate. In the context of the Model Tree view, it is already established, that "To duplicate Elements or Views in the Model Tree select "Duplicate" from the main "Edit" menu or from the right-click context menu. Note that Duplicate Views contain references to the original elements copied." This Duplicate does what a duplicate should do, it creates a copy of the selected entity in the same context, with a slightly different name.
For the diagrams, there appears to be two alternatives. Assume that the user has selected a number of DE, in the selection SD. In the same view, he chooses "Duplicate", then "Paste" (This could also be Copy + Duplicate, or similar).
Alternatives are
- a) A new set of DEs appears, associated with at a new set of AEs
- b) A new set of DEs appears, associated with the existing set of AEs.
Currently, the a) option is what copy-paste does, when pasted to the same diagram. But, it does the b) option, if copy-pasting to another diagram than the source diagram. I would suggest that duplicate does the second option, and that duplicate is an instant action, that only works on the current diagram. This is consistent with the duplicate command for the Model Tree, and eliminates the need for tracking "deletes". (Alternative would be duplicate to another diagram - this really is a modified paste option).
There is however, the issue of naming. The Copy-Paste operation in diagrams suffixes the string "(copy)" to the AE's when it needs to copy them. Because the duplicate operation does not create new AEs, it can not add this string. From the user point of view, this might be slightly confusing: Duplicate in the model tree appends "(copy)" when used, Duplicate in the diagrams does not. However, this is actually consistent: when using Duplicate in the Model Tree, "(copy)" is only added to new elements in the model tree, not to new elements in the diagrams.
So, my suggestion is, that at some point, there should be a "Duplicate" entry on the context menu, that creates a new set of DEs, associated with the existing AEs. This is similar to the drag-n-drop operation from the modeltree, btw.
This is probably not a much sought for feature, but it can actually be implemented as a special case Paste command: simply paste without creating new AEs. (It will still suffer from the quirks copy-paste currently does, though).
Merge feature
The merge feature is really my motivation for writing all of this.
UI wise, I think Merge may need to have its own entry in the menus, just below paste. It might also just be a alt+Paste action, or similar, for advanced users.
The merge command, "merges" the DE's in the current diagram with the DE's in the clipboard (CopySnapshot). It does this by the following major principles, first for the objects.
- If a DO is pasted that is identical (same instance) to a DO in the diagram, it is not actually pasted, but the existing DO is used as a "reference" when pasting DR's.
- If a DO is pasted that is not present in the diagram, but one or more DOs in the diagram is associated with the same AE as the DO that is pasted, is, then the DO is not actually pasted, but the set of existing DOs are used as a "reference".
- If a DO is pasted that is not present in the diagram, and no DOs in the diagram is associated with the same AE as the DO that is pasted, is, then the DO is pasted (as a copy), and used as reference.
- If a DO is pasted that is not present in the diagram, and no DOs in the diagram is associated with the same AE as the DO that is pasted, is, and the AE the DO is associated with no longer exists, then the DO is pasted (as a copy), with a new AE, and the pasted DO is used as a reference.
After "pasting" all the DO's its time to paste the relations. This is done by this principle:
- For a given DR, the set of sources and targets in the diagram that is pasted into is found. For each combination, a DR is created in the diagram, that mimics the DR.
A special note about relations and multiple occurencies of a single AE element through multiple DEs: In that case, all existing relations between the DEs in the selection and the existing DEs that is used as a reference, should should be pasted in all permutations, as it is much easier for the user to remove these connections from the diagram, than manually making sure all are present. This goes both for DE's that are already in the diagram, and DEs that are present multiple times in the selection. There are some pathetic corner cases, where multiple represented AEs in the selection "collapses" to a single AE in the model, if the AE is already represented in the target diagram, but that is consistent with a merge situation.
A few examples (all "extreme" situations):
- If the user selects all instances in a digram, copies them, and paste-merge them into the diagram again, nothing happens: all DEs in the snapshot are already present in the diagram, and only principle 1 is actually used.
- If the user first duplicate a view (diagram) where no AE's are multiple represented via multiple DEs, then select all elements in the source diagram copies and pastes them to the new view, nothing happens: the selection merges into the existing diagram, using principle 2
- If the user first duplicate a view (diagram) where AE's are multiple represented via multiple DEs, then select all elements in the source diagram copies and pastes them to the new view, no changes in the DOs takes place, as the existing DOs are used for reference, however a number of DRs may be added, because DRs are added to all DEs representing a given AE. (TODO: Give simple example).
- If there is no overlap in the AEs represented by the DEs in the target diagram and the AEs represented by the DEs in the snapshot, the paste-merge is like a normal paste.
TODO: Nested DOs - can't the same algorithem be followed? (I think so). One needs to make sure when pasting a DO with other DOs embedded, that any new DO based on the embedded ones, reference the right DO in the new diagram - this might be an existing DO.
Example of merge
Note: In the following, if an AE associated with any of the DE's in the original selection have been deleted, new ones are created, that obviously are different from any existing...
Lets say we have the a Diagram named "SOURCE", containing the following elements:
DO_0(AE_0), DO_1(AE_1), DO_2(AE_2), DO_3(AE_3), DO_4(AE_4)
(In other words, five DO's with five associated AE's). Lets assume these relations:
DR_0(AR_0,DO_1,DO_3), DR_1(AR_1,DO_0,DO_3), DR_2(AR_2,DO_0,DO_4), DR_3(AR_3,DO_2,DO_4)
Additionally, lets assume that DO_1 and DO_2 are nested in DO_0 (with an implicit aggregation relation).
Lets assume that another Diagram, named "TARGET", contains the following elements:
DO_10(AE_0), DO_11(AE_1), DO_12(AE_3), DO_13(AE_3), DO_14(AE5), and the relations:
DR_10(AR_0,DO_11,DO_13), DR_11(AR_1,DO_10,DO_12), DR_12(AR_4,DO_12,DO_14)
Lets now assume that the user selects all DE's on the SOURCE diagram, and wants to merge them into TARGET. Lets look at the objects first:
SOURCE_O = { DO_0(AE_0), DO_1(AE_1), DO_2(AE_2), DO_3(AE_3), DO_4(AE_4) }
TARGET_O = { DO_10(AE_0), DO_11(AE_1), DO_12(AE_3), DO_13(AE_3), DO_14(AE5) }
REFERENCE_O = {}
Applying the principle, for DO_0, we find that DO_10 also references AE_0, so this gives rise to
REFERENCE_O = { Ref_DO_0 = { DO_10(AE_0) } }
Applying for the rest, we find that:
REFERENCE_O = { Ref_DO_0 = { DO_10(AE_0) }, Ref_DO_1 = { DO_11(AE_1) }, Ref_DO_2 = { CopyOf_DO_2(AE_2) }, Ref_DO_3 = { DO_12(AE_3), DO_13(AE_3) }, Ref_DO_4 = { CopyOf_DO_4(AE_4) } }
Two points: Only DO_2 and DO_4 must be "copied" to the target diagram. For the rest, existing DOs can be used as the reference. Second point: For DO_3, multiple references exists. This has implications for the relations.
NEW_O = { CopyOf_DO_2(AE_2), CopyOf_DO_4(AE_4) }
We can set up a new set of objects, that are the "merged" objects of TARGET and REFERENCE:
MERGED_O = TARGET + NEW_O = { DO_10(AE_0), DO_11(AE_1), DO_12(AE_3), DO_13(AE_3), DO_14(AE5), CopyOf_DO_2(AE_2), CopyOf_DO_4(AE_4) }
Now, relations:
SOURCE_R = { DR_0(AR_0,DO_1,DO_3), DR_1(AR_1,DO_0,DO_3), DR_2(AR_2,DO_0,DO_4), DR_3(AR_3,DO_2,DO_4) }
TARGET_R = { DR_10(AR_0,DO_11,DO_13), DR_11(AR_1,DO_10,DO_12), DR_12(AR_4,DO_12,DO_14) }
Applying the principle, where the REFERENCE_O are used to resolve references from SOURCE to TARGET, we get:
DR_0(AR_0,DO_1,DO_3): The REFERENCE_O, says the source end (DO_1) must be mapped to DO_11. It says the target end must be mapped to DO_12 and DO_13. Checking the TARGET_R, there is already a connection DR_10(AR_0,DO_11,DO_13), so this is not recreated. However, there is no DR_X(AR_0,DO_11,DO_12), so this must be created as a copy of DR_0: CopyOf_DR_0(AR_0,D0_11,DO_12).
NEW_R = { CopyOf_DR_0(AR_0,D0_11,DO_12) }.
DR_1(AR_1,DO_0,DO_3): The reference maps to s:DO_10(AE_0) and t:{DO_12,DO_13}. Checking TARGET_R, there is already a connection DR_11(AR_1,DO_10,DO_12), but no DR_11(AR_1,DO_10,DO_13). This is created as CopyOf_DR_1(AR_1,DO_10,DO_13).
NEW_R = { CopyOf_DR_0(AR_0,D0_11,DO_12), CopyOf_DR_1(AR_1,DO_10,DO_13) }.
Applying furter, we end up with:
NEW_R = { CopyOf_DR_0(AR_0,D0_11,DO_12), CopyOf_DR_1(AR_1,DO_10,DO_13), CopyOf_DR_2(AR_2,DO_10,CopyOf_DO_4), CopyOf_DR_3(AR_3,CopyOf_DO_2(AE_2),CopyOf_DO_4) }
So, the end situation is that:
MERGED_O = { DO_10(AE_0), DO_11(AE_1), DO_12(AE_3), DO_13(AE_3), DO_14(AE5), CopyOf_DO_2(AE_2), CopyOf_DO_4(AE_4) }
MERGED_R = { DR_10(AR_0,DO_11,DO_13), DR_11(AR_1,DO_10,DO_12), DR_12(AR_4,DO_12,DO_14), CopyOf_DR_0(AR_0,D0_11,DO_12), CopyOf_DR_1(AR_1,DO_10,DO_13), CopyOf_DR_2(AR_2,DO_10,CopyOf_DO_4), CopyOf_DR_3(AR_3,CopyOf_DO_2(AE_2),CopyOf_DO_4) }
Note: The merge operation still needs to track nested stuff, and there are some issues about creating new connections between elements (but, drag and drop solves this, so I guess it is possibly), and laying out new objects, but I am sure that is solvable.
Complications
TODO: Write this / integrate into above / might be ignored.
-
Connections are directional - they are only registered with the source??? If a source of target DE is not pasted - can you create a connection anyway for merge (does this even make sense, I am writing right now?)
-
Can you create new DR's if pasting two elements with a relation, and you decide to reuse an existing DE? How are they layouted? It must be similar to drag and drop. What does it do, if there are multiple elements, btw?