Skip to content

Commit 2b35e20

Browse files
committed
CayenneModeler .. Messy combo box sizing for editable popups
vibecoding vs Swing :-/
1 parent 35bc313 commit 2b35e20

1 file changed

Lines changed: 24 additions & 23 deletions

File tree

modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/toolkit/table/CMComboBoxCellEditor.java

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,10 @@ public CMComboBoxCellEditor(JComboBox<?> comboBox) {
6262
comboBox.addPopupMenuListener(new PopupMenuListener() {
6363
@Override
6464
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
65-
// First call: sets popup.preferredSize so the popup *window* is created at the
66-
// correct width (window size is determined from popup.preferredSize before show()).
67-
adjustPopupWidth();
68-
// Second call via invokeLater: BasicComboPopup.show() calls getPopupLocation()
69-
// *after* firing this listener, which re-constrains scroller.maxSize back to the
70-
// column width. Running again on the next EDT cycle fixes the scroller, then
71-
// revalidate/repaint forces the layout to update inside the already-wide window.
72-
SwingUtilities.invokeLater(() -> {
73-
adjustPopupWidth();
74-
Object child = comboBox.getUI().getAccessibleChild(comboBox, 0);
75-
if (child instanceof JPopupMenu popup) {
76-
popup.revalidate();
77-
popup.repaint();
78-
}
79-
});
65+
// BasicComboPopup.show() calls getPopupLocation() after this listener fires,
66+
// constraining the popup to the column width. Adjust on the next EDT cycle —
67+
// invokeLater lands ahead of the first WM_PAINT, so no flash occurs.
68+
SwingUtilities.invokeLater(() -> adjustPopupWidth());
8069
}
8170
@Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {}
8271
@Override public void popupMenuCanceled(PopupMenuEvent e) {}
@@ -97,30 +86,42 @@ public Component getTableCellEditorComponent(JTable table, Object value,
9786

9887
private void adjustPopupWidth() {
9988
Object child = comboBox.getUI().getAccessibleChild(comboBox, 0);
100-
if (!(child instanceof JPopupMenu)) {
89+
if (!(child instanceof JPopupMenu popup)) {
10190
return;
10291
}
103-
JPopupMenu popup = (JPopupMenu) child;
10492
JScrollPane scrollPane = findScrollPane(popup);
10593
if (scrollPane == null) {
10694
return;
10795
}
96+
Window window = SwingUtilities.getWindowAncestor(popup);
97+
if (window == null) {
98+
return;
99+
}
108100

109-
// BasicComboPopup.show() constrains the scroll pane's preferredSize and maximumSize
110-
// to the column width before firing this listener. Reset them so the scroll pane
111-
// reports its natural content-based width — which already incorporates item metrics,
112-
// list insets, scrollbar width, and scroll pane borders — no manual overhead needed.
101+
// Clear sizes set by BasicComboPopup.getPopupLocation() so the scroll pane
102+
// reports its natural content-based width.
113103
scrollPane.setPreferredSize(null);
114104
scrollPane.setMaximumSize(null);
115105
popup.setPreferredSize(null);
116106

117107
int naturalWidth = scrollPane.getPreferredSize().width;
118108
int targetWidth = Math.min(Math.max(naturalWidth, comboBox.getWidth()), ComboBoxPopup.MAX_WIDTH);
119109

120-
Dimension scrollSize = new Dimension(targetWidth, scrollPane.getPreferredSize().height);
110+
// Use the window's actual height — correctly determined by BasicComboPopup based on row count.
111+
// Setting scroller maxSize to windowHeight lets BoxLayout fill all available vertical space.
112+
int windowHeight = window.getHeight();
113+
Dimension scrollSize = new Dimension(targetWidth, windowHeight);
121114
scrollPane.setPreferredSize(scrollSize);
122115
scrollPane.setMaximumSize(scrollSize);
123-
popup.setPreferredSize(new Dimension(targetWidth, popup.getPreferredSize().height));
116+
popup.setPreferredSize(new Dimension(targetWidth, windowHeight));
117+
118+
// Widen the popup window; the height was already set correctly by BasicComboPopup.
119+
Point loc = window.getLocation();
120+
window.setSize(targetWidth, windowHeight);
121+
window.setLocation(loc);
122+
123+
popup.revalidate();
124+
popup.repaint();
124125
}
125126

126127
private static JScrollPane findScrollPane(Container container) {

0 commit comments

Comments
 (0)