This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 256398807cd2fbe3ecd1c844a468d04360e7ea1f
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sat May 23 10:32:00 2026 -0400

    Unifying combobox editors
---
 .../combobox/CMAutoCompleteComboBoxCellEditor.java | 61 ++++++++++++++++++++++
 .../toolkit/combobox/CMComboBoxCellEditor.java     | 59 ++++++---------------
 .../ui/dbrelationship/DbRelationshipDialog.java    |  6 +--
 .../dbentity/properties/DbAttributePanel.java      |  4 +-
 .../dbentity/properties/DbRelationshipPanel.java   |  4 +-
 .../attributes/EmbeddableAttributesView.java       |  4 +-
 .../duplicates/DuplicatedAttributesDialog.java     |  2 +-
 .../objentity/properties/ObjAttributePanel.java    |  4 +-
 .../editor/procedure/ProcedureParameterTab.java    |  3 +-
 9 files changed, 90 insertions(+), 57 deletions(-)

diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/CMAutoCompleteComboBoxCellEditor.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/CMAutoCompleteComboBoxCellEditor.java
new file mode 100644
index 000000000..6b6ced0a7
--- /dev/null
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/CMAutoCompleteComboBoxCellEditor.java
@@ -0,0 +1,61 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.modeler.toolkit.combobox;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+/**
+ * Combo box cell editor for autocomplete combos. Wires up the
+ * {@code "comboBoxEdited"} action-command path so that pressing Enter commits
+ * the edit, and sets {@code JComboBox.isTableCellEditor} so the Swing L&F
+ * keeps popup behaviour table-friendly.
+ */
+public class CMAutoCompleteComboBoxCellEditor extends CMComboBoxCellEditor 
implements ActionListener {
+
+    // Read by Swing's combo UI to keep the popup behaviour table-friendly.
+    private static final String IS_TABLE_CELL_EDITOR_PROPERTY = 
"JComboBox.isTableCellEditor";
+
+    public CMAutoCompleteComboBoxCellEditor(JComboBox<?> comboBox) {
+        super(comboBox);
+        comboBox.putClientProperty(IS_TABLE_CELL_EDITOR_PROPERTY, 
Boolean.TRUE);
+        comboBox.addActionListener(this);
+    }
+
+    @Override
+    public boolean stopCellEditing() {
+        if (comboBox.isEditable()) {
+            // Notify the combo that editing has stopped (e.g. focus lost, F2).
+            comboBox.actionPerformed(new ActionEvent(this, 0, ""));
+        }
+
+        return super.stopCellEditing();
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        // Selecting an item produces "comboBoxChanged" — ignore.
+        // Hitting enter produces "comboBoxEdited" — stop editing.
+        if ("comboBoxEdited".equals(e.getActionCommand())) {
+            stopCellEditing();
+        }
+    }
+}
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/CMComboBoxCellEditor.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/CMComboBoxCellEditor.java
index d1d858278..6b8bde884 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/CMComboBoxCellEditor.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/CMComboBoxCellEditor.java
@@ -22,38 +22,34 @@ package org.apache.cayenne.modeler.toolkit.combobox;
 import javax.swing.*;
 import javax.swing.table.TableCellEditor;
 import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
 import java.io.Serializable;
 import java.util.EventObject;
 
 /**
- * Combo box cell editor for the modeler. Handles both auto-completion-aware
- * and plain combos uniformly. Editing is suppressed for ctrl/shift-clicks so
- * the user can extend a multi-row selection without opening the editor.
+ * Plain combo box cell editor for the modeler. Editing is suppressed for
+ * ctrl/shift-clicks so the user can extend a multi-row selection without
+ * opening the editor.
  */
-public class CMComboBoxCellEditor extends AbstractCellEditor implements 
TableCellEditor, ActionListener, Serializable {
+public class CMComboBoxCellEditor extends AbstractCellEditor implements 
TableCellEditor, Serializable {
 
-    // Auto-complete combos collide with DefaultCellEditor's stop-editing flow,
-    // so they need a custom action-listener-based path. This client property
-    // is read by Swing's combo UI to keep the popup behavior table-friendly.
-    private static final String IS_TABLE_CELL_EDITOR_PROPERTY = 
"JComboBox.isTableCellEditor";
-
-    private final JComboBox<?> comboBox;
-    private final boolean autocomplete;
+    protected final JComboBox<?> comboBox;
 
     public CMComboBoxCellEditor(JComboBox<?> comboBox) {
         this.comboBox = comboBox;
-        this.autocomplete = Boolean.TRUE.equals(
-                
comboBox.getClientProperty(AutoCompletion.AUTOCOMPLETION_PROPERTY));
+        comboBox.addPopupMenuListener(new CMComboBoxPopupResizer(comboBox));
+    }
 
-        if (autocomplete) {
-            comboBox.putClientProperty(IS_TABLE_CELL_EDITOR_PROPERTY, 
Boolean.TRUE);
-            comboBox.addActionListener(this);
+    public static boolean isTableCellEditable(EventObject e) {
+        if (e instanceof MouseEvent me) {
+            return !me.isControlDown() && !me.isShiftDown();
         }
+        return true;
+    }
 
-        comboBox.addPopupMenuListener(new CMComboBoxPopupResizer(comboBox));
+    @Override
+    public boolean isCellEditable(EventObject e) {
+        return isTableCellEditable(e);
     }
 
     @Override
@@ -70,32 +66,7 @@ public class CMComboBoxCellEditor extends AbstractCellEditor 
implements TableCel
 
     @Override
     public boolean stopCellEditing() {
-        if (autocomplete && comboBox.isEditable()) {
-            // Notify the combo box that editing has stopped (e.g. user 
pressed F2).
-            comboBox.actionPerformed(new ActionEvent(this, 0, ""));
-        }
         fireEditingStopped();
         return true;
     }
-
-    public static boolean isTableCellEditable(EventObject e) {
-        if (e instanceof MouseEvent me) {
-            return !me.isControlDown() && !me.isShiftDown();
-        }
-        return true;
-    }
-
-    @Override
-    public boolean isCellEditable(EventObject e) {
-        return isTableCellEditable(e);
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        // Selecting an item produces "comboBoxChanged" — ignore.
-        // Hitting enter produces "comboBoxEdited" — stop editing.
-        if (autocomplete && "comboBoxEdited".equals(e.getActionCommand())) {
-            stopCellEditing();
-        }
-    }
 }
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 3fb61a545..28bcc3b97 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
@@ -36,7 +36,7 @@ import org.apache.cayenne.modeler.project.DbRelationshipOps;
 import org.apache.cayenne.modeler.toolkit.buttons.CMButtonPanel;
 import org.apache.cayenne.modeler.toolkit.combobox.AutoCompletion;
 import org.apache.cayenne.modeler.toolkit.combobox.CMComboBox;
-import org.apache.cayenne.modeler.toolkit.combobox.CMComboBoxCellEditor;
+import 
org.apache.cayenne.modeler.toolkit.combobox.CMAutoCompleteComboBoxCellEditor;
 import org.apache.cayenne.modeler.toolkit.table.CMTable;
 import org.apache.cayenne.modeler.pref.adapters.CMTablePrefs;
 import org.apache.cayenne.modeler.toolkit.ProjectDialog;
@@ -313,13 +313,13 @@ public class DbRelationshipDialog extends ProjectDialog {
         JComboBox<String> sourceCombo = new CMComboBox<>(
                 
dbAttributeNames(relationship.getSourceEntity()).stream().sorted().toArray(String[]::new));
         AutoCompletion.enable(sourceCombo, session::getSelectedDataMap);
-        sourceColumn.setCellEditor(new CMComboBoxCellEditor(sourceCombo));
+        sourceColumn.setCellEditor(new 
CMAutoCompleteComboBoxCellEditor(sourceCombo));
 
         TableColumn targetColumn = 
table.getColumnModel().getColumn(DbJoinTableModel.TARGET);
         JComboBox<String> targetCombo = new CMComboBox<>(
                 
dbAttributeNames(relationship.getTargetEntity()).stream().sorted().toArray(String[]::new));
         AutoCompletion.enable(targetCombo, session::getSelectedDataMap);
-        targetColumn.setCellEditor(new CMComboBoxCellEditor(targetCombo));
+        targetColumn.setCellEditor(new 
CMAutoCompleteComboBoxCellEditor(targetCombo));
 
         new CMTablePrefs(app.getPrefsManager().uiNode("dbEntity/dbjoinTable"))
                 .bind(table, null, DbJoinTableModel.SOURCE);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbAttributePanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbAttributePanel.java
index 35b9459c1..be320c60a 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbAttributePanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbAttributePanel.java
@@ -33,7 +33,7 @@ import org.apache.cayenne.modeler.toolkit.ProjectPanel;
 import org.apache.cayenne.modeler.toolkit.combobox.AutoCompletion;
 import org.apache.cayenne.modeler.toolkit.combobox.CMComboBox;
 import org.apache.cayenne.modeler.toolkit.table.BoardTableCellRenderer;
-import org.apache.cayenne.modeler.toolkit.combobox.CMComboBoxCellEditor;
+import 
org.apache.cayenne.modeler.toolkit.combobox.CMAutoCompleteComboBoxCellEditor;
 import org.apache.cayenne.modeler.toolkit.table.CMTable;
 import org.apache.cayenne.modeler.toolkit.table.CMTablePanel;
 import org.apache.cayenne.modeler.pref.adapters.CMTablePrefs;
@@ -183,7 +183,7 @@ public class DbAttributePanel extends ProjectPanel 
implements DbEntityDisplayLis
         AutoCompletion.enable(comboBox, session::getSelectedDataMap);
 
         TableColumn typeColumn = 
table.getColumnModel().getColumn(DbAttributeTableModel.DB_ATTRIBUTE_TYPE);
-        typeColumn.setCellEditor(new CMComboBoxCellEditor(comboBox));
+        typeColumn.setCellEditor(new 
CMAutoCompleteComboBoxCellEditor(comboBox));
 
         new 
CMTablePrefs(app.getPrefsManager().uiNode("dbEntity/attributeTable"))
                 .bind(table, null, DbAttributeTableModel.DB_ATTRIBUTE_NAME);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbRelationshipPanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbRelationshipPanel.java
index 42b6136ba..6f37b3848 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbRelationshipPanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/dbentity/properties/DbRelationshipPanel.java
@@ -45,7 +45,7 @@ import org.apache.cayenne.modeler.toolkit.table.CMTablePanel;
 import org.apache.cayenne.modeler.toolkit.Renderers;
 import org.apache.cayenne.modeler.toolkit.combobox.AutoCompletion;
 import org.apache.cayenne.modeler.toolkit.combobox.CMComboBox;
-import org.apache.cayenne.modeler.toolkit.combobox.CMComboBoxCellEditor;
+import 
org.apache.cayenne.modeler.toolkit.combobox.CMAutoCompleteComboBoxCellEditor;
 
 import javax.swing.*;
 import javax.swing.event.ListSelectionEvent;
@@ -188,7 +188,7 @@ public class DbRelationshipPanel extends ProjectPanel 
implements DbEntityDisplay
         targetCombo.setModel(createComboModel());
 
         TableColumn targetColumn = 
table.getColumnModel().getColumn(DbRelationshipTableModel.TARGET);
-        targetColumn.setCellEditor(new CMComboBoxCellEditor(targetCombo));
+        targetColumn.setCellEditor(new 
CMAutoCompleteComboBoxCellEditor(targetCombo));
 
         TableColumn toDepPkColumn = 
table.getColumnModel().getColumn(DbRelationshipTableModel.TO_DEPENDENT_KEY);
         toDepPkColumn.setCellRenderer(new CheckBoxCellRenderer());
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/attributes/EmbeddableAttributesView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/attributes/EmbeddableAttributesView.java
index a122547a0..5b5d38fcf 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/attributes/EmbeddableAttributesView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/embeddable/attributes/EmbeddableAttributesView.java
@@ -34,7 +34,7 @@ import 
org.apache.cayenne.modeler.service.action.GlobalActions;
 import org.apache.cayenne.modeler.toolkit.valuetype.ValueTypes;
 import org.apache.cayenne.modeler.toolkit.combobox.AutoCompletion;
 import org.apache.cayenne.modeler.toolkit.combobox.CMComboBox;
-import org.apache.cayenne.modeler.toolkit.combobox.CMComboBoxCellEditor;
+import 
org.apache.cayenne.modeler.toolkit.combobox.CMAutoCompleteComboBoxCellEditor;
 import org.apache.cayenne.modeler.toolkit.table.CMTable;
 import org.apache.cayenne.modeler.toolkit.table.CMTablePanel;
 import org.apache.cayenne.modeler.pref.adapters.CMTablePrefs;
@@ -169,7 +169,7 @@ public class EmbeddableAttributesView extends ProjectPanel 
implements
         TableColumn typeColumn = 
table.getColumnModel().getColumn(EmbeddableAttributeTableModel.OBJ_ATTRIBUTE_TYPE);
         JComboBox javaTypesCombo = new CMComboBox<>(ValueTypes.getTypes());
         AutoCompletion.enable(javaTypesCombo, false, true, 
session::getSelectedDataMap);
-        typeColumn.setCellEditor(new CMComboBoxCellEditor(javaTypesCombo));
+        typeColumn.setCellEditor(new 
CMAutoCompleteComboBoxCellEditor(javaTypesCombo));
 
         new 
CMTablePrefs(app.getPrefsManager().uiNode("embeddable/attributeTable"))
                 .bind(table, null, 
EmbeddableAttributeTableModel.OBJ_ATTRIBUTE);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/duplicates/DuplicatedAttributesDialog.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/duplicates/DuplicatedAttributesDialog.java
index 4287871e5..1e553721b 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/duplicates/DuplicatedAttributesDialog.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/duplicates/DuplicatedAttributesDialog.java
@@ -145,7 +145,7 @@ public class DuplicatedAttributesDialog extends AppDialog {
 
     private void updateTable() {
         TableColumn actionColumn = 
attributesTable.getColumnModel().getColumn(DuplicatedAttributeTableModel.ACTION);
-        JComboBox actionsCombo = new CMComboBox<>(DELETE_ACTION, 
RENAME_ACTION);
+        JComboBox<?> actionsCombo = new CMComboBox<>(DELETE_ACTION, 
RENAME_ACTION);
         actionColumn.setCellEditor(new CMComboBoxCellEditor(actionsCombo));
     }
 
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributePanel.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributePanel.java
index 0dcfce0cb..1ef32f16f 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributePanel.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/objentity/properties/ObjAttributePanel.java
@@ -39,7 +39,7 @@ import org.apache.cayenne.modeler.project.ObjEntityOps;
 import org.apache.cayenne.modeler.service.action.GlobalActions;
 import org.apache.cayenne.modeler.toolkit.combobox.AutoCompletion;
 import org.apache.cayenne.modeler.toolkit.combobox.CMComboBox;
-import org.apache.cayenne.modeler.toolkit.combobox.CMComboBoxCellEditor;
+import 
org.apache.cayenne.modeler.toolkit.combobox.CMAutoCompleteComboBoxCellEditor;
 import org.apache.cayenne.modeler.toolkit.icon.IconFactory;
 import org.apache.cayenne.modeler.toolkit.table.CMTable;
 import org.apache.cayenne.modeler.toolkit.table.CMTableModel;
@@ -166,7 +166,7 @@ public class ObjAttributePanel extends ProjectPanel 
implements ObjEntityDisplayL
 
         JComboBox<String> javaTypesCombo = new CMComboBox<>(typeNames);
         AutoCompletion.enable(javaTypesCombo, false, true, 
session::getSelectedDataMap);
-        typeColumn.setCellEditor(new CMComboBoxCellEditor(javaTypesCombo));
+        typeColumn.setCellEditor(new 
CMAutoCompleteComboBoxCellEditor(javaTypesCombo));
     }
 
     /**
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureParameterTab.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureParameterTab.java
index 1ecbd0c31..61e2c2b8d 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureParameterTab.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/procedure/ProcedureParameterTab.java
@@ -37,6 +37,7 @@ import org.apache.cayenne.modeler.toolkit.ProjectPanel;
 import org.apache.cayenne.modeler.toolkit.combobox.AutoCompletion;
 import org.apache.cayenne.modeler.toolkit.combobox.CMComboBox;
 import org.apache.cayenne.modeler.toolkit.icon.IconFactory;
+import 
org.apache.cayenne.modeler.toolkit.combobox.CMAutoCompleteComboBoxCellEditor;
 import org.apache.cayenne.modeler.toolkit.combobox.CMComboBoxCellEditor;
 import org.apache.cayenne.modeler.toolkit.table.CMTable;
 import org.apache.cayenne.modeler.toolkit.table.CMTablePanel;
@@ -274,7 +275,7 @@ public class ProcedureParameterTab extends ProjectPanel 
implements ProcedurePara
         Arrays.sort(dbTypes);
         JComboBox<String> typesEditor = new CMComboBox<>(dbTypes);
         AutoCompletion.enable(typesEditor, session::getSelectedDataMap);
-        typesColumn.setCellEditor(new CMComboBoxCellEditor(typesEditor));
+        typesColumn.setCellEditor(new 
CMAutoCompleteComboBoxCellEditor(typesEditor));
 
         // direction column tweaking
         TableColumn directionColumn = table.getColumnModel()

Reply via email to