001package jmri.util.swing; 002 003import java.awt.Component; 004import java.awt.GraphicsEnvironment; 005import java.awt.Rectangle; 006import javax.swing.JComboBox; 007import javax.swing.JList; 008import javax.swing.ListModel; 009 010/** 011 * Common utility methods for working with JComboBoxes. 012 * <p> 013 * To do vertical sizing of <u>empty</u> JComboBoxen, 014 * this will create a dummy object and cast it to the 015 * contents' type. This can fail. 016 * 017 * @author Bob Jacobsen Copyright 2003, 2010 018 * @since 4.9.5 019 */ 020public class JComboBoxUtil { 021 022 /** 023 * Set the maximum number of rows for a JComboBox so that it always can fit 024 * on the screen 025 * <p> 026 * To do vertical sizing of <u>empty</u> JComboBoxen, 027 * this will create a temporary String and use that to set a default height based 028 * on the current font settings. 029 * 030 * @param <E> type of JComboBox contents 031 * @param <T> subclass of JComboBox being setup 032 * @param inComboBox the JComboBox to setup 033 */ 034 public static <E extends Object, T extends JComboBox<E>> void setupComboBoxMaxRows(T inComboBox) { 035 int maxItemHeight = 12; // pick some absolute minimum here 036 037 if (inComboBox.getItemCount() == 0 || (inComboBox.getItemCount() == 1 && "".equals(inComboBox.getItemAt(0)))) { 038 maxItemHeight = getDefaultRowHeight(maxItemHeight); 039 } 040 041 ListModel<E> lm = inComboBox.getModel(); 042 JList<E> list = new JList<>(lm); 043 044 for (int i = 0; i < lm.getSize(); ++i) { 045 E value = lm.getElementAt(i); 046 Component c = list.getCellRenderer().getListCellRendererComponent(list, value, i, false, false); 047 maxItemHeight = Math.max(maxItemHeight, c.getPreferredSize().height); 048 } 049 // Compensate for slightly undersized cell height for macOS 050 // The last rows will be off the screen if the dock is hidden 051 if (jmri.util.SystemType.isMacOSX()) maxItemHeight++; 052 053 int itemsPerScreen = inComboBox.getItemCount(); 054 // calculate the number of items that will fit on the screen 055 if (!GraphicsEnvironment.isHeadless()) { 056 // note: this line returns the maximum available size, accounting all 057 // taskbars etc. no matter where they are aligned: 058 Rectangle maxWindowBounds = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); 059 itemsPerScreen = (int) maxWindowBounds.getHeight() / maxItemHeight; 060 } 061 062 int c = Math.max(itemsPerScreen - 1, 8); 063 064 // Adjust max rows if the Preferences => Display setting is greater than zero. 065 int maxRows = jmri.InstanceManager.getDefault(jmri.util.gui.GuiLafPreferencesManager.class).getMaxComboRows(); 066 if (maxRows > 0) { 067 c = Math.min(c, maxRows); 068 } 069 070 inComboBox.setMaximumRowCount(c); 071 } 072 073 /** 074 * Set a default row height if the related combo box is empty. 075 * @param minimumHeight The default minimum height. 076 * @return a new height based on sample text. 077 */ 078 private static int getDefaultRowHeight(int minimumHeight) { 079 String[] data = {"XYZxyz"}; 080 JList<String> list = new JList<>(data); 081 String value = list.getModel().getElementAt(0); 082 Component c = list.getCellRenderer().getListCellRendererComponent(list, value, 0, false, false); 083 return Math.max(minimumHeight, c.getPreferredSize().height); 084 } 085 086// private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(JComboBoxUtil.class); 087}