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;

Reply via email to