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 7f4305129f49c83b87885bf3cb777ff2bc71a913
Author: Andrus Adamchik <[email protected]>
AuthorDate: Thu May 7 09:55:17 2026 -0400

    CAY-2934 Modeler: dropdown data trunction
---
 RELEASE-NOTES.txt                                  |  1 +
 .../modeler/toolkit/combobox/AutoCompletion.java   | 42 +++++++--------
 .../modeler/toolkit/combobox/SuggestionList.java   | 21 ++++++--
 .../toolkit/table/CMComboBoxCellEditor.java        | 60 ++++++++++++++++++++++
 4 files changed, 100 insertions(+), 24 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 02da2510d..7e7984591 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -63,6 +63,7 @@ CAY-2919 Exception in "Generate Database Schema"
 CAY-2921 Modeler: consistent duplicate name handling
 CAY-2926 Modeler: renaming an ObjEntity adds it to cgen excludeEntities
 CAY-2931 Modeler: default encoding detected as UTF8, should be UTF-8
+CAY-2934 Modeler: dropdown data trunction
 
 ----------------------------------
 Release: 5.0-M1
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/AutoCompletion.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/AutoCompletion.java
index b436be59e..e433b646c 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/AutoCompletion.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/AutoCompletion.java
@@ -40,24 +40,24 @@ public class AutoCompletion implements FocusListener, 
KeyListener, Runnable {
      * Property to mark combobox as 'auto-completing'
      */
     public static final String AUTOCOMPLETION_PROPERTY = 
"JComboBox.autoCompletion";
-    
+
     /**
      * A list with matching items
      */
-    private final SuggestionList suggestionList; 
+    private final SuggestionList suggestionList;
 
     /**
      * Combo with auto-completion
      */
     private final JComboBox comboBox;
-    
+
     private final JTextComponent textEditor;
-    
+
     private final boolean allowsUserValues;
-    
-    protected AutoCompletion(final JComboBox comboBox, boolean strict, boolean 
allowsUserValues, Supplier<MappingNamespace> namespaceSupplier) {
+
+    protected AutoCompletion(JComboBox comboBox, boolean strict, boolean 
allowsUserValues, Supplier<MappingNamespace> namespaceSupplier) {
         this.comboBox = comboBox;
-        textEditor = 
((JTextComponent)comboBox.getEditor().getEditorComponent());
+        textEditor = ((JTextComponent) 
comboBox.getEditor().getEditorComponent());
         this.allowsUserValues = allowsUserValues;
         suggestionList = new SuggestionList(comboBox, strict, 
namespaceSupplier);
 
@@ -68,9 +68,9 @@ public class AutoCompletion implements FocusListener, 
KeyListener, Runnable {
     /**
      * Enables auto-completion for specified combobox
      *
-     * @param comboBox Combo to be featured
-     * @param strict Whether strict matching (check 'startWith' or 'contains') 
should be used
-     * @param allowsUserValues Whether non-present items are allowed
+     * @param comboBox          Combo to be featured
+     * @param strict            Whether strict matching (check 'startWith' or 
'contains') should be used
+     * @param allowsUserValues  Whether non-present items are allowed
      * @param namespaceSupplier Supplies the {@link MappingNamespace} 
(typically the currently selected DataMap)
      *                          used to render entity labels.
      */
@@ -98,7 +98,8 @@ public class AutoCompletion implements FocusListener, 
KeyListener, Runnable {
         enable(comboBox, true, false, namespaceSupplier);
     }
 
-    public void focusGained(FocusEvent e) {}
+    public void focusGained(FocusEvent e) {
+    }
 
     public void focusLost(FocusEvent e) {
         suggestionList.hide();
@@ -119,7 +120,8 @@ public class AutoCompletion implements FocusListener, 
KeyListener, Runnable {
         }
     }
 
-    public void keyTyped(KeyEvent e) {}
+    public void keyTyped(KeyEvent e) {
+    }
 
     public void run() {
         String text = textEditor.getText();
@@ -136,7 +138,7 @@ public class AutoCompletion implements FocusListener, 
KeyListener, Runnable {
             }
         }
     }
-    
+
     /**
      * Calculates next selection row, according to a pressed key and selects 
it.
      * This might affect either suggestion list or original popup
@@ -154,7 +156,7 @@ public class AutoCompletion implements FocusListener, 
KeyListener, Runnable {
         suggestionListScrolling();
     }
 
-    private void processKeyPressedWhenSuggestionListIsInvisible(KeyEvent e){
+    private void processKeyPressedWhenSuggestionListIsInvisible(KeyEvent e) {
         int sel = comboBox.getSelectedIndex();
         int max = comboBox.getItemCount() - 1;
 
@@ -189,10 +191,10 @@ public class AutoCompletion implements FocusListener, 
KeyListener, Runnable {
                 return;
         }
         e.consume();
-        handleNavigationKeys(false,next,sel,max);
+        handleNavigationKeys(false, next, sel, max);
     }
 
-    private void processKeyPressedWhenSuggestionListIsVisible(KeyEvent e){
+    private void processKeyPressedWhenSuggestionListIsVisible(KeyEvent e) {
         int sel = suggestionList.getSelectedIndex();
         int max = suggestionList.getItemCount() - 1;
         int next;
@@ -229,10 +231,10 @@ public class AutoCompletion implements FocusListener, 
KeyListener, Runnable {
                 return;
         }
         e.consume();
-        handleNavigationKeys(true,next,sel,max);
+        handleNavigationKeys(true, next, sel, max);
     }
 
-    private void processEnterPressed(){
+    private void processEnterPressed() {
         Object value = suggestionList.getSelectedValue();
         if (!allowsUserValues && value == null && 
suggestionList.getItemCount() > 0) {
             value = suggestionList.getItemAt(0);
@@ -244,7 +246,7 @@ public class AutoCompletion implements FocusListener, 
KeyListener, Runnable {
         suggestionList.hide();
     }
 
-    private void handleNavigationKeys(boolean suggest, int next, int sel, int 
max){
+    private void handleNavigationKeys(boolean suggest, int next, int sel, int 
max) {
         if (!suggest && !comboBox.isPopupVisible()) {
             comboBox.setPopupVisible(true);
             return;
@@ -271,7 +273,7 @@ public class AutoCompletion implements FocusListener, 
KeyListener, Runnable {
         }
     }
 
-    private void suggestionListScrolling(){
+    private void suggestionListScrolling() {
         JList list = suggestionList.getList();
         int selectedIndex = suggestionList.getSelectedIndex();
         list.ensureIndexIsVisible(selectedIndex);
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/SuggestionList.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/SuggestionList.java
index 5cb499922..d78f6c42a 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/SuggestionList.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/combobox/SuggestionList.java
@@ -31,11 +31,11 @@ import java.awt.event.MouseListener;
 import java.util.function.Supplier;
 
 /**
- * SuggestionList is a combo-popup displaying all items matching for
- * autocompletion.
- *
+ * SuggestionList is a combo-popup displaying all items matching for 
autocompletion.
  */
-public class SuggestionList extends BasicComboPopup {
+class SuggestionList extends BasicComboPopup {
+
+    private static final int MAX_POPUP_WIDTH = 450;
 
     /**
      * 'Strict' matching, i.e. whether 'startWith' or 'contains' function
@@ -96,6 +96,19 @@ public class SuggestionList extends BasicComboPopup {
         return super.getPopupHeightForRowCount(Math.min(maxRowCount, 
list.getModel().getSize()));
     }
 
+    /**
+     * Expands the popup width to fit the widest filtered item.
+     * Called by BasicComboPopup.show() before the scroll pane is constrained,
+     * so getScrollPane().getPreferredSize() still reflects natural content 
width.
+     */
+    @Override
+    protected Rectangle computePopupBounds(int px, int py, int pw, int ph) {
+        Rectangle bounds = super.computePopupBounds(px, py, pw, ph);
+        int naturalWidth = scroller.getPreferredSize().width;
+        int targetWidth = Math.min(Math.max(naturalWidth, pw), 
MAX_POPUP_WIDTH);
+        return new Rectangle(bounds.x, bounds.y, targetWidth, bounds.height);
+    }
+
     /**
      * @return selected index in popup
      */
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/table/CMComboBoxCellEditor.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/table/CMComboBoxCellEditor.java
index de331f335..219bc47d3 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/table/CMComboBoxCellEditor.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/table/CMComboBoxCellEditor.java
@@ -23,9 +23,15 @@ import 
org.apache.cayenne.modeler.toolkit.combobox.AutoCompletion;
 
 import javax.swing.AbstractCellEditor;
 import javax.swing.JComboBox;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
 import javax.swing.JTable;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
 import javax.swing.table.TableCellEditor;
 import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
@@ -45,6 +51,8 @@ public class CMComboBoxCellEditor extends AbstractCellEditor
     // is read by Swing's combo UI to keep the popup behavior table-friendly.
     static final String IS_TABLE_CELL_EDITOR_PROPERTY = 
"JComboBox.isTableCellEditor";
 
+    private static final int MAX_POPUP_WIDTH = 450;
+
     private final JComboBox<?> comboBox;
     private final boolean autocomplete;
 
@@ -57,6 +65,15 @@ public class CMComboBoxCellEditor extends AbstractCellEditor
             comboBox.putClientProperty(IS_TABLE_CELL_EDITOR_PROPERTY, 
Boolean.TRUE);
             comboBox.addActionListener(this);
         }
+
+        comboBox.addPopupMenuListener(new PopupMenuListener() {
+            @Override
+            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+                adjustPopupWidth();
+            }
+            @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent 
e) {}
+            @Override public void popupMenuCanceled(PopupMenuEvent e) {}
+        });
     }
 
     @Override
@@ -71,6 +88,49 @@ public class CMComboBoxCellEditor extends AbstractCellEditor
         return comboBox;
     }
 
+    private void adjustPopupWidth() {
+        Object child = comboBox.getUI().getAccessibleChild(comboBox, 0);
+        if (!(child instanceof JPopupMenu)) {
+            return;
+        }
+        JPopupMenu popup = (JPopupMenu) child;
+        JScrollPane scrollPane = findScrollPane(popup);
+        if (scrollPane == null) {
+            return;
+        }
+
+        // BasicComboPopup.show() constrains the scroll pane's preferredSize 
and maximumSize
+        // to the column width before firing this listener. Reset them so the 
scroll pane
+        // reports its natural content-based width — which already 
incorporates item metrics,
+        // list insets, scrollbar width, and scroll pane borders — no manual 
overhead needed.
+        scrollPane.setPreferredSize(null);
+        scrollPane.setMaximumSize(null);
+        popup.setPreferredSize(null);
+
+        int naturalWidth = scrollPane.getPreferredSize().width;
+        int targetWidth = Math.min(Math.max(naturalWidth, 
comboBox.getWidth()), MAX_POPUP_WIDTH);
+
+        Dimension scrollSize = new Dimension(targetWidth, 
scrollPane.getPreferredSize().height);
+        scrollPane.setPreferredSize(scrollSize);
+        scrollPane.setMaximumSize(scrollSize);
+        popup.setPreferredSize(new Dimension(targetWidth, 
popup.getPreferredSize().height));
+    }
+
+    private static JScrollPane findScrollPane(Container container) {
+        for (Component c : container.getComponents()) {
+            if (c instanceof JScrollPane) {
+                return (JScrollPane) c;
+            }
+            if (c instanceof Container) {
+                JScrollPane found = findScrollPane((Container) c);
+                if (found != null) {
+                    return found;
+                }
+            }
+        }
+        return null;
+    }
+
     @Override
     public boolean stopCellEditing() {
         if (autocomplete && comboBox.isEditable()) {

Reply via email to