001package jmri.jmrit.beantable; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004 005import java.awt.Component; 006import java.awt.event.ActionEvent; 007import java.awt.event.ActionListener; 008import java.text.MessageFormat; 009 010import javax.swing.BoxLayout; 011import javax.swing.JMenu; 012import javax.swing.JMenuBar; 013import javax.swing.JMenuItem; 014import javax.swing.JPanel; 015import javax.swing.JScrollPane; 016import javax.swing.JTable; 017import javax.swing.SortOrder; 018import javax.swing.table.TableRowSorter; 019 020import jmri.NamedBean; 021import jmri.swing.RowSorterUtil; 022import jmri.util.AlphanumComparator; 023 024/** 025 * Provide a JFrame to display a table of NamedBeans. 026 * <p> 027 * This frame includes the table itself at the top, plus a "bottom area" for 028 * things like an Add... button and checkboxes that control display options. 029 * <p> 030 * The usual menus are also provided here. 031 * <p> 032 * Specific uses are customized via the BeanTableDataModel implementation they 033 * provide, and by providing a {@link #extras} implementation that can in turn 034 * invoke {@link #addToBottomBox} as needed. 035 * 036 * @author Bob Jacobsen Copyright (C) 2003 037 */ 038public class BeanTableFrame<E extends NamedBean> extends jmri.util.JmriJFrame { 039 040 BeanTableDataModel<E> dataModel; 041 JTable dataTable; 042 final JPanel bottomBox; // panel at bottom for extra buttons etc 043 044 public BeanTableFrame() { 045 super(); 046 bottomBox = new JPanel(); 047 bottomBox.setLayout(new jmri.util.swing.WrapLayout( jmri.util.swing.WrapLayout.LEFT, 20, 5)); 048 } 049 050 public BeanTableFrame(String s) { 051 super(s); 052 bottomBox = new JPanel(); 053 bottomBox.setLayout(new jmri.util.swing.WrapLayout( jmri.util.swing.WrapLayout.LEFT, 20, 5)); 054 } 055 056 public BeanTableFrame(BeanTableDataModel<E> model, String helpTarget, JTable dataTab) { 057 058 this(); 059 dataModel = model; 060 this.dataTable = dataTab; 061 062 JScrollPane dataScroll = new JScrollPane(dataTable); 063 064 // give system name column as smarter sorter and use it initially 065 TableRowSorter<BeanTableDataModel<?>> sorter = new TableRowSorter<>(dataModel); 066 067 // use NamedBean's built-in Comparator interface for sorting the system name column 068 RowSorterUtil.setSortOrder(sorter, BeanTableDataModel.SYSNAMECOL, SortOrder.ASCENDING); 069 070 sorter.setComparator(BeanTableDataModel.USERNAMECOL, new AlphanumComparator()); 071 RowSorterUtil.setSortOrder(sorter, BeanTableDataModel.USERNAMECOL, SortOrder.ASCENDING); 072 073 this.dataTable.setRowSorter(sorter); 074 075 // configure items for GUI 076 dataModel.configureTable(dataTable); 077 078 // general GUI config 079 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 080 081 // add save menu item 082 JMenuBar menuBar = new JMenuBar(); 083 JMenu fileMenu = new JMenu(Bundle.getMessage("MenuFile")); 084 menuBar.add(fileMenu); 085 fileMenu.add(new jmri.configurexml.StoreMenu()); 086 087 JMenuItem printItem = new JMenuItem(Bundle.getMessage("PrintTable")); 088 fileMenu.add(printItem); 089 printItem.addActionListener(new ActionListener() { 090 @Override 091 public void actionPerformed(ActionEvent e) { 092 try { 093 // MessageFormat headerFormat = new MessageFormat(getTitle()); // not used below 094 MessageFormat footerFormat = new MessageFormat(getTitle() + " page {0,number}"); 095 dataTable.print(JTable.PrintMode.FIT_WIDTH, null, footerFormat); 096 } catch (java.awt.print.PrinterException e1) { 097 log.warn("error printing: {}", e1, e1); 098 } 099 } 100 }); 101 102 setJMenuBar(menuBar); 103 104 addHelpMenu(helpTarget, true); 105 106 // install items in GUI 107 getContentPane().add(dataScroll); 108 getContentPane().add(bottomBox); 109 110 // add extras, if desired by subclass 111 extras(); 112 113 // set Viewport preferred size from size of table 114 java.awt.Dimension dataTableSize = dataTable.getPreferredSize(); 115 // width is right, but if table is empty, it's not high 116 // enough to reserve much space. 117 dataTableSize.height = Math.max(dataTableSize.height, 400); 118 dataScroll.getViewport().setPreferredSize(dataTableSize); 119 120 // set preferred scrolling options 121 dataScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 122 dataScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 123 dataModel.persistTable(dataTable); 124 } 125 126 /** 127 * Hook to allow sub-types to install more items in GUI 128 */ 129 void extras() { 130 } 131 132 /** 133 * Add a component to the bottom box. Takes care of organising glue, struts 134 * etc 135 * 136 * @param comp {@link Component} to add 137 * @param c Class name 138 */ 139 @SuppressFBWarnings(value = "UUF_UNUSED_FIELD", 140 justification = "param c is required in the listedtableframe") 141 protected void addToBottomBox(Component comp, String c) { 142 bottomBox.add(comp); 143 } 144 145 @Override 146 public void dispose() { 147 if (dataModel != null) { 148 dataModel.stopPersistingTable(dataTable); 149 dataModel.dispose(); 150 } 151 dataModel = null; 152 dataTable = null; 153 super.dispose(); 154 } 155 156 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BeanTableFrame.class); 157 158}