2929
3030package org .scijava .ui .swing .viewer .table ;
3131
32+ import java .awt .Component ;
33+ import java .awt .Toolkit ;
34+ import java .awt .event .ActionEvent ;
35+ import java .awt .event .ComponentAdapter ;
36+ import java .awt .event .ComponentEvent ;
37+ import java .awt .event .KeyEvent ;
38+ import java .util .Arrays ;
39+
40+ import javax .swing .AbstractAction ;
41+ import javax .swing .Action ;
42+ import javax .swing .JComponent ;
43+ import javax .swing .JMenuItem ;
44+ import javax .swing .JPopupMenu ;
3245import javax .swing .JScrollPane ;
3346import javax .swing .JTable ;
47+ import javax .swing .KeyStroke ;
3448import javax .swing .table .AbstractTableModel ;
49+ import javax .swing .table .TableCellRenderer ;
50+ import javax .swing .table .TableColumn ;
3551
3652import org .scijava .table .Table ;
3753import org .scijava .table .TableDisplay ;
@@ -65,9 +81,25 @@ public SwingTableDisplayPanel(final TableDisplay display,
6581 this .window = window ;
6682 nullModel = new NullTableModel ();
6783 table = makeTable ();
84+
6885 table .setAutoCreateRowSorter (true );
86+ table .setRowSelectionAllowed (true );
87+ new TablePopupMenu ().install ();
88+
89+ //table.setPreferredScrollableViewportSize(getPreferredSize());
90+ addComponentListener (new ComponentAdapter () {
91+ @ Override
92+ public void componentResized (final ComponentEvent e ) {
93+ if (table .getPreferredSize ().width < getWidth ()) {
94+ table .setAutoResizeMode (JTable .AUTO_RESIZE_ALL_COLUMNS );
95+ } else {
96+ table .setAutoResizeMode (JTable .AUTO_RESIZE_OFF );
97+ }
98+ }
99+ });
69100 setViewportView (table );
70101 window .setContent (this );
102+
71103 }
72104
73105 // -- TableDisplayPanel methods --
@@ -133,6 +165,7 @@ private JTable makeTable() {
133165
134166 // -- Helper classes --
135167
168+ @ SuppressWarnings ("serial" )
136169 public static class NullTableModel extends AbstractTableModel {
137170
138171 @ Override
@@ -209,6 +242,14 @@ public void setValueAt(final Object value, final int row, final int col) {
209242 fireTableCellUpdated (row , col );
210243 }
211244
245+ public void removeRows (int [] indices ) {
246+ Arrays .sort (indices );
247+ for (int i = indices .length - 1 ; i >= 0 ; i --) {
248+ tab .removeRow (indices [i ]);
249+ fireTableRowsDeleted (indices [i ], indices [i ]);
250+ }
251+ }
252+
212253 // -- Helper methods --
213254
214255 private <T > void set (final Table <?, T > table ,
@@ -221,4 +262,91 @@ private <T> void set(final Table<?, T> table,
221262
222263 }
223264
265+ @ SuppressWarnings ("serial" )
266+ class TablePopupMenu extends JPopupMenu {
267+ public TablePopupMenu () {
268+ super ();
269+ JMenuItem mi ;
270+ mi = new JMenuItem (new ActionMapAction ("Copy" , table , "copy" ));
271+ final int MASK = Toolkit .getDefaultToolkit ().getMenuShortcutKeyMask ();
272+ mi .setAccelerator (KeyStroke .getKeyStroke (KeyEvent .VK_C , MASK ));
273+ add (mi );
274+ mi = new JMenuItem (new ActionMapAction ("Select All" , table , "selectAll" ));
275+ mi .setAccelerator (KeyStroke .getKeyStroke (KeyEvent .VK_A , MASK ));
276+ add (mi );
277+ addSeparator ();
278+ mi = new JMenuItem ("Delete Selected Row(s)" );
279+ mi .addActionListener (e -> {
280+ final int [] selectedRows = table .getSelectedRows ();
281+ if (selectedRows .length > 0 )
282+ ((TableModel ) table .getModel ()).removeRows (selectedRows );
283+ });
284+ add (mi );
285+ mi = new JMenuItem ("Resize Column Widths" );
286+ mi .addActionListener (e -> resizeColumns ());
287+ add (mi );
288+ }
289+
290+ private void resizeColumns () {
291+ // https://stackoverflow.com/a/30355804
292+ table .setAutoResizeMode (JTable .AUTO_RESIZE_OFF );
293+ table .getTableHeader ();
294+ for (int column = 0 ; column < table .getColumnCount (); column ++) {
295+ final TableColumn tableColumn = table .getColumnModel ().getColumn (column );
296+ int preferredWidth = Math .max (tableColumn .getMinWidth (), getColumnHeaderWidth (tableColumn , column ));
297+ final int maxWidth = tableColumn .getMaxWidth ();
298+ for (int row = 0 ; row < table .getRowCount (); row ++) {
299+ final TableCellRenderer cellRenderer = table .getCellRenderer (row , column );
300+ final Component c = table .prepareRenderer (cellRenderer , row , column );
301+ final int width = c .getPreferredSize ().width + table .getIntercellSpacing ().width ;
302+ preferredWidth = Math .max (preferredWidth , width );
303+ if (preferredWidth >= maxWidth ) {
304+ preferredWidth = maxWidth ;
305+ break ;
306+ }
307+ }
308+ tableColumn .setPreferredWidth (preferredWidth );
309+ }
310+ }
311+
312+ private int getColumnHeaderWidth (final TableColumn tableColumn , final int column ) {
313+ final Object value = tableColumn .getHeaderValue ();
314+ TableCellRenderer renderer = tableColumn .getHeaderRenderer ();
315+ if (renderer == null ) {
316+ renderer = table .getTableHeader ().getDefaultRenderer ();
317+ }
318+ final Component c = renderer .getTableCellRendererComponent (table , value , false , false , -1 , column );
319+ return c .getPreferredSize ().width ;
320+ }
321+
322+ void install () {
323+ table .setComponentPopupMenu (this );
324+ SwingTableDisplayPanel .this .setComponentPopupMenu (this );
325+ }
326+
327+ }
328+
329+ @ SuppressWarnings ("serial" )
330+ private class ActionMapAction extends AbstractAction {
331+
332+ private final Action originalAction ;
333+ private final JComponent component ;
334+ private final String actionCommand = "" ;
335+
336+ ActionMapAction (final String name , final JComponent component , final String actionKey ) {
337+ super (name );
338+ originalAction = component .getActionMap ().get (actionKey );
339+ if (originalAction == null ) {
340+ throw new IllegalArgumentException ("No Action for action key: " + actionKey );
341+ }
342+ this .component = component ;
343+ }
344+
345+ @ Override
346+ public void actionPerformed (ActionEvent e ) {
347+ e = new ActionEvent (component , ActionEvent .ACTION_PERFORMED , actionCommand , e .getWhen (), e .getModifiers ());
348+ originalAction .actionPerformed (e );
349+ }
350+
351+ }
224352}
0 commit comments