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()
