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