Skip to content

Add Invert Connection Direction feature for ArchiMate diagrams#1214

Closed
Yassimba wants to merge 1 commit intoarchimatetool:masterfrom
Yassimba:invert-relations
Closed

Add Invert Connection Direction feature for ArchiMate diagrams#1214
Yassimba wants to merge 1 commit intoarchimatetool:masterfrom
Yassimba:invert-relations

Conversation

@Yassimba
Copy link
Copy Markdown
Contributor

@Yassimba Yassimba commented Mar 7, 2026

Summary

Adds "Invert Connection Direction" action for ArchiMate diagrams (with a ctrl+i, cmd+i shortcuts)

Changes

  • InvertConnectionCommand: New GEF command that inverts an IArchimateRelationship and all its
  • referencing diagram connections — swaps source/target, reverses bendpoints, and swaps text position.
  • Fully supports undo/redo.
  • InvertConnectionAction: New SelectionAction that validates selected connections against the ArchiMate relationship matrix, deduplicates by underlying relationship, and executes a CompoundCommand for batch inversion. Greyed out when no valid inversions exist.
  • ArchimateDiagramEditor: Registers the action in createActions()
  • ArchimateDiagramEditorActionBarContributor: Adds retarget action in buildActions()
  • ArchimateDiagramEditorContextMenuProvider: Adds entry to the right-click context menu
  • plugin.xml: Adds command definition and Ctrl+I / Cmd+I key binding in the diagram context

@Yassimba
Copy link
Copy Markdown
Contributor Author

Yassimba commented Mar 7, 2026

@Phillipus I checked against the new GEF classic interface and this should not break anything, I right now based my PR on main but if you want me to base it on one of the GEF branches you are currently working on let me know.

A fellow architect that works with Archi asked me if I could implement an invert relationship feature so when you went the wrong way you can quickly invert it. I tested this quite thorough, this should work right now and respect the relationship rules, one thing I wonder when bulk selecting (or single selecting) and a relationship is not allowed to be inverted I right now silently do nothing, if you feel a better UX is showing the user something about it not being allowed let me know but I liked this for now.

Thanks and if there is something you need (code) improvements some related additional feature or wanting me to fix this on a newer branch please let me know!

@Phillipus
Copy link
Copy Markdown
Member

Phillipus commented Mar 7, 2026

@YassinCh Thanks for the PR, I'll take a look at it soon. If it's OK we can look at adding to the next version of Archi.

< snip > removed my comment about what needs to be done for next version of Eclipse/GEF. Not relevant here. 😉

@Phillipus
Copy link
Copy Markdown
Member

I'll try and get this PR merged for Archi Archi 5.8.1 because we have another PR that needs to be merged.

@Phillipus
Copy link
Copy Markdown
Member

Phillipus commented Mar 18, 2026

Hi, can you make a small change? Could you remove the default key binding of Ctrl-I in plugin.xml? I found from experience that it's better to allow the user to set their own key bindings for non-core features. It may be that some users have already assigned Ctrl-I to another command. They can do this in keys preferences.

Optional stylistic changes (but only if you have time):

Pattern matching in InvertConnectionAction (gets rid of casts):

private Set<IArchimateRelationship> getValidRelationships() {
    Set<IArchimateRelationship> result = new HashSet<>();

    for(Object object : getSelectedObjects()) {
        if(!(object instanceof EditPart editPart && editPart.getModel() instanceof IDiagramModelArchimateConnection connection)) {
            continue;
        }

        IArchimateRelationship relationship = connection.getArchimateRelationship();

        // Skip if null or already validated — avoids redundant matrix lookup
        if(relationship == null || result.contains(relationship)) {
            continue;
        }

        // Check if the inverted relationship would be valid
        if(ArchimateModelUtils.isValidRelationship(relationship.getTarget().eClass(),
                relationship.getSource().eClass(), relationship.eClass())) {
            result.add(relationship);
        }
    }

    return result;
}

Use of Java record in InvertConnectionCommand

Here you could use a Java record (prefect for this type of thing:

private record ConnectionState(IDiagramModelArchimateConnection connection, IConnectable source, IConnectable target, int textPosition,
        List<int[]> bendpoints) {
}

for(IDiagramModelArchimateConnection connection : fRelationship.getReferencingDiagramConnections()) {
    ConnectionState state = new ConnectionState(connection, connection.getSource(), connection.getTarget(), connection.getTextPosition(), new ArrayList<>());
    for(IDiagramModelBendpoint bp : connection.getBendpoints()) {
        state.bendpoints().add(new int[] { bp.getStartX(), bp.getStartY(), bp.getEndX(), bp.getEndY() });
    }
    fConnectionStates.add(state);
}

@Yassimba
Copy link
Copy Markdown
Contributor Author

Heey! I cleaned up the code as you suggested and removed the keybind!

Tnx for the suggestions : )

@Phillipus
Copy link
Copy Markdown
Member

@YassinCh Thanks for that! I know they're nitpicky things but I just thought it might be better.

If you like you could combine into one line in InvertConnectionAction :

if(!(object instanceof EditPart editPart && editPart.getModel() instanceof IDiagramModelArchimateConnection connection)) {
    continue;
}

@Yassimba
Copy link
Copy Markdown
Contributor Author

Done :)

@Phillipus
Copy link
Copy Markdown
Member

Phillipus commented Mar 18, 2026

Thanks. Final thing now...in order to get a clean merge the commits should be squashed into one clean commit. Is this OK for you to do?

@Phillipus
Copy link
Copy Markdown
Member

Also, the following key binding entry will have to be removed completely from plugin.xml as it gives an error "Attribute 'sequence' of element 'key' must be defined.":

      <key
            commandId="com.archimatetool.editor.action.invertConnection"
            contextId="com.archimatetool.editor.diagram.context"
            schemeId="com.archimatetool.editor.keybindings">
      </key>

@Yassimba
Copy link
Copy Markdown
Contributor Author

Fixed!

@Phillipus
Copy link
Copy Markdown
Member

Thanks! If you're happy with it I can merge.

@Yassimba
Copy link
Copy Markdown
Contributor Author

Thanks I am ! will be cool

@Phillipus
Copy link
Copy Markdown
Member

Phillipus commented Mar 18, 2026

I've merged this now in the "dev" branch.

@YassinCh Many thanks for this PR, it was well done and I'm sure Archi users will find it very useful. It will be in the next version of Archi.

Phil

@Phillipus Phillipus closed this Mar 18, 2026
@Phillipus
Copy link
Copy Markdown
Member

Phillipus commented Mar 18, 2026

@YassinCh Hi, there seems to be a problem with changing the bendpoints on a connection. Here's a video of one example:

Screen.Recording.2026-03-18.at.19.24.55.mov

Could you take a look?

@Phillipus Phillipus reopened this Mar 18, 2026
@Phillipus
Copy link
Copy Markdown
Member

Phillipus commented Mar 18, 2026

@YassinCh Hi, I've unmerged this from the dev branch as it needs more work. The bend-point handling I think needs a new approach.

Also, fRelationship.connect(fOldTarget, fOldSource) may not be necessary, but that needs more analysis.

@Yassimba
Copy link
Copy Markdown
Contributor Author

Heey thanks for checking that is a good one I do realise I mostly tested it for straight connections, I will look at it tommorow

When do you plan to release 5.8.1? Just trying to get a feel so I can try to fix this in time

@Phillipus
Copy link
Copy Markdown
Member

When do you plan to release 5.8.1? Just trying to get a feel so I can try to fix this in time

No hurry. When it's ready. Thanks!

@Phillipus
Copy link
Copy Markdown
Member

Phillipus commented Mar 19, 2026

@YassinCh This seems to be a better solution:

82d0244

A copy of bendpoints is made and there's no need to swap source and target ends in the relationship as this is done when calling connect().

@Yassimba
Copy link
Copy Markdown
Contributor Author

Nice I like it !

@Phillipus
Copy link
Copy Markdown
Member

Nice I like it !

Could you test it to death please? ;-)

BTW - did you use AI at all in the original?

@Phillipus
Copy link
Copy Markdown
Member

Updated to 7d9a7ad - no need to declare a RetargetAction in ArchimateDiagramEditorActionBarContributor if it's not used in the main menu.

@Phillipus
Copy link
Copy Markdown
Member

Simplified even more in fa25eb2

I'm not sure the label text positions should be swapped. Surely those should remain the same?

@Phillipus
Copy link
Copy Markdown
Member

Added help documentation in ab909d3

@Yassimba
Copy link
Copy Markdown
Contributor Author

Yassimba commented Mar 19, 2026

Nice!! And I am not sure I wanted to keep the amount of visual difference the same. The reason is WHY someone would want to invert the relation. Say someone added a label and then realised he accidently swapped the relation. Do you want it when he inverts it to keep hte label where it is or swap as well?

I personally felt it should stay in the same spot

@Phillipus
Copy link
Copy Markdown
Member

Nice!! And I am not sure I wanted to keep the amount of visual difference the same. The reason is WHY someone would want to invert the relation. Say someone added a label and then realised he accidently swapped the relation. Do you want it when he inverts it to keep hte label where it is or swap as well?

I personally felt it should stay in the same spot

It depends. Does the user want the label at the actual source or target of the connection or do they want it physically at that position?

@Yassimba
Copy link
Copy Markdown
Contributor Author

Yassimba commented Mar 19, 2026

So what I feel is an example
data goes
MY DB -----------------------> MY OTHER DB

And then he realizes oh no I want to invert this relationship does he then want this label to be at the now new source? Or does he wanna keep it as is but just invert an access relationship which he accidently inverted>

@Yassimba
Copy link
Copy Markdown
Contributor Author

(SADLY my label isnt indenting cause of the comments but my point is likely the label is at the right box/actual object it tries to identify but is just the relationship swapped more likely? What do you think? You might be right but just checking :)

@Phillipus
Copy link
Copy Markdown
Member

For me if I set the label to be at source I want it left at source. One can always change it.

I think on this issue there will be two schools of thought. If we go one way sure enough someone will want the other way.

@Yassimba
Copy link
Copy Markdown
Contributor Author

Yassimba commented Mar 19, 2026

You have infinitely more experience in this then I do. So let's do it your way for sure :) I was just happy to challenge it a bit

@Phillipus
Copy link
Copy Markdown
Member

You have infinitely more experience in this then I do. So let's do it your way for sure :) I was just happy to challenge it a bit

Well, not really. Personally I don't mind either way. Let's sleep on it.

@Phillipus
Copy link
Copy Markdown
Member

Added internal preference to swap label positions 1895b64

@Phillipus
Copy link
Copy Markdown
Member

I've added unit tests in branch invert-connection.

As this is done now I'll close this PR.

@Phillipus Phillipus closed this Mar 20, 2026
@Yassimba
Copy link
Copy Markdown
Contributor Author

Tnx :)

@Yassimba
Copy link
Copy Markdown
Contributor Author

Was cool to see your approach to have worked on this together

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants