001package jmri.jmrit.beantable; 002 003import java.awt.BorderLayout; 004import java.awt.event.ActionEvent; 005import java.util.ArrayList; 006 007import javax.annotation.Nonnull; 008import javax.swing.*; 009import javax.swing.event.*; 010import javax.swing.table.*; 011 012import jmri.*; 013import jmri.swing.RowSorterUtil; 014import jmri.util.AlphanumComparator; 015 016public abstract class AbstractTableTabAction<E extends NamedBean> extends AbstractTableAction<E> { 017 018 protected JTabbedPane dataTabs; 019 protected boolean init = false; 020 021 public AbstractTableTabAction(String s) { 022 super(s); 023 } 024 025 @Override 026 protected void createModel() { 027 dataTabs = new JTabbedPane(); 028 Manager<E> mgr = getManager(); 029 if (mgr instanceof jmri.managers.AbstractProxyManager) { 030 // build the list, with default at start and internal at end (if present) 031 jmri.managers.AbstractProxyManager<E> proxy = (jmri.managers.AbstractProxyManager<E>) mgr; 032 033 tabbedTableArray.add(new TabbedTableItem<>( 034 Bundle.getMessage("All"), true, mgr, getNewTableAction("All"))); // NOI18N 035 036 proxy.getDisplayOrderManagerList().stream().map(manager -> { 037 String manuName = manager.getMemo().getUserName(); 038 return new TabbedTableItem<>( 039 manuName, true, manager, getNewTableAction(manuName)); // connection name to display in Tab 040 }).forEachOrdered(itemModel -> tabbedTableArray.add(itemModel)); 041 042 } else { 043 Manager<E> man = getManager(); 044 String manuName = ( man!=null ? man.getMemo().getUserName() : "Unknown Manager"); 045 tabbedTableArray.add(new TabbedTableItem<>(manuName, true, getManager(), getNewTableAction(manuName))); 046 } 047 for (int x = 0; x < tabbedTableArray.size(); x++) { 048 AbstractTableAction<E> table = tabbedTableArray.get(x).getAAClass(); 049 table.addToPanel(this); 050 dataTabs.addTab(tabbedTableArray.get(x).getItemString(), tabbedTableArray.get(x).getPanel()); 051 } 052 dataTabs.addChangeListener((ChangeEvent evt) -> setMenuBar(f)); 053 init = true; 054 } 055 056 @Override 057 protected abstract Manager<E> getManager(); 058 059 protected abstract AbstractTableAction<E> getNewTableAction(String choice); 060 061 @Override 062 public JComponent getPanel() { 063 if (!init) { 064 createModel(); 065 } 066 return dataTabs; 067 } 068 069 protected ArrayList<TabbedTableItem<E>> tabbedTableArray = new ArrayList<>(); 070 071 @Override 072 protected void setTitle() { 073 //atf.setTitle("multiple sensors"); 074 } 075 076 @Override 077 protected abstract String helpTarget(); 078 079 @Override 080 protected void addPressed(ActionEvent e) { 081 log.warn("This should not have happened"); 082 } 083 084 @Override 085 public void addToFrame(BeanTableFrame<E> f) { 086 try { 087 TabbedTableItem<E> table = tabbedTableArray.get(dataTabs.getSelectedIndex()); 088 if (table != null) { 089 table.getAAClass().addToFrame(f); 090 } 091 } catch (ArrayIndexOutOfBoundsException ex) { 092 log.error("{} in add to Frame {} {}", ex.toString(), dataTabs.getSelectedIndex(), dataTabs.getSelectedComponent()); 093 } 094 } 095 096 @Override 097 public void setMenuBar(BeanTableFrame<E> f) { 098 try { 099 tabbedTableArray.get(dataTabs.getSelectedIndex()).getAAClass().setMenuBar(f); 100 } catch (ArrayIndexOutOfBoundsException ex) { 101 log.error("{} in add to Menu {} {}", ex.toString(), dataTabs.getSelectedIndex(), dataTabs.getSelectedComponent()); 102 } 103 } 104 105 public void addToBottomBox(JComponent c, String str) { 106 tabbedTableArray.forEach( table -> { 107 String item = table.getItemString(); 108 if (item != null && item.equals(str)) { 109 table.addToBottomBox(c); 110 } 111 }); 112 } 113 114 @Override 115 @SuppressWarnings("unchecked") // have to run-time cast to BeanTableDataModel<E> after check of BeanTableDataModel<?> 116 public BeanTableDataModel<E> getDataModel() { 117 var model = tabbedTableArray.get(dataTabs.getSelectedIndex()).getDataTable().getModel(); 118 if (model instanceof BeanTableDataModel<?>) { 119 return (BeanTableDataModel<E>)model; 120 } else { 121 log.warn("Did not find suitable model type, result is null"); 122 return null; 123 } 124 } 125 126 @Override 127 public void print(javax.swing.JTable.PrintMode mode, java.text.MessageFormat headerFormat, java.text.MessageFormat footerFormat) { 128 try { 129 tabbedTableArray.get(dataTabs.getSelectedIndex()).getDataTable().print(mode, headerFormat, footerFormat); 130 } catch (java.awt.print.PrinterException e1) { 131 log.warn("error printing", e1); 132 } catch (NullPointerException ex) { 133 log.error("Trying to print returned a NPE error"); 134 } 135 } 136 137 @Override 138 public void dispose() { 139 for (int x = 0; x < tabbedTableArray.size(); x++) { 140 tabbedTableArray.get(x).dispose(); 141 } 142 super.dispose(); 143 } 144 145 protected static class TabbedTableItem<E extends NamedBean> extends AbstractTableAction.TableItem<E> { // E comes from the parent 146 147 final String itemText; 148 149 final JPanel bottomBox; 150 private boolean addToFrameRan = false; 151 final Manager<E> manager; 152 153 private boolean standardModel = true; 154 155 private final JPanel tabPanel; 156 157 @SuppressWarnings("unchecked") 158 public TabbedTableItem(String choice, boolean stdModel, Manager<E> manager, @Nonnull AbstractTableAction<E> tableAction) { 159 160 super(tableAction); 161 162 itemText = choice; 163 standardModel = stdModel; 164 this.manager = manager; 165 166 //If a panel model is used, it should really add to the bottom box 167 //but it can be done this way if required. 168 tabPanel = new JPanel(); 169 tabPanel.setLayout(new BorderLayout()); 170 171 bottomBox = new JPanel(); 172 bottomBox.setLayout(new jmri.util.swing.WrapLayout(jmri.util.swing.WrapLayout.LEFT,20,5)); 173 174 if (stdModel) { 175 createDataModel(); 176 } else { 177 addPanelModel(); 178 } 179 } 180 181 @SuppressWarnings("unchecked") 182 final void createDataModel() { 183 tableAction.setManager(manager); 184 dataModel = tableAction.getTableDataModel(); 185 TableRowSorter<BeanTableDataModel<E>> sorter = new TableRowSorter<>(dataModel); 186 dataTable = dataModel.makeJTable(dataModel.getMasterClassName() + ":" + getItemString(), dataModel, sorter); 187 JScrollPane dataScroll = new JScrollPane(dataTable); 188 189 RowSorterUtil.setSortOrder(sorter, BeanTableDataModel.SYSNAMECOL, SortOrder.ASCENDING); 190 191 sorter.setComparator(BeanTableDataModel.USERNAMECOL, new AlphanumComparator()); 192 RowSorterUtil.setSortOrder(sorter, BeanTableDataModel.USERNAMECOL, SortOrder.ASCENDING); 193 194 dataModel.configureTable(dataTable); 195 tableAction.configureTable(dataTable); 196 197 java.awt.Dimension dataTableSize = dataTable.getPreferredSize(); 198 // width is right, but if table is empty, it's not high 199 // enough to reserve much space. 200 dataTableSize.height = Math.max(dataTableSize.height, 400); 201 dataScroll.getViewport().setPreferredSize(dataTableSize); 202 203 // set preferred scrolling options 204 dataScroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 205 dataScroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 206 207 tabPanel.add(dataScroll, BorderLayout.CENTER); 208 tabPanel.add(bottomBox, BorderLayout.SOUTH); 209 210 includeAddButton(tableAction.includeAddButton()); 211 212 includePropertyCheckBox(); 213 214 } 215 216 final void addPanelModel() { 217 tabPanel.add(tableAction.getPanel(), BorderLayout.CENTER); 218 tabPanel.add(bottomBox, BorderLayout.SOUTH); 219 } 220 221 public boolean getStandardTableModel() { 222 return standardModel; 223 } 224 225 public String getItemString() { 226 return itemText; 227 } 228 229 public JComponent getPanel() { 230 return tabPanel; 231 } 232 233 public boolean getAdditionsToFrameDone() { 234 return addToFrameRan; 235 } 236 237 public void setAddToFrameRan() { 238 addToFrameRan = true; 239 } 240 241 @Override 242 protected void addToBottomBox(JComponent comp) { 243 bottomBox.add(comp); 244 } 245 246 } 247 248 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractTableTabAction.class); 249 250}