001package jmri.jmrit.beantable; 002 003import java.awt.*; 004import java.awt.event.ActionEvent; 005import java.beans.PropertyChangeEvent; 006import java.lang.reflect.InvocationTargetException; 007import java.text.MessageFormat; 008import java.util.ArrayList; 009import java.util.Vector; 010 011import javax.annotation.Nonnull; 012 013import javax.swing.*; 014import javax.swing.table.TableRowSorter; 015 016import jmri.*; 017import jmri.swing.RowSorterUtil; 018import jmri.util.AlphanumComparator; 019import jmri.util.gui.GuiLafPreferencesManager; 020import jmri.util.swing.*; 021 022/** 023 * Provide access to the various tables in the tabbed Tables interface via a listed pane (normally to the left). 024 * <p> 025 * Based upon the {@link apps.gui3.tabbedpreferences.TabbedPreferences} by Bob Jacobsen 026 * 027 * @author Kevin Dickerson Copyright 2010 028 * @author Bob Jacobsen Copyright 2010 029 */ 030public class ListedTableFrame<E extends NamedBean> extends BeanTableFrame<E> { 031 032 ActionJList actionList; 033 034 public boolean isMultipleInstances() { 035 return true; 036 } 037 038 static ArrayList<TabbedTableItemListArray> tabbedTableItemListArrayArray = new ArrayList<>(); 039 ArrayList<TabbedTableItem<E>> tabbedTableArray = new ArrayList<>(); 040 041 final UserPreferencesManager pref = InstanceManager.getDefault(UserPreferencesManager.class); 042 JSplitPane cardHolder; 043 JList<String> list; 044 JScrollPane listScroller; 045 JPanel listPanel; 046 JPanel detailPanel; 047 static boolean init = false; 048 049 /** 050 * Create a new Listed Table Frame. 051 * Call initTables() before initComponents() 052 */ 053 public ListedTableFrame() { 054 this(Bundle.getMessage("TitleListedTable")); 055 } 056 057 /** 058 * Create a new Listed Table Frame. 059 * Call initTables() before initComponents() 060 * @param s Initial Frame Title 061 */ 062 public ListedTableFrame(String s) { 063 super(s); 064 if (InstanceManager.getNullableDefault(jmri.jmrit.beantable.ListedTableFrame.class) == null) { 065 // We add this to the InstanceManager so that other components can add to the table 066 InstanceManager.store(ListedTableFrame.this, jmri.jmrit.beantable.ListedTableFrame.class); 067 } 068 } 069 070 /** 071 * Initialise all tables to be added to Frame. 072 * Should be called after ListedTableFrame construction and before initComponents() 073 */ 074 public void initTables() { 075 if (!init) { 076 // Add the default tables to the static list array, 077 // this should only be done once on first loading 078 addTable("jmri.jmrit.beantable.TurnoutTableTabAction", Bundle.getMessage("MenuItemTurnoutTable"), false); 079 addTable("jmri.jmrit.beantable.SensorTableTabAction", Bundle.getMessage("MenuItemSensorTable"), false); 080 addTable("jmri.jmrit.beantable.LightTableTabAction", Bundle.getMessage("MenuItemLightTable"), false); 081 addTable("jmri.jmrit.beantable.SignalHeadTableAction", Bundle.getMessage("MenuItemSignalTable"), true); 082 addTable("jmri.jmrit.beantable.SignalMastTableAction", Bundle.getMessage("MenuItemSignalMastTable"), true); 083 addTable("jmri.jmrit.beantable.SignalGroupTableAction", Bundle.getMessage("MenuItemSignalGroupTable"), true); 084 addTable("jmri.jmrit.beantable.SignalMastLogicTableAction", Bundle.getMessage("MenuItemSignalMastLogicTable"), true); 085 addTable("jmri.jmrit.beantable.ReporterTableTabAction", Bundle.getMessage("MenuItemReporterTable"), false); 086 addTable("jmri.jmrit.beantable.MemoryTableAction", Bundle.getMessage("MenuItemMemoryTable"), true); 087 addTable("jmri.jmrit.beantable.RouteTableAction", Bundle.getMessage("MenuItemRouteTable"), true); 088 addTable("jmri.jmrit.beantable.LRouteTableAction", Bundle.getMessage("MenuItemLRouteTable"), true); 089 addTable("jmri.jmrit.beantable.LogixTableAction", Bundle.getMessage("MenuItemLogixTable"), true); 090 addTable("jmri.jmrit.beantable.LogixNGTableAction", Bundle.getMessage("MenuItemLogixNGTable"), true); 091 addTable("jmri.jmrit.beantable.LogixNGModuleTableAction", Bundle.getMessage("MenuItemLogixNGModuleTable"), true); 092 addTable("jmri.jmrit.beantable.LogixNGTableTableAction", Bundle.getMessage("MenuItemLogixNGTableTable"), true); 093 addTable("jmri.jmrit.beantable.LogixNGGlobalVariableTableAction", Bundle.getMessage("MenuItemLogixNGGlobalVariableTableAction"), true); 094 addTable("jmri.jmrit.beantable.BlockTableAction", Bundle.getMessage("MenuItemBlockTable"), true); 095 if (InstanceManager.getDefault(GuiLafPreferencesManager.class).isOblockEditTabbed()) { // select _tabbed in prefs 096 addTable("jmri.jmrit.beantable.OBlockTableAction", Bundle.getMessage("MenuItemOBlockTable"), false); 097 } // requires restart after changing the interface setting (on Display tab) 098 addTable("jmri.jmrit.beantable.SectionTableAction", Bundle.getMessage("MenuItemSectionTable"), true); 099 addTable("jmri.jmrit.beantable.TransitTableAction", Bundle.getMessage("MenuItemTransitTable"), true); 100 addTable("jmri.jmrit.beantable.AudioTableAction", Bundle.getMessage("MenuItemAudioTable"), false); 101 addTable("jmri.jmrit.beantable.IdTagTableTabAction", Bundle.getMessage("MenuItemIdTagTable"), false); 102 addTable("jmri.jmrit.beantable.RailComTableAction", Bundle.getMessage("MenuItemRailComTable"), true); 103 ListedTableFrame.setInit(true); 104 } 105 } 106 107 /** 108 * Initialise Frame Components. 109 * Should be called after initTables() 110 * {@inheritDoc} 111 */ 112 @Override 113 public void initComponents() { 114 if (tabbedTableItemListArrayArray.isEmpty()) { 115 log.error("No tables loaded: {}",this); 116 return; 117 } 118 actionList = new ActionJList(this); 119 120 detailPanel = new JPanel(); 121 detailPanel.setLayout(new CardLayout()); 122 tabbedTableArray = new ArrayList<>(tabbedTableItemListArrayArray.size()); 123 ArrayList<TabbedTableItemListArray> removeItem = new ArrayList<>(5); 124 for (TabbedTableItemListArray item : tabbedTableItemListArrayArray) { 125 // Here we add all the tables into the panel 126 try { 127 TabbedTableItem<E> itemModel = new TabbedTableItem<>( 128 item.getClassAsString(), item.getItemString(), item.getStandardTableModel()); 129 detailPanel.add(itemModel.getPanel(), itemModel.getClassAsString()); 130 tabbedTableArray.add(itemModel); 131 itemModel.getAAClass().addToFrame(this); 132 } catch (Exception ex) { 133 detailPanel.add(errorPanel(item.getItemString()), item.getClassAsString()); 134 log.error("Error when adding {} to display", item.getClassAsString(), ex); 135 removeItem.add(item); 136 } 137 } 138 139 for (TabbedTableItemListArray dead : removeItem) { 140 tabbedTableItemListArrayArray.remove(dead); 141 } 142 143 list = new JList<>(new Vector<>(getChoices())); 144 listScroller = new JScrollPane(list); 145 146 list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); 147 list.setLayoutOrientation(JList.VERTICAL); 148 list.addMouseListener(JmriMouseListener.adapt(actionList)); 149 150 listPanel = new JPanel(); 151 listPanel.setLayout(new BorderLayout(5, 0)); 152 listPanel.setLayout(new BoxLayout(listPanel, BoxLayout.Y_AXIS)); 153 listPanel.add(listScroller); 154 listPanel.setMinimumSize(new Dimension(140, 400)); // guarantees minimum width of left divider list 155 156 buildMenus(tabbedTableArray.get(0)); 157 setTitle(tabbedTableArray.get(0).getItemString()); 158 159 cardHolder = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, 160 listPanel, detailPanel); 161 162 cardHolder.setDividerSize(8); 163 if (this.getDividerLocation() != 0) { 164 cardHolder.setDividerLocation(this.getDividerLocation()); 165 } else { // if no specific size has been given we set it to the lists preferred width 166 cardHolder.setDividerLocation(listScroller.getPreferredSize().width); 167 } 168 cardHolder.addPropertyChangeListener((PropertyChangeEvent e) -> { 169 if (e.getPropertyName().equals("dividerLocation")) { 170 InstanceManager.getDefault(UserPreferencesManager.class) 171 .setProperty(ListedTableFrame.class.getName(), "dividerLocation", e.getNewValue()); 172 } 173 }); 174 175 cardHolder.setOneTouchExpandable(true); 176 getContentPane().add(cardHolder); 177 pack(); 178 actionList.selectListItem(0); 179 } 180 181 JPanel errorPanel(String text) { 182 JPanel error = new JPanel(); 183 error.add(new JLabel(Bundle.getMessage("ErrorAddingTable", text))); 184 return error; 185 } 186 187 /* Method allows for the table to go to a specific list item */ 188 public void gotoListItem(String selection) { 189 for (int x = 0; x < tabbedTableArray.size(); x++) { 190 try { 191 if (tabbedTableArray.get(x).getClassAsString().equals(selection)) { 192 actionList.selectListItem(x); 193 return; 194 } 195 } catch (Exception ex) { 196 log.error("An error occurred in the goto list for {}, {}", selection,ex.getMessage()); 197 } 198 } 199 } 200 201 public void addTable(String aaClass, String choice, boolean stdModel) { 202 TabbedTableItemListArray itemToAdd = null; 203 for (TabbedTableItemListArray ttila : tabbedTableItemListArrayArray) { 204 if (ttila.getClassAsString().equals(aaClass)) { 205 log.info("Class {} is already added", aaClass); 206 itemToAdd = ttila; 207 break; 208 } 209 } 210 if (itemToAdd == null) { 211 itemToAdd = new TabbedTableItemListArray(aaClass, choice, stdModel); 212 tabbedTableItemListArrayArray.add(itemToAdd); 213 } 214 } 215 216 @Override 217 public void dispose() { 218 pref.setSaveAllowed(false); 219 for (TabbedTableItem<E> tti : tabbedTableArray) { 220 tti.dispose(); 221 } 222 if (list != null && list.getListSelectionListeners().length > 0) { 223 list.removeListSelectionListener(list.getListSelectionListeners()[0]); 224 } 225 super.dispose(); 226 pref.setSaveAllowed(true); 227 } 228 229 void buildMenus( @Nonnull final TabbedTableItem<E> item) { 230 JMenuBar menuBar = new JMenuBar(); 231 JMenu fileMenu = new JMenu(Bundle.getMessage("MenuFile")); 232 menuBar.add(fileMenu); 233 234 JMenuItem newItem = new JMenuItem(Bundle.getMessage("MenuNewWindow")); 235 fileMenu.add(newItem); 236 newItem.addActionListener((ActionEvent e) -> actionList.openNewTableWindow(list.getSelectedIndex())); 237 238 // do not display Store All Table Content in IdTag Table 239 if (!( item.getAAClass() instanceof IdTagTableAction || 240 item.getAAClass() instanceof IdTagTableTabAction ) ) { 241 fileMenu.add(new jmri.configurexml.StoreMenu()); 242 } 243 244 JMenuItem printItem = new JMenuItem(Bundle.getMessage("PrintTable")); 245 fileMenu.add(printItem); 246 printItem.addActionListener((ActionEvent e) -> { 247 try { 248 // MessageFormat headerFormat = new MessageFormat(getTitle()); // not used below 249 MessageFormat footerFormat = new MessageFormat(getTitle() + " page {0,number}"); 250 if (item.getStandardTableModel()) { 251 item.getDataTable().print(JTable.PrintMode.FIT_WIDTH, null, footerFormat); 252 } else { 253 item.getAAClass().print(JTable.PrintMode.FIT_WIDTH, null, footerFormat); 254 } 255 } catch (java.awt.print.PrinterException e1) { 256 log.warn("Printing error", e1); 257 } catch (NullPointerException ex) { 258 log.error("Trying to print returned a NPE error"); 259 } 260 }); 261 262 JMenuItem exportItem = new JMenuItem(Bundle.getMessage("ExportTable")); 263 fileMenu.add(exportItem); 264 exportItem.addActionListener((ActionEvent e) -> { 265 if (item.getStandardTableModel()) { 266 item.getDataModel().exportToCSV(null); 267 } else { 268 // following goes through frame to avoid recreating data model 269 var model = item.getAAClass() 270 .getDataModel(); 271 model.exportToCSV(null); 272 } 273 }); 274 275 JMenu viewMenu = new JMenu(Bundle.getMessage("MenuView")); 276 menuBar.add(viewMenu); 277 for (final TabbedTableItemListArray itemList : tabbedTableItemListArrayArray) { 278 JMenuItem viewItem = new JMenuItem(itemList.getItemString()); 279 viewMenu.add(viewItem); 280 viewItem.addActionListener((ActionEvent e) -> gotoListItem(itemList.getClassAsString())); 281 } 282 283 this.setJMenuBar(menuBar); 284 try { 285 item.getAAClass().setMenuBar(this); 286 this.addHelpMenu(item.getAAClass().helpTarget(), true); 287 } catch (Exception ex) { 288 log.error("Error when trying to set menu bar for {}", item.getClassAsString(), ex); 289 } 290 this.revalidate(); 291 } 292 293 /* This is a bit of a bodge to add the contents to the bottom box and keep 294 * it backwardly compatible with the original views. When the original views 295 * are deprecated then this can be re-written 296 */ 297 //@TODO Sort out the procedure to add to bottom box 298 @Override 299 protected void addToBottomBox(Component comp, String c) { 300 for (TabbedTableItem<E> tti : tabbedTableArray) { 301 if (tti.getClassAsString().equals(c)) { 302 tti.addToBottomBox(comp); 303 return; 304 } 305 } 306 } 307 308 protected static ArrayList<String> getChoices() { 309 ArrayList<String> choices = new ArrayList<>(); 310 for (TabbedTableItemListArray ttila : tabbedTableItemListArrayArray) { 311 choices.add(ttila.getItemString()); 312 } 313 return choices; 314 } 315 316 public void setDividerLocation(int loc) { 317 if (loc == 0) { 318 return; 319 } 320 cardHolder.setDividerLocation(loc); 321 InstanceManager.getDefault(UserPreferencesManager.class) 322 .setProperty(ListedTableFrame.class.getName(), "dividerLocation", loc); 323 } 324 325 public int getDividerLocation() { 326 try { 327 return Integer.parseInt(InstanceManager.getDefault(UserPreferencesManager.class) 328 .getProperty(ListedTableFrame.class.getName(), "dividerLocation").toString()); 329 } catch (NullPointerException | NumberFormatException ex) { 330 // ignore, this means the divider location has never been saved 331 return 0; 332 } 333 } 334 335 /** 336 * Flag Table initialisation started 337 * @param newVal true when started 338 */ 339 private static synchronized void setInit(boolean newVal) { 340 init = newVal; 341 } 342 343 /** 344 * One tabbed item on the ListedTable containing the table(s) for a NamedBean class. 345 * 346 * @param <E> main class of the table(s) 347 */ 348 public static class TabbedTableItem<E extends NamedBean> { 349 350 private AbstractTableAction<E> tableAction; 351 private final String className; 352 private String itemText; 353 private BeanTableDataModel<E> dataModel; 354 private JTable dataTable; 355 private JScrollPane dataScroll; 356 private final JPanel bottomBox; 357 358 private final boolean standardModel; 359 360 final JPanel dataPanel = new JPanel(); 361 362 @SuppressWarnings("unchecked") // type ensured by reflection 363 TabbedTableItem(String aaClass, String choice, boolean stdModel) { 364 className = aaClass; 365 itemText = choice; 366 standardModel = stdModel; 367 368 bottomBox = new JPanel(); 369 bottomBox.setLayout(new WrapLayout(WrapLayout.LEFT, 20, 5)); 370 371 try { 372 Class<?> cl = Class.forName(aaClass); 373 java.lang.reflect.Constructor<?> co = cl.getConstructor(String.class); 374 tableAction = (AbstractTableAction<E>) co.newInstance(choice); // this cast is handled by reflection 375 } catch (ClassNotFoundException | InstantiationException e1) { 376 log.error("Not a valid class : {}", aaClass); 377 return; 378 } catch (NoSuchMethodException e2) { 379 log.error("Not such method : {}", aaClass); 380 return; 381 } catch (ClassCastException e4) { 382 log.error("Not part of the abstractTableActions : {}", aaClass); 383 return; 384 } catch (IllegalAccessException | IllegalArgumentException | SecurityException | InvocationTargetException e) { 385 log.error("Exception accessing {}: {}", aaClass, e.getMessage()); 386 return; 387 } 388 389 // If a panel model is used, it should really add to the bottom box 390 // but it can be done this way if required. 391 // In this case we "hijack" the TabbedTable for different (non-bean) tables to manage OBlocks. 392 dataPanel.setLayout(new BorderLayout()); 393 394 if (stdModel) { 395 createDataModel(); // first table of a grouped set with the primary manager, see OBlockTable 396 } else { 397 addPanelModel(); // for any additional table using a different manager, see Audio, OBlock 398 } 399 } 400 401 void createDataModel() { 402 dataModel = tableAction.getTableDataModel(); 403 TableRowSorter<BeanTableDataModel<E>> sorter = new TableRowSorter<>(dataModel); 404 dataTable = dataModel.makeJTable(dataModel.getMasterClassName() + ":" + getItemString(), dataModel, sorter); 405 dataScroll = new JScrollPane(dataTable); 406 407 // use NamedBean's built-in Comparator interface for sorting the system name column 408 RowSorterUtil.setSortOrder(sorter, BeanTableDataModel.SYSNAMECOL, SortOrder.ASCENDING); 409 410 sorter.setComparator(BeanTableDataModel.USERNAMECOL, new AlphanumComparator()); 411 RowSorterUtil.setSortOrder(sorter, BeanTableDataModel.USERNAMECOL, SortOrder.ASCENDING); 412 413 dataModel.configureTable(dataTable); 414 415 java.awt.Dimension dataTableSize = dataTable.getPreferredSize(); 416 // width is fine, but if table is empty, it's not high 417 // enough to reserve much space. 418 dataTableSize.height = Math.max(dataTableSize.height, 400); 419 dataScroll.getViewport().setPreferredSize(dataTableSize); 420 421 // set preferred scrolling options 422 dataScroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 423 dataScroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 424 425 dataPanel.add(dataScroll, BorderLayout.CENTER); 426 427 dataPanel.add(bottomBox, BorderLayout.SOUTH); 428 if (tableAction.includeAddButton()) { 429 JButton addButton = new JButton(Bundle.getMessage("ButtonAdd")); 430 addToBottomBox(addButton); 431 addButton.addActionListener((ActionEvent e) -> tableAction.addPressed(e)); 432 } 433 if (dataModel.getPropertyColumnCount() > 0) { 434 final JCheckBox propertyVisible = new JCheckBox(Bundle.getMessage 435 ("ShowSystemSpecificProperties")); 436 propertyVisible.setToolTipText(Bundle.getMessage 437 ("ShowSystemSpecificPropertiesToolTip")); 438 addToBottomBox(propertyVisible); 439 propertyVisible.addActionListener((ActionEvent e) -> 440 dataModel.setPropertyColumnsVisible(dataTable, propertyVisible.isSelected())); 441 dataModel.setPropertyColumnsVisible(dataTable, false); 442 } 443 tableAction.addToFrame(this); 444 dataModel.persistTable(dataTable); 445 } 446 447 void addPanelModel() { 448 try { 449 dataPanel.add(tableAction.getPanel(), BorderLayout.CENTER); 450 if ( bottomBox.getComponentCount()>0 ) { 451 dataPanel.add(bottomBox, BorderLayout.SOUTH); 452 } 453 } catch (NullPointerException e) { 454 log.error("An error occurred while trying to create the table for {}", itemText, e); 455 } 456 } 457 458 boolean getStandardTableModel() { 459 return standardModel; 460 } 461 462 String getClassAsString() { 463 return className; 464 } 465 466 String getItemString() { 467 return itemText; 468 } 469 470 AbstractTableAction<E> getAAClass() { 471 return tableAction; 472 } 473 474 JPanel getPanel() { 475 return dataPanel; 476 } 477 478 JTable getDataTable() { 479 return dataTable; 480 } 481 482 BeanTableDataModel<E> getDataModel() { 483 return dataModel; 484 } 485 486 public void addToBottomBox(Component comp) { 487 bottomBox.add(comp); 488 } 489 490 void dispose() { 491 if (dataModel != null) { 492 dataModel.stopPersistingTable(dataTable); 493 dataModel.dispose(); 494 } 495 if (tableAction != null) { 496 tableAction.dispose(); 497 } 498 dataModel = null; 499 dataTable = null; 500 dataScroll = null; 501 } 502 } 503 504 private static class TabbedTableItemListArray { 505 506 String className; 507 String itemText; 508 boolean standardModel; 509 510 TabbedTableItemListArray(String aaClass, String choice, boolean stdModel) { 511 className = aaClass; 512 itemText = choice; 513 standardModel = stdModel; 514 } 515 516 boolean getStandardTableModel() { 517 return standardModel; 518 } 519 520 String getClassAsString() { 521 return className; 522 } 523 524 String getItemString() { 525 return itemText; 526 } 527 528 } 529 530 /** 531 * ActionJList This deals with handling non-default mouse operations on the 532 * List panel and allows for right click popups and double click to open new 533 * windows of the items we are hovering over. 534 */ 535 private class ActionJList extends JmriMouseAdapter { 536 537 JPopupMenu popUp; 538 JMenuItem menuItem; 539 540 protected BeanTableFrame<E> frame; 541 542 ActionJList(BeanTableFrame<E> f) { 543 frame = f; 544 popUp = new JPopupMenu(); 545 menuItem = new JMenuItem(Bundle.getMessage("MenuOpenInNewWindow")); 546 popUp.add(menuItem); 547 menuItem.addActionListener((ActionEvent e) -> openNewTableWindow(mouseItem)); 548 currentItemSelected = 0; 549 } 550 551 private int currentItemSelected; 552 553 @Override 554 public void mousePressed(JmriMouseEvent e) { 555 if (e.isPopupTrigger()) { 556 showPopup(e); 557 } 558 } 559 560 @Override 561 public void mouseReleased(JmriMouseEvent e) { 562 if (e.isPopupTrigger()) { 563 showPopup(e); 564 } 565 } 566 567 // records the original pre-click index 568 private int beforeClickIndex; 569 570 //Records the item index that the mouse is currently over 571 private int mouseItem; 572 573 void showPopup(JmriMouseEvent e) { 574 popUp.show(e.getComponent(), e.getX(), e.getY()); 575 mouseItem = list.locationToIndex(e.getPoint()); 576 } 577 578 @Override 579 public void mouseClicked(JmriMouseEvent e) { 580 581 mouseItem = list.locationToIndex(e.getPoint()); 582 if (popUp.isVisible()) { 583 return; 584 } 585 if (e.isPopupTrigger()) { 586 showPopup(e); 587 return; 588 } 589 if (e.getClickCount() == 1) { 590 beforeClickIndex = currentItemSelected; 591 selectListItem(mouseItem); 592 } else if (e.getClickCount() == 2) { 593 list.setSelectedIndex(beforeClickIndex); 594 selectListItem(beforeClickIndex); 595 openNewTableWindow(mouseItem); 596 } 597 } 598 599 void openNewTableWindow(int index) { 600 TabbedTableItem<E> item = tabbedTableArray.get(index); 601 class WindowMaker implements Runnable { 602 603 final TabbedTableItem<E> item; 604 605 WindowMaker(TabbedTableItem<E> tItem) { 606 item = tItem; 607 } 608 609 @Override 610 public void run() { 611 ListedTableAction tmp = new ListedTableAction( 612 item.getItemString(), item.getClassAsString(), cardHolder.getDividerLocation()); 613 tmp.actionPerformed(); 614 } 615 } 616 WindowMaker t = new WindowMaker(item); 617 SwingUtilities.invokeLater(t); 618 } 619 620 void selectListItem(int index) { 621 currentItemSelected = index; 622 TabbedTableItem<E> item = tabbedTableArray.get(index); 623 CardLayout cl = (CardLayout) (detailPanel.getLayout()); 624 cl.show(detailPanel, item.getClassAsString()); 625 frame.setTitle(item.getItemString()); 626 frame.generateWindowRef(); 627 try { 628 item.getAAClass().setFrame(frame); 629 buildMenus(item); 630 } catch (Exception ex) { 631 log.error("Could not build table {}", item, ex); 632 } 633 list.ensureIndexIsVisible(index); 634 list.setSelectedIndex(index); 635 } 636 } 637 638 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ListedTableFrame.class); 639 640}