001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.util; 003 004import java.awt.Component; 005 006import javax.swing.JTable; 007import javax.swing.ListSelectionModel; 008import javax.swing.event.ListDataEvent; 009import javax.swing.event.ListSelectionEvent; 010import javax.swing.table.AbstractTableModel; 011import javax.swing.table.TableCellRenderer; 012import javax.swing.table.TableColumn; 013 014import org.openstreetmap.josm.gui.dialogs.IEnabledStateUpdating; 015 016/** 017 * The class that provide common JTable customization methods 018 * @since 5785 019 */ 020public final class TableHelper { 021 022 private TableHelper() { 023 // Hide default constructor for utils classes 024 } 025 026 /** 027 * Wires <code>listener</code> to <code>listSelectionModel</code> in such a way, that 028 * <code>listener</code> receives a {@link IEnabledStateUpdating#updateEnabledState()} 029 * on every {@link ListSelectionEvent}. 030 * 031 * @param listener the listener 032 * @param listSelectionModel the source emitting {@link ListSelectionEvent}s 033 * @since 15226 034 */ 035 public static void adaptTo(final IEnabledStateUpdating listener, ListSelectionModel listSelectionModel) { 036 listSelectionModel.addListSelectionListener(e -> listener.updateEnabledState()); 037 } 038 039 /** 040 * Wires <code>listener</code> to <code>listModel</code> in such a way, that 041 * <code>listener</code> receives a {@link IEnabledStateUpdating#updateEnabledState()} 042 * on every {@link ListDataEvent}. 043 * 044 * @param listener the listener 045 * @param listModel the source emitting {@link ListDataEvent}s 046 * @since 15226 047 */ 048 public static void adaptTo(final IEnabledStateUpdating listener, AbstractTableModel listModel) { 049 listModel.addTableModelListener(e -> listener.updateEnabledState()); 050 } 051 052 static int getColumnHeaderWidth(JTable tbl, int col) { 053 TableColumn tableColumn = tbl.getColumnModel().getColumn(col); 054 TableCellRenderer renderer = tableColumn.getHeaderRenderer(); 055 056 if (renderer == null && tbl.getTableHeader() != null) 057 renderer = tbl.getTableHeader().getDefaultRenderer(); 058 059 if (renderer == null) 060 return 0; 061 062 Component c = renderer.getTableCellRendererComponent(tbl, tableColumn.getHeaderValue(), false, false, -1, col); 063 return c.getPreferredSize().width; 064 } 065 066 static int getMaxWidth(JTable tbl, int col) { 067 int maxwidth = getColumnHeaderWidth(tbl, col); 068 for (int row = 0; row < tbl.getRowCount(); row++) { 069 TableCellRenderer tcr = tbl.getCellRenderer(row, col); 070 Object val = tbl.getValueAt(row, col); 071 Component comp = tcr.getTableCellRendererComponent(tbl, val, false, false, row, col); 072 maxwidth = Math.max(comp.getPreferredSize().width, maxwidth); 073 } 074 return maxwidth; 075 } 076 077 /** 078 * adjust the preferred width of column col to the maximum preferred width of the cells (including header) 079 * @param tbl table 080 * @param col column index 081 * @param resizable if true, resizing is allowed 082 * @since 15176 083 */ 084 public static void adjustColumnWidth(JTable tbl, int col, boolean resizable) { 085 int maxwidth = getMaxWidth(tbl, col); 086 TableColumn column = tbl.getColumnModel().getColumn(col); 087 column.setPreferredWidth(maxwidth); 088 column.setResizable(resizable); 089 if (!resizable) { 090 column.setMaxWidth(maxwidth); 091 } 092 } 093 094 /** 095 * adjust the preferred width of column col to the maximum preferred width of the cells (including header) 096 * requires JTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 097 * @param tbl table 098 * @param col column index 099 * @param maxColumnWidth maximum column width 100 */ 101 public static void adjustColumnWidth(JTable tbl, int col, int maxColumnWidth) { 102 int maxwidth = getMaxWidth(tbl, col); 103 tbl.getColumnModel().getColumn(col).setPreferredWidth(Math.min(maxwidth+10, maxColumnWidth)); 104 } 105 106 /** 107 * adjust the table's columns to fit their content best 108 * requires JTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 109 * @param tbl table 110 * @since 14476 111 */ 112 public static void computeColumnsWidth(JTable tbl) { 113 for (int column = 0; column < tbl.getColumnCount(); column++) { 114 adjustColumnWidth(tbl, column, Integer.MAX_VALUE); 115 } 116 } 117 118 /** 119 * Returns an array of all of the selected indices in the selection model, in increasing order. 120 * Unfortunately this method is not available in OpenJDK before version 11, see 121 * https://bugs.openjdk.java.net/browse/JDK-8199395 122 * Code taken from OpenJDK 11. To be removed when we switch to Java 11 or later. 123 * 124 * @param selectionModel list selection model. 125 * 126 * @return all of the selected indices, in increasing order, 127 * or an empty array if nothing is selected 128 * @since 15226 129 */ 130 public static int[] getSelectedIndices(ListSelectionModel selectionModel) { 131 int iMin = selectionModel.getMinSelectionIndex(); 132 int iMax = selectionModel.getMaxSelectionIndex(); 133 134 if (iMin < 0 || iMax < 0) { 135 return new int[0]; 136 } 137 138 int[] rvTmp = new int[1 + iMax - iMin]; 139 int n = 0; 140 for (int i = iMin; i <= iMax; i++) { 141 if (selectionModel.isSelectedIndex(i)) { 142 rvTmp[n++] = i; 143 } 144 } 145 int[] rv = new int[n]; 146 System.arraycopy(rvTmp, 0, rv, 0, n); 147 return rv; 148 } 149}