This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch past-M2 in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit 5f78e6dbcf524ec3d6a592f4b6096c1bf627d853 Author: Andrus Adamchik <[email protected]> AuthorDate: Thu Jun 11 19:05:42 2026 -0400 CAY-2959 Modeler: DbRelationship dialog "Cancel" does not cancel bonus points: do notdirty the project of no changes occured --- .../ui/dbrelationship/DbRelationshipDialog.java | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbrelationship/DbRelationshipDialog.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbrelationship/DbRelationshipDialog.java index 8a1d5184c..0d83b75b8 100644 --- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbrelationship/DbRelationshipDialog.java +++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/dbrelationship/DbRelationshipDialog.java @@ -317,6 +317,11 @@ public class DbRelationshipDialog extends ProjectDialog { private void save() { stopEditing(); + // "Done" with no edits must behave like "Cancel" - no mutation, no events, no dirty flag + if (!create && !hasChanges()) { + return; + } + handleNameUpdate(relationship, name.getText().trim()); // the single place where the dialog editing state is written to the relationship @@ -394,6 +399,56 @@ public class DbRelationshipDialog extends ProjectDialog { } } + /** + * Compares the dialog widget state against the untouched relationship, covering every input that + * {@link #save()} would write. Must be called before any mutation. + */ + private boolean hasChanges() { + if (!Objects.equals(relationship.getName(), name.getText().trim())) { + return true; + } + if (!Objects.equals(relationship.getTargetEntityName(), currentTarget != null ? currentTarget.getName() : null)) { + return true; + } + if (relationship.isToMany() != toMany.isSelected()) { + return true; + } + if (relationship.isToDependentPK() != toDepPk.isSelected()) { + return true; + } + if (unsetReverseDepPk && reverseRelationship != null && reverseRelationship.isToDependentPK()) { + return true; + } + if (reverseRelationship != null + && !Objects.equals(reverseRelationship.getName(), reverseName.getText().trim())) { + return true; + } + if (joinsChanged()) { + return true; + } + + String oldComment = ObjectInfo.getFromMetaData(app.getMetaData(), relationship, ObjectInfo.COMMENT); + return !Objects.equals(oldComment != null ? oldComment : "", comment.getText()); + } + + /** + * Compares the join table rows against the relationship's joins, ignoring blank rows (the ones + * {@link DbJoinTableModel#commit()} drops) and row order, so that merely sorting the table by a column + * doesn't count as a change. + */ + private boolean joinsChanged() { + List<String> edited = ((DbJoinTableModel) table.getModel()).getObjectList().stream() + .filter(j -> j.getSourceName() != null || j.getTargetName() != null) + .map(j -> j.getSourceName() + "→" + j.getTargetName()) + .sorted() + .toList(); + List<String> existing = relationship.getJoins().stream() + .map(j -> j.getSourceName() + "→" + j.getTargetName()) + .sorted() + .toList(); + return !edited.equals(existing); + } + private void handleNameUpdate(DbRelationship rel, String userInputName) { if (Objects.equals(rel.getName(), userInputName)) { return;
