001package jmri.jmrit.beantable.oblock; 002 003import java.awt.*; 004import java.awt.event.*; 005import java.beans.PropertyVetoException; 006import java.text.MessageFormat; 007import java.util.HashMap; 008import java.util.List; 009import java.util.SortedSet; 010import javax.annotation.CheckForNull; 011import javax.annotation.Nonnull; 012import javax.swing.*; 013import javax.swing.event.InternalFrameEvent; 014import javax.swing.event.InternalFrameListener; 015import javax.swing.table.AbstractTableModel; 016import javax.swing.table.TableColumn; 017import javax.swing.table.TableRowSorter; 018 019import jmri.*; 020import jmri.jmrit.logix.OBlock; 021import jmri.jmrit.logix.OBlockManager; 022import jmri.jmrit.logix.OPath; 023import jmri.jmrit.logix.Portal; 024import jmri.jmrit.logix.PortalManager; 025import jmri.jmrit.logix.WarrantTableAction; 026import jmri.swing.NamedBeanComboBox; 027import jmri.util.JmriJFrame; 028import jmri.util.SystemType; 029import jmri.util.com.sun.TransferActionListener; 030import jmri.util.gui.GuiLafPreferencesManager; 031import jmri.util.swing.XTableColumnModel; 032import jmri.util.swing.JmriJOptionPane; 033import jmri.util.table.ButtonEditor; 034import jmri.util.table.ButtonRenderer; 035import jmri.util.table.ToggleButtonEditor; 036import jmri.util.table.ToggleButtonRenderer; 037 038/** 039 * GUI to define OBlocks. 040 * <p> 041 * Core code can be used with two interfaces: 042 * <ul> 043 * <li>original "desktop" InternalFrames (displays as InternalJFrames inside a JmriJFrame) 044 * <li>JMRI standard Tabbed tables (displays as Js inside a ListedTableFrame) 045 * </ul> 046 * The _tabbed field decides, it is set in prefs (restart required). TableFrames itself has no UI. 047 * <hr> 048 * This file is part of JMRI. 049 * <p> 050 * JMRI is free software; you can redistribute it and/or modify it under the 051 * terms of version 2 of the GNU General Public License as published by the Free 052 * Software Foundation. See the "COPYING" file for a copy of this license. 053 * <p> 054 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 055 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 056 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 057 * 058 * @author Pete Cressman (C) 2010 059 * @author Egbert Broerse (C) 2019 060 * @author Egbert Broerse (C) 2020 061 */ 062public class TableFrames implements InternalFrameListener { 063 064 public static final int ROW_HEIGHT = (new JButton("X").getPreferredSize().height)*9/10; 065 public static final int STRUT_SIZE = 10; 066 protected static final String SET_CLOSED = jmri.InstanceManager.turnoutManagerInstance().getClosedText(); 067 protected static final String SET_THROWN = jmri.InstanceManager.turnoutManagerInstance().getThrownText(); 068 private static String oblockPrefix; 069 private final static String portalPrefix = "IP"; 070 private String _title; 071 072 private JTable _oBlockTable; 073 private final OBlockTableModel _oBlockModel; 074 private JTable _portalTable; 075 private final PortalTableModel _portalModel; 076 private JTable _blockPortalTable; 077 private final BlockPortalTableModel _blockPortalXRefModel; 078 private JTable _signalTable; 079 private final SignalTableModel _signalModel; 080 081 private final boolean _tabbed; // updated from prefs (restart required) 082 private boolean pathEdit = false; 083 084 private JmriJFrame desktopframe; 085 private JDesktopPane _desktop; 086 private final int maxHeight = 600; 087 private JInternalFrame _blockTableFrame; 088 private JInternalFrame _portalTableFrame; 089 private JInternalFrame _blockPortalXRefFrame; 090 private JInternalFrame _signalTableFrame; 091 092 private boolean _showWarnings = true; 093 private JMenuItem _showWarnItem; 094 private JMenu tablesMenu; 095 private JMenuItem openBlock; 096 private JMenuItem openPortal; 097 private JMenuItem openXRef; 098 private JMenuItem openSignal; 099 private JMenuItem _setUnits; 100 101 private final HashMap<String, BlockPathFrame> _blockPathMap = new HashMap<>(); 102 private final HashMap<String, PathTurnoutFrame> _pathTurnoutMap = new HashMap<>(); 103 // _tabbed edit panes are not stored in a map 104 105 public TableFrames() { 106 this("OBlock Tables"); 107 } // NOI18N, title will be updated during init 108 109 public TableFrames(String actionName) { 110 _tabbed = InstanceManager.getDefault(GuiLafPreferencesManager.class).isOblockEditTabbed(); 111 _title = actionName; 112 if (!_tabbed) { 113 desktopframe = new JmriJFrame(actionName); 114 } 115 // create the tables 116 _oBlockModel = new OBlockTableModel(this); 117 _portalModel = new PortalTableModel(this); 118 _blockPortalXRefModel = new BlockPortalTableModel(_oBlockModel); 119 _signalModel = new SignalTableModel(this); 120 _signalModel.init(); 121 } 122 123 public OBlockTableModel getOblockTableModel() { 124 return _oBlockModel; 125 } 126 public PortalTableModel getPortalTableModel() { 127 return _portalModel; 128 } 129 public BlockPortalTableModel getPortalXRefTableModel() { 130 return _blockPortalXRefModel; 131 } 132 public BlockPathTableModel getBlockPathTableModel(OBlock block) { 133 return new BlockPathTableModel(block, this); 134 } 135 public SignalTableModel getSignalTableModel() { 136 return _signalModel; 137 } 138 139 public void initComponents() { 140 // build and display the classic floating "OBlock and its..." desktop interface 141 if (!_tabbed) { // just to be sure 142 setTitle(Bundle.getMessage("TitleOBlocks")); 143 144 // build tables 145 _blockTableFrame = buildFrame(_oBlockModel, Bundle.getMessage("TitleBlockTable"), Bundle.getMessage("AddBlockPrompt")); 146 _blockTableFrame.setVisible(true); 147 148 _portalTableFrame = buildFrame(_portalModel, Bundle.getMessage("TitlePortalTable"), Bundle.getMessage("AddPortalPrompt")); 149 _portalTableFrame.setVisible(true); 150 151 _signalTableFrame = buildFrame(_signalModel, Bundle.getMessage("TitleSignalTable"), Bundle.getMessage("AddSignalPrompt")); 152 _signalTableFrame.setVisible(false); 153 154 _blockPortalXRefFrame = buildFrame(_blockPortalXRefModel, Bundle.getMessage("TitleBlockPortalXRef"), Bundle.getMessage("XRefPrompt")); 155 _blockPortalXRefFrame.setVisible(false); // start with frame hidden 156 157 // build the print menu after the tables have been created 158 desktopframe.setTitle(getTitle()); 159 desktopframe.setJMenuBar(addMenus(desktopframe.getJMenuBar())); 160 desktopframe.addHelpMenu("package.jmri.jmrit.logix.OBlockTable", true); 161 162 createDesktop(); // adds tables as windows on desktopframe._desktop 163 desktopframe.setLocation(10, 30); 164 desktopframe.setVisible(true); 165 desktopframe.pack(); 166 addCloseListener(desktopframe); 167 168 // finally check table contents for errors 169 WarrantTableAction.getDefault().errorCheck(); 170 } 171 } 172 173 public JMenuBar addMenus(JMenuBar mBar) { 174 if (mBar == null) { 175 mBar = new JMenuBar(); 176 } 177 // create and add the menus 178 if (!_tabbed) { // _tabbed Print is handled via getPrintItem() in OBlockTablePanel 179 // File menu 180 JMenu fileMenu = new JMenu(Bundle.getMessage("MenuFile")); 181 fileMenu.add(new jmri.configurexml.StoreMenu()); 182 fileMenu.add(getPrintMenuItems(_oBlockTable, _portalTable, _signalTable, _blockPortalTable)); // add the print items 183 mBar.add(fileMenu); 184 185 // Edit menu 186 JMenu editMenu = new JMenu(Bundle.getMessage("MenuEdit")); 187 editMenu.setMnemonic(KeyEvent.VK_E); 188 TransferActionListener actionListener = new TransferActionListener(); 189 190 JMenuItem menuItem = new JMenuItem(Bundle.getMessage("MenuItemCut")); 191 menuItem.setActionCommand((String) TransferHandler.getCutAction().getValue(Action.NAME)); 192 menuItem.addActionListener(actionListener); 193 if (SystemType.isMacOSX()) { 194 menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.META_DOWN_MASK)); 195 } else { 196 menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK)); 197 } 198 menuItem.setMnemonic(KeyEvent.VK_T); 199 editMenu.add(menuItem); 200 201 menuItem = new JMenuItem(Bundle.getMessage("MenuItemCopy")); 202 menuItem.setActionCommand((String) TransferHandler.getCopyAction().getValue(Action.NAME)); 203 menuItem.addActionListener(actionListener); 204 if (SystemType.isMacOSX()) { 205 menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.META_DOWN_MASK)); 206 } else { 207 menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK)); 208 } 209 menuItem.setMnemonic(KeyEvent.VK_C); 210 editMenu.add(menuItem); 211 212 menuItem = new JMenuItem(Bundle.getMessage("MenuItemPaste")); 213 menuItem.setActionCommand((String) TransferHandler.getPasteAction().getValue(Action.NAME)); 214 menuItem.addActionListener(actionListener); 215 if (SystemType.isMacOSX()) { 216 menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.META_DOWN_MASK)); 217 } else { 218 menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK)); 219 } 220 menuItem.setMnemonic(KeyEvent.VK_P); 221 editMenu.add(menuItem); 222 mBar.add(editMenu); 223 } 224 225 mBar.add(getOptionMenu()); 226 mBar.add(getTablesMenu()); 227 return mBar; 228 } 229 230 public JMenu getPrintMenuItems(JTable oBlockTable, JTable portalTable, JTable signalTable, JTable blockPortalTable) { 231 JMenu print = new JMenu(Bundle.getMessage("PrintTable")); 232 JMenuItem printItem = new JMenuItem(Bundle.getMessage("PrintOBlockTable")); 233 print.add(printItem); 234 printItem.addActionListener(e -> { 235 try { 236 MessageFormat headerFormat = new MessageFormat(Bundle.getMessage("TitleOBlockTable")); 237 MessageFormat footerFormat = new MessageFormat(getTitle() + " page {0,number}"); 238 oBlockTable.print(JTable.PrintMode.FIT_WIDTH, headerFormat, footerFormat); 239 } catch (java.awt.print.PrinterException e1) { 240 log.warn("error printing: {}", e1, e1); 241 } 242 }); 243 printItem = new JMenuItem(Bundle.getMessage("PrintPortalTable")); 244 print.add(printItem); 245 printItem.addActionListener(e -> { 246 try { 247 MessageFormat headerFormat = new MessageFormat(Bundle.getMessage("TitlePortalTable")); 248 MessageFormat footerFormat = new MessageFormat(getTitle() + " page {0,number}"); 249 portalTable.print(JTable.PrintMode.FIT_WIDTH, headerFormat, footerFormat); 250 } catch (java.awt.print.PrinterException e1) { 251 log.warn("error printing: {}", e1, e1); 252 } 253 }); 254 printItem = new JMenuItem(Bundle.getMessage("PrintSignalTable")); 255 print.add(printItem); 256 printItem.addActionListener(e -> { 257 try { 258 MessageFormat headerFormat = new MessageFormat(Bundle.getMessage("TitleSignalTable")); 259 MessageFormat footerFormat = new MessageFormat(getTitle() + " page {0,number}"); 260 signalTable.print(JTable.PrintMode.FIT_WIDTH, headerFormat, footerFormat); 261 } catch (java.awt.print.PrinterException e1) { 262 log.warn("error printing: {}", e1, e1); 263 } 264 }); 265 printItem = new JMenuItem(Bundle.getMessage("PrintXRef")); 266 print.add(printItem); 267 printItem.addActionListener(e -> { 268 try { 269 MessageFormat headerFormat = new MessageFormat(Bundle.getMessage("OpenXRefMenu", "")); 270 MessageFormat footerFormat = new MessageFormat(getTitle() + " page {0,number}"); 271 blockPortalTable.print(JTable.PrintMode.FIT_WIDTH, headerFormat, footerFormat); 272 } catch (java.awt.print.PrinterException e1) { 273 log.warn("error printing: {}", e1, e1); 274 } 275 }); 276 return print; 277 } 278 279 // for desktop style interface, ignored for _tabbed 280 private void createDesktop() { 281 _desktop = new JDesktopPane(); 282 _desktop.putClientProperty("JDesktopPane.dragMode", "outline"); // slower or faster? 283 int deskWidth = _blockTableFrame.getWidth(); 284 int deskHeight = _blockTableFrame.getHeight(); 285// _desktop.setPreferredSize(new Dimension(deskWidth, 286// deskHeight + _portalTableFrame.getHeight() + 100)); 287 _desktop.setBackground(new Color(180,180,180)); 288 desktopframe.setContentPane(_desktop); 289 desktopframe.setPreferredSize(new Dimension(deskWidth + 16, 290 deskHeight + _portalTableFrame.getHeight() + 64)); 291 292 // placed at 0,0 293 _desktop.add(_blockTableFrame); 294 _portalTableFrame.setLocation(0, deskHeight); 295 _desktop.add(_portalTableFrame); 296 _signalTableFrame.setLocation(200, deskHeight+100); 297 _desktop.add(_signalTableFrame); 298 _blockPortalXRefFrame.setLocation(deskWidth - _blockPortalXRefFrame.getWidth(), deskHeight); 299 _desktop.add(_blockPortalXRefFrame); 300 } 301 302 public JMenu getOptionMenu() { 303 // Options menu 304 JMenu optionMenu = new JMenu(Bundle.getMessage("MenuOptions")); 305 _showWarnItem = new JMenuItem(Bundle.getMessage("SuppressWarning")); 306 _showWarnItem.addActionListener(event -> { 307 String cmd = event.getActionCommand(); 308 setShowWarnings(cmd); 309 }); 310 optionMenu.add(_showWarnItem); 311 setShowWarnings("ShowWarning"); 312 313 JMenuItem importBlocksItem = new JMenuItem(Bundle.getMessage("ImportBlocksMenu")); 314 importBlocksItem.addActionListener((ActionEvent event) -> importBlocks()); 315 optionMenu.add(importBlocksItem); 316 // disable ourself if there is no primary Block manager available 317 if (jmri.InstanceManager.getNullableDefault(jmri.BlockManager.class) == null) { // means Block list is empty 318 importBlocksItem.setEnabled(false); 319 } 320 _setUnits = new JMenuItem(Bundle.getMessage("changeUnits", 321 (_oBlockModel.isMetric() ? Bundle.getMessage("LengthInches") : Bundle.getMessage("LengthCentimeters")))); 322 _setUnits.addActionListener(event -> setUnits()); 323 optionMenu.add(_setUnits); 324 return optionMenu; 325 } 326 327 public JMenu getTablesMenu() { 328 // Tables menu 329 tablesMenu = new JMenu(Bundle.getMessage("OpenMenu")); 330 updateOBlockTablesMenu(); // replaces the last 2 menu items with appropriate submenus 331 return tablesMenu; 332 } 333 334 private String oblockPrefix() { 335 if (oblockPrefix == null) { 336 oblockPrefix = InstanceManager.getDefault(OBlockManager.class).getSystemNamePrefix(); 337 } 338 return oblockPrefix; 339 } 340 341 /** 342 * Get the JFrame containig all UI windows. 343 * 344 * @return the contentframe 345 */ 346 protected JmriJFrame getDesktopFrame() { 347 return desktopframe; 348 } 349 350 /** 351 * Convert a copy of your current JMRI Blocks to OBlocks and connect them with Portals and Paths. 352 * Accessed from the Options menu. 353 * @throws IllegalArgumentException exception 354 */ 355 protected void importBlocks() throws IllegalArgumentException { 356 Manager<Block> bm = InstanceManager.getDefault(jmri.BlockManager.class); 357 OBlockManager obm = InstanceManager.getDefault(OBlockManager.class); 358 PortalManager pom = InstanceManager.getDefault(PortalManager.class); 359 SortedSet<Block> blkList = bm.getNamedBeanSet(); 360 // don't return an element if there are no Blocks to include 361 if (blkList.isEmpty()) { 362 log.warn("no Blocks to convert"); // NOI18N 363 JmriJOptionPane.showMessageDialog(desktopframe, Bundle.getMessage("ImportNoBlocks"), 364 Bundle.getMessage("InfoTitle"), JmriJOptionPane.INFORMATION_MESSAGE); 365 return; 366 } else { 367 if (_showWarnings) { 368 int reply = JmriJOptionPane.showOptionDialog(null, 369 Bundle.getMessage("ImportBlockConfirm", oblockPrefix(), blkList.size()), 370 Bundle.getMessage("QuestionTitle"), 371 JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.QUESTION_MESSAGE, null, 372 new Object[]{Bundle.getMessage("ButtonYes"), 373 Bundle.getMessage("ButtonCancel")}, 374 Bundle.getMessage("ButtonYes")); // standard JOptionPane can't be found in Jemmy log4J 375 if (reply > 0) { 376 return; 377 } 378 } 379 } 380 for (Block b : blkList) { 381 try { 382 // read Block properties 383 String sName = b.getSystemName(); 384 String uName = b.getUserName(); 385 String blockNumber = sName.substring(sName.startsWith("IB:AUTO:") ? 8 : 3); 386 String oBlockName = oblockPrefix() + blockNumber; 387 String sensor = ""; 388 Sensor s = b.getSensor(); 389 if (s != null) { 390 sensor = s.getDisplayName(); 391 } 392 float length = b.getLengthMm(); // length is stored in Mm in OBlock.setLength(float) 393 int curve = b.getCurvature(); 394 List<Path> blockPaths = b.getPaths(); 395 String toBlockName; 396 Portal port = null; 397 int n = 0; 398 Portal prevPortal = null; 399 400 log.debug("start creating OBlock {} from Block {}", oBlockName, sName); 401 if ((uName != null) && (obm.getOBlock(uName) != null)) { 402 log.warn("an OBlock with this user name already exists, replacing {}", uName); 403 } 404 // create the OBlock by systemName 405 OBlock oBlock = obm.provideOBlock(oBlockName); 406 oBlock.setUserName(uName); 407 if (!sensor.isEmpty()) { 408 oBlock.setSensor(sensor); 409 } 410 oBlock.setMetricUnits(true); // length always stored in Mm in Block, so copy that for OBlock 411 oBlock.setLength(length); 412 oBlock.setCurvature(curve); 413 414 for (Path pa : blockPaths) { 415 log.debug("Start loop: Path {} on Block {}", n, oBlockName); 416 String toBlockNumber = pa.getBlock().getSystemName().substring(sName.startsWith("IB:AUTO:") ? 8 : 3); 417 toBlockName = oblockPrefix() + toBlockNumber; 418 String portalName = portalPrefix + toBlockNumber + "-" + blockNumber; // reversed name for new Portal 419 port = pom.getPortal(portalName); 420 if (port == null) { 421 portalName = portalPrefix + blockNumber + "-" + toBlockNumber; // normal name for new Portal 422 log.debug("new Portal {} on block {}, path #{}", portalName, toBlockName, n); 423 port = pom.providePortal(portalName); // normally, will create a new Portal 424 port.setFromBlock(oBlock, false); 425 port.setToBlock(obm.provideOBlock(toBlockName), false); // create one if required 426 } else { 427 log.debug("duplicate Portal {} on block {}, path #{}", portalName, toBlockName, n); 428 // Portal port already set 429 } 430 oBlock.addPortal(port); 431 432 // create OPath from this Path 433 OPath opa = new OPath(oBlock, "IP" + n++); // only needs to be unique within oBlock 434 opa.setLength(oBlock.getLengthMm()); // simple assumption, works for default OBlock/OPath 435 log.debug("new OPath #{} - {} on OBlock {}", n, opa.getName(), opa.getBlock().getDisplayName()); 436 oBlock.addPath(opa); // checks for duplicates, will add OPath to any Portals on oBlock as well 437 log.debug("number of paths: {}", oBlock.getPaths().size()); 438 439 // set _fromPortal and _toPortal for each OPath in OBlock 440 if (opa.getFromPortal() == null) { 441 opa.setFromPortal(port); 442 } 443 for (BeanSetting bs : pa.getSettings()) { 444 opa.addSetting(bs); 445 } 446 if ((opa.getToPortal() == null) && (prevPortal != null)) { 447 opa.setToPortal(prevPortal); 448 // leaves ToPortal in previously (first) created OPath n-1 empty 449 } 450 prevPortal = port; // remember the new portal for use as ToPortal in opposing OPath 451 // user must remove nonsense manually unless... 452 } 453 // we use the last FromPortal as ToPortal in OPath P0 454 OPath p0 = oBlock.getPathByName("IP0"); 455 if ((p0 != null) && (n > 1) && (p0.getToPortal() == null)) { 456 p0.setToPortal(port); 457 } 458 } catch (IllegalArgumentException iae) { 459 log.error("Could not convert Block {} to OBlock. {}", 460 b.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME), iae.getMessage()); 461 } 462 // finished setting up 1 OBlock 463 } 464 // add recursive Path elements to FromBlock/ToBlock 465 SortedSet<OBlock> oblkList = obm.getNamedBeanSet(); 466 for (OBlock oblk : oblkList) { 467 for (Portal po : oblk.getPortals()) { 468 OBlock oob = obm.getByUserName(po.getFromBlockName()); 469 if (oob !=null) { 470 oob.addPortal(po); 471 } 472 oob = obm.getByUserName(po.getToBlockName()); 473 if (oob !=null) { 474 oob.addPortal(po); 475 } 476 } 477 } 478 // storing and reloading will add in these items 479 WarrantTableAction.getDefault().errorCheck(); 480 if (_showWarnings) { 481 JmriJOptionPane.showMessageDialog(null, 482 Bundle.getMessage("ImportBlockComplete", blkList.size(), oblkList.size()), 483 Bundle.getMessage("MessageTitle"), 484 JmriJOptionPane.INFORMATION_MESSAGE); // standard JOptionPane can't be found in Jemmy log4J 485 } 486 } 487 // End of importBlocks() menu method 488 489 protected void setShowWarnings(String cmd) { 490 if (cmd.equals("ShowWarning")) { 491 _showWarnings = true; 492 _showWarnItem.setActionCommand("SuppressWarning"); 493 _showWarnItem.setText(Bundle.getMessage("SuppressWarning")); 494 } else { 495 _showWarnings = false; 496 _showWarnItem.setActionCommand("ShowWarning"); 497 _showWarnItem.setText(Bundle.getMessage("ShowWarning")); 498 } 499 log.debug("setShowWarnings: _showWarnings= {}", _showWarnings); 500 } 501 502 private void setUnits() { 503 _oBlockModel.changeUnits(); 504 _setUnits.setText(Bundle.getMessage("changeUnits", 505 (_oBlockModel.isMetric() ? Bundle.getMessage("LengthInches") : Bundle.getMessage("LengthCentimeters")))); 506 } 507 508 // listen for _desktopframe closing 509 void addCloseListener(JmriJFrame desktop) { 510 desktop.addWindowListener(new java.awt.event.WindowAdapter() { 511 @Override 512 public void windowClosing(java.awt.event.WindowEvent e) { 513 WarrantTableAction.getDefault().errorCheck(); 514 desktop.setDefaultCloseOperation(javax.swing.WindowConstants.HIDE_ON_CLOSE); 515 // closing instead of hiding removes name from Windows menu.handle menu to read Show... 516 log.debug("windowClosing: {}", toString()); 517 desktop.dispose(); 518 } 519 }); 520 } 521 522 private String getTitle() { 523 return _title; 524 } 525 526 private void setTitle(String title) { 527 _title = title; 528 } 529 530 /** 531 * Fill in the Open/Hide Tables menu on tablesMenu. 532 */ 533 protected void updateOBlockTablesMenu() { 534 if (tablesMenu == null) { 535 return; 536 } 537 tablesMenu.removeAll(); 538 if (!_tabbed) { // full menu in _desktop, open/show not available in _tabbed interface 539 // use string Bundle.getMessage("HideTable") to correct action in menu for all table open at start 540 openBlock = new JMenuItem(Bundle.getMessage("OpenBlockMenu", Bundle.getMessage("HideTable"))); 541 tablesMenu.add(openBlock); 542 openBlock.addActionListener(event -> showHideFrame(_blockTableFrame, openBlock, "OpenBlockMenu")); 543 544 openPortal = new JMenuItem(Bundle.getMessage("OpenPortalMenu", Bundle.getMessage("HideTable"))); 545 tablesMenu.add(openPortal); 546 openPortal.addActionListener(event -> showHideFrame(_portalTableFrame, openPortal, "OpenPortalMenu")); 547 548 openXRef = new JMenuItem(Bundle.getMessage("OpenXRefMenu", Bundle.getMessage("ShowTable"))); 549 tablesMenu.add(openXRef); 550 openXRef.addActionListener(event -> showHideFrame(_blockPortalXRefFrame, openXRef, "OpenXRefMenu")); 551 552 openSignal = new JMenuItem(Bundle.getMessage("OpenSignalMenu", Bundle.getMessage("ShowTable"))); 553 tablesMenu.add(openSignal); 554 openSignal.addActionListener(event -> showHideFrame(_signalTableFrame, openSignal, "OpenSignalMenu")); 555 } 556 557 OBlockManager manager = InstanceManager.getDefault(OBlockManager.class); 558 559 // Block-Path submenus 560 JMenu openBlockPath = new JMenu(Bundle.getMessage("OpenBlockPathMenu")); 561 ActionListener openFrameAction = e -> { 562 String blockSystemName = e.getActionCommand(); 563 openBlockPathPane(blockSystemName, Bundle.getMessage("TitlePaths")); // handles both interfaces 564 }; 565 566 if (manager.getNamedBeanSet().size() == 0) { 567 JMenuItem mi = new JMenuItem(Bundle.getMessage("NoBlockPathYet")); 568 mi.setEnabled(false); 569 openBlockPath.add(mi); 570 } else { 571 for (OBlock block : manager.getNamedBeanSet()) { 572 JMenuItem mi = new JMenuItem(Bundle.getMessage("OpenPathMenu", block.getDisplayName())); 573 mi.setActionCommand(block.getSystemName()); 574 mi.addActionListener(openFrameAction); 575 openBlockPath.add(mi); 576 } 577 } 578 tablesMenu.add(openBlockPath); 579 580 // Path-Turnout submenus 581 JMenu openTurnoutPath = new JMenu(Bundle.getMessage("OpenBlockPathTurnoutMenu")); 582 if (manager.getNamedBeanSet().size() == 0) { 583 JMenuItem mi = new JMenuItem(Bundle.getMessage("NoPathTurnoutYet")); 584 mi.setEnabled(false); 585 openTurnoutPath.add(mi); 586 } else { 587 for (OBlock block : manager.getNamedBeanSet()) { 588 JMenu openTurnoutMenu = new JMenu(Bundle.getMessage("OpenTurnoutMenu", block.getDisplayName())); 589 openTurnoutPath.add(openTurnoutMenu); 590 openFrameAction = e -> { 591 String pathTurnoutName = e.getActionCommand(); 592 openPathTurnoutEditPane(pathTurnoutName); // handles both interfaces 593 }; 594 for (Path p : block.getPaths()) { 595 if (p instanceof OPath) { 596 OPath path = (OPath) p; 597 JMenuItem mi = new JMenuItem(Bundle.getMessage("OpenPathTurnoutMenu", path.getName())); 598 mi.setActionCommand(makePathTurnoutName(block.getSystemName(), path.getName())); 599 mi.addActionListener(openFrameAction); 600 openTurnoutMenu.add(mi); 601 } 602 } 603 } 604 } 605 tablesMenu.add(openTurnoutPath); 606 } 607 608 public void openPathTurnoutEditPane(String pathTurnoutName) { 609 if (_tabbed) { 610 log.debug("openPathTurnoutEditPane for {}", pathTurnoutName); 611 openPathTurnoutEditor(pathTurnoutName); 612 } else { // stand alone frame only used for _desktop, created from/stored in Portal 613 openPathTurnoutFrame(pathTurnoutName); 614 } 615 } 616 617 /** 618 * Show or hide a table in the _desktop interface. 619 * 620 * @param frame JInternalFrame to show (or hide, name property value contains {} var handled by frame) 621 * @param menu menu item object 622 * @param menuName base i18n string containing table name 623 */ 624 private void showHideFrame(JInternalFrame frame, JMenuItem menu, String menuName) { 625 if (!frame.isVisible()) { 626 frame.setVisible(true); 627 try { 628 frame.setIcon(false); 629 } catch (PropertyVetoException pve) { 630 log.warn("{} Frame vetoed setIcon {}", frame.getTitle(), pve.toString()); 631 } 632 frame.moveToFront(); 633 } else { 634 frame.setVisible(false); 635 } 636 menu.setText(Bundle.getMessage(menuName, 637 (frame.isVisible() ? Bundle.getMessage("HideTable") : Bundle.getMessage("ShowTable")))); 638 } 639 640 /** 641 * Wrapper for shared code around each Table in a JInternal window on _desktop interface. 642 * 643 * @param tableModel underlying model for the table 644 * @param title text displayed as title of frame 645 * @param prompt text below bottom line 646 * @return iframe to put on _desktop interface 647 */ 648 protected JInternalFrame buildFrame(AbstractTableModel tableModel, String title, String prompt) { 649 JInternalFrame iframe = new JInternalFrame(title, true, false, false, true); 650 651 // specifics for table 652 JTable table = new JTable(); 653 if (tableModel instanceof OBlockTableModel) { 654 table = makeOBlockTable((OBlockTableModel) tableModel); 655 } else if (tableModel instanceof PortalTableModel) { 656 table = makePortalTable((PortalTableModel) tableModel); 657 } else if (tableModel instanceof BlockPortalTableModel) { 658 table = makeBlockPortalTable((BlockPortalTableModel) tableModel); 659 } else if (tableModel instanceof SignalTableModel) { 660 table = makeSignalTable((SignalTableModel) tableModel); 661 } // no case here for BlockPathTableModel, it is handled directly from OBlockTable 662 663 JScrollPane scroll = new JScrollPane(table); 664 JPanel contentPane = new JPanel(); 665 contentPane.setLayout(new BorderLayout(5, 5)); 666 JLabel _prompt = new JLabel(prompt); 667 contentPane.add(_prompt, BorderLayout.NORTH); 668 contentPane.add(scroll, BorderLayout.CENTER); 669 670 iframe.setContentPane(contentPane); 671 iframe.pack(); 672 return iframe; 673 } 674 675 /* 676 * ********************* OBlock Table for _desktop **************** 677 */ 678 protected JTable makeOBlockTable(OBlockTableModel model) { 679 _oBlockTable = new JTable(model); 680 TableRowSorter<OBlockTableModel> sorter = new TableRowSorter<>(_oBlockModel); 681 // use NamedBean's built-in Comparator interface for sorting 682 _oBlockTable.setRowSorter(sorter); 683 _oBlockTable.setTransferHandler(new jmri.util.DnDTableImportExportHandler(new int[]{OBlockTableModel.EDIT_COL, 684 OBlockTableModel.DELETE_COL, OBlockTableModel.REPORT_CURRENTCOL, OBlockTableModel.SPEEDCOL, 685 OBlockTableModel.PERMISSIONCOL, OBlockTableModel.UNITSCOL})); 686 _oBlockTable.setDragEnabled(true); 687 688 // Use XTableColumnModel so we can control which columns are visible 689 XTableColumnModel tcm = new XTableColumnModel(); 690 _oBlockTable.setColumnModel(tcm); 691 _oBlockTable.getTableHeader().setReorderingAllowed(true); 692 _oBlockTable.createDefaultColumnsFromModel(); 693 _oBlockModel.addHeaderListener(_oBlockTable); 694 695 _oBlockTable.setDefaultEditor(JComboBox.class, new jmri.jmrit.symbolicprog.ValueEditor()); 696 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.EDIT_COL).setCellEditor(new ButtonEditor(new JButton())); 697 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.EDIT_COL).setCellRenderer(new ButtonRenderer()); 698 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.DELETE_COL).setCellEditor(new ButtonEditor(new JButton())); 699 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.DELETE_COL).setCellRenderer(new ButtonRenderer()); 700 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.UNITSCOL).setCellRenderer( 701 new ToggleButtonRenderer(Bundle.getMessage("cm"), Bundle.getMessage("in"))); 702 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.UNITSCOL).setCellEditor( 703 new ToggleButtonEditor(new JToggleButton(), Bundle.getMessage("cm"), Bundle.getMessage("in"))); 704 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.REPORT_CURRENTCOL).setCellRenderer( 705 new ToggleButtonRenderer(Bundle.getMessage("Current"), Bundle.getMessage("Last"))); 706 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.REPORT_CURRENTCOL).setCellEditor( 707 new ToggleButtonEditor(new JToggleButton(), Bundle.getMessage("Current"), Bundle.getMessage("Last"))); 708 model.configSpeedColumn(_oBlockTable); // use real combo 709 // JComboBox<String> box = new JComboBox<>(OBlockTableModel.curveOptions); 710 // _oBlockTable.getColumnModel().getColumn(OBlockTableModel.CURVECOL).setCellEditor(new DefaultCellEditor(box)); 711 model.configCurveColumn(_oBlockTable); // use real combo 712 // box = new JComboBox<>(jmri.InstanceManager.getDefault(SignalSpeedMap.class).getValidSpeedNames()); 713// box.addItem(""); 714// _oBlockTable.getColumnModel().getColumn(OBlockTableModel.SPEEDCOL).setCellRenderer(new DefaultCellRenderer(new _oBlockModel.SpeedComboBoxPanel())); 715// _oBlockTable.getColumnModel().getColumn(OBlockTableModel.SPEEDCOL).setCellEditor(new DefaultCellEditor(box)); 716 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.PERMISSIONCOL).setCellRenderer( 717 new ToggleButtonRenderer(Bundle.getMessage("Permissive"), Bundle.getMessage("Absolute"))); 718 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.PERMISSIONCOL).setCellEditor( 719 new ToggleButtonEditor(new JToggleButton(), Bundle.getMessage("Permissive"), Bundle.getMessage("Absolute"))); 720 _oBlockTable.addMouseListener(new MouseAdapter() { 721 @Override 722 public void mousePressed(MouseEvent me) { // for macOS, Linux 723 showPopup(me); 724 } 725 726 @Override 727 public void mouseReleased(MouseEvent me) { // for Windows 728 showPopup(me); 729 } 730 }); 731 732 for (int i = 0; i < _oBlockModel.getColumnCount(); i++) { 733 int width = _oBlockModel.getPreferredWidth(i); 734 _oBlockTable.getColumnModel().getColumn(i).setPreferredWidth(width); 735 } 736 _oBlockTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 737 _oBlockTable.setRowHeight(ROW_HEIGHT); 738 739 TableColumn column = tcm.getColumnByModelIndex(OBlockTableModel.REPORTERCOL); 740 tcm.setColumnVisible(column, false); 741 column = tcm.getColumnByModelIndex(OBlockTableModel.REPORT_CURRENTCOL); 742 tcm.setColumnVisible(column, false); 743 column = tcm.getColumnByModelIndex(OBlockTableModel.PERMISSIONCOL); 744 tcm.setColumnVisible(column, false); 745 column = tcm.getColumnByModelIndex(OBlockTableModel.ERR_SENSORCOL); 746 tcm.setColumnVisible(column, false); 747 column = tcm.getColumnByModelIndex(OBlockTableModel.CURVECOL); 748 tcm.setColumnVisible(column, false); 749 750 _oBlockTable.setPreferredScrollableViewportSize(new java.awt.Dimension(_oBlockTable.getPreferredSize().width, 751 ROW_HEIGHT * Math.min(20, InstanceManager.getDefault(OBlockManager.class).getObjectCount()))); 752 return _oBlockTable; 753 } 754 755 private void showPopup(MouseEvent me) { 756 Point p = me.getPoint(); 757 int col = _oBlockTable.columnAtPoint(p); 758 if (!me.isPopupTrigger() && !me.isMetaDown() && !me.isAltDown() && col == OBlockTableModel.STATECOL) { 759 int row = _oBlockTable.rowAtPoint(p); 760 String stateStr = (String) _oBlockModel.getValueAt(row, col); 761 int state = Integer.parseInt(stateStr, 2); 762 stateStr = OBlockTableModel.getValue(state); 763 JPopupMenu popupMenu = new JPopupMenu(); 764 popupMenu.add(new JMenuItem(stateStr)); 765 popupMenu.show(_oBlockTable, me.getX(), me.getY()); 766 } 767 } 768 769 // Opens the Edit OBlock panel for _tabbed 770 protected boolean openOBlockEditor(String blockSystemName, String tabname) { 771 boolean result = false; 772 if (blockSystemName != null) { 773 // this is for Edit (new OBlocks are created from [Add OBlock...] button in table) 774 OBlock oblock = InstanceManager.getDefault(OBlockManager.class).getBySystemName(blockSystemName); 775 if (oblock != null) { 776 BlockPathJPanel panel = makeBlockPathEditPanel(oblock); 777 // BeanEdit UI, adapted from jmri.jmrit.beantable.BlockTableAction 778 jmri.jmrit.beantable.beanedit.OBlockEditAction beanEdit = new jmri.jmrit.beantable.beanedit.OBlockEditAction(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, tabname)); 779 beanEdit.setBean(oblock); 780 beanEdit.setTablePanel(panel); 781 beanEdit.actionPerformed(null); 782 // run on separate thread? does not update new Paths in table! 783 // class WindowMaker implements Runnable { 784 // final OBlock ob; 785 // final BlockPathJPanel panel; 786 // WindowMaker(OBlock oblock, BlockPathJPanel panel) { 787 // ob = oblock; 788 // this.panel = panel; 789 // } 790 // @Override 791 // public void run() { 792 // jmri.jmrit.beantable.beanedit.OBlockEditAction beanEdit = new jmri.jmrit.beantable.beanedit.OBlockEditAction(); 793 // beanEdit.setBean(oblock); 794 // beanEdit.setTablePanel(panel); 795 // beanEdit.actionPerformed(null); 796 // } 797 // } 798 // WindowMaker t = new WindowMaker(oblock, panel); 799 // javax.swing.SwingUtilities.invokeLater(t); 800 log.debug("path table created for oblock {}", blockSystemName); 801 result = true; 802 } 803 } 804 return result; 805 } 806 807 /** 808 * Open the Edit Path panel for _tabbed. 809 * Compare with openOBlockEditor(block, selectedtabname) and OBlockTableAction. 810 * 811 * @param blockName system or user name of the owning oblock 812 * @param pathName name of the path under edit, or null to create a new path 813 * @param bpmodel blockpathtablemodel that should be informed about changes 814 * @return true if successful 815 */ 816 protected boolean openPathEditor(@Nonnull String blockName, @CheckForNull String pathName, BlockPathTableModel bpmodel) { 817 OBlock block = InstanceManager.getDefault(OBlockManager.class).getOBlock(blockName); 818 if (block == null) { 819 log.error("OBlock {} not found", blockName); 820 return false; 821 } 822 OPath path; 823 String title; 824 PathTurnoutJPanel turnouttable = makePathTurnoutPanel(block, pathName); // shows the turnouts on path, includes Add Turnout button, checks for null path 825 if (pathName == null) { // new Path, empty TurnoutTable 826 // a new Path is created from [Add Path...] button in Path table on OBlock Editor pane. 827 path = null; 828 title = Bundle.getMessage("AddPathTitle", blockName); 829 } else { 830 path = block.getPathByName(pathName); 831 title = Bundle.getMessage("EditPathTitle", pathName, blockName); 832 } 833 BlockPathEditFrame bpef = new BlockPathEditFrame(title, block, path, turnouttable, bpmodel, this); 834 bpef.setVisible(true); 835 // run on separate thread? combos are final, difficult to store Partals in Path/see them show up in the table 836 // class WindowMaker implements Runnable { 837 // final String title; 838 // final OBlock ob; 839 // final OPath path; 840 // final PathTurnoutTableModel tomodel; 841 // final BlockPathTableModel bpmodel; 842 // final TableFrames parent; 843 // WindowMaker(String title, OBlock ob, OPath path, PathTurnoutTableModel turnoutmodel, BlockPathTableModel blockpathmodel, TableFrames tf) { 844 // this.title = title; 845 // this.ob = ob; 846 // this.path = path; 847 // this.tomodel = turnoutmodel; 848 // this.bpmodel = blockpathmodel; 849 // parent = tf; 850 // } 851 // @Override 852 // public void run() { 853 // BlockPathEditFrame bpef = new BlockPathEditFrame(title, block, path, turnouttable, bpmodel, parent); 854 // bpef.setVisible(true); 855 // } 856 // } 857 // WindowMaker t = new WindowMaker(title, block, path, turnouttable.getModel(), bpmodel, this); 858 // javax.swing.SwingUtilities.invokeLater(t); 859 860 log.debug("Path editor created for path {} on block {}", pathName, blockName); 861 return true; 862 } 863 864 /* 865 * ********************* PortalTable for _desktop ***************************** 866 */ 867 protected JTable makePortalTable(PortalTableModel model) { 868 _portalTable = new JTable(model); 869 TableRowSorter<PortalTableModel> sorter = new TableRowSorter<>(model); 870 _portalTable.setRowSorter(sorter); 871 _portalTable.setTransferHandler(new jmri.util.DnDTableImportExportHandler(new int[]{PortalTableModel.DELETE_COL})); 872 _portalTable.setDragEnabled(true); 873 874 _portalTable.getColumnModel().getColumn(PortalTableModel.DELETE_COL).setCellEditor(new ButtonEditor(new JButton())); 875 _portalTable.getColumnModel().getColumn(PortalTableModel.DELETE_COL).setCellRenderer(new ButtonRenderer()); 876 for (int i = 0; i < model.getColumnCount(); i++) { 877 int width = model.getPreferredWidth(i); 878 _portalTable.getColumnModel().getColumn(i).setPreferredWidth(width); 879 } 880 _portalTable.doLayout(); 881 int tableWidth = _portalTable.getPreferredSize().width; 882 _portalTable.setRowHeight(ROW_HEIGHT); 883 _portalTable.setPreferredScrollableViewportSize(new java.awt.Dimension(tableWidth, 884 ROW_HEIGHT * Math.min(20, InstanceManager.getDefault(PortalManager.class).getPortalCount()))); 885 return _portalTable; 886 } 887 888 /* 889 * ********************* Block-Portal (XRef) Table for _desktop ***************************** 890 */ 891 protected JTable makeBlockPortalTable(BlockPortalTableModel model) { 892 _blockPortalTable = new JTable(model); 893 _blockPortalTable.setTransferHandler(new jmri.util.DnDTableExportHandler()); 894 _blockPortalTable.setDragEnabled(true); 895 896 _blockPortalTable.setDefaultRenderer(String.class, new jmri.jmrit.symbolicprog.ValueRenderer()); 897 _blockPortalTable.setDefaultEditor(String.class, new jmri.jmrit.symbolicprog.ValueEditor()); // useful on non-editable cell? 898 for (int i = 0; i < model.getColumnCount(); i++) { 899 int width = model.getPreferredWidth(i); 900 _blockPortalTable.getColumnModel().getColumn(i).setPreferredWidth(width); 901 } 902 _blockPortalTable.doLayout(); 903 _blockPortalTable.setRowHeight(ROW_HEIGHT); 904 int tableWidth = _blockPortalTable.getPreferredSize().width; 905 _blockPortalTable.setPreferredScrollableViewportSize(new java.awt.Dimension(tableWidth, 906 ROW_HEIGHT * Math.min(20, InstanceManager.getDefault(PortalManager.class).getPortalCount()))); 907 908 return _blockPortalTable; 909 } 910 911 /* 912 * ********************* Signal Table for _desktop ***************************** 913 */ 914 protected JTable makeSignalTable(SignalTableModel model) { 915 _signalTable = new JTable(model); 916 TableRowSorter<SignalTableModel> sorter = new TableRowSorter<>(model); 917 _signalTable.setRowSorter(sorter); 918 _signalTable.setTransferHandler(new jmri.util.DnDTableImportExportHandler( 919 new int[]{SignalTableModel.UNITSCOL, SignalTableModel.DELETE_COL})); 920 _signalTable.setDragEnabled(true); 921 922 _signalTable.getColumnModel().getColumn(SignalTableModel.UNITSCOL).setCellRenderer( 923 new ToggleButtonRenderer(Bundle.getMessage("cm"), Bundle.getMessage("in"))); 924 _signalTable.getColumnModel().getColumn(SignalTableModel.UNITSCOL).setCellEditor( 925 new ToggleButtonEditor(new JToggleButton(), Bundle.getMessage("cm"), Bundle.getMessage("in"))); 926 _signalTable.getColumnModel().getColumn(SignalTableModel.DELETE_COL).setCellEditor(new ButtonEditor(new JButton())); 927 _signalTable.getColumnModel().getColumn(SignalTableModel.DELETE_COL).setCellRenderer(new ButtonRenderer()); 928 for (int i = 0; i < model.getColumnCount(); i++) { 929 int width = SignalTableModel.getPreferredWidth(i); 930 _signalTable.getColumnModel().getColumn(i).setPreferredWidth(width); 931 } 932 _signalTable.doLayout(); 933 int tableWidth = _signalTable.getPreferredSize().width; 934 _signalTable.setRowHeight(ROW_HEIGHT); 935 _signalTable.setPreferredScrollableViewportSize(new java.awt.Dimension(tableWidth, 936 ROW_HEIGHT * Math.min(10, _signalTable.getRowCount()))); 937 return _signalTable; 938 } 939 940 /* 941 * ***************** end of permanent Tables + InternalFrame definitions ***************** 942 */ 943 944 945 /* 946 * ***************** On Demand Tables + InternalFrame definitions ***************** 947 */ 948 949 /* 950 * ********************* Block-Path Frame ***************************** 951 */ 952 953 // called from Tables menu and the OBlockTable EDIT buttons 954 public void openBlockPathPane(String blockSystemName, String editorTabName) { 955 if (_tabbed) { 956 if (!openOBlockEditor(blockSystemName, editorTabName)) { 957 // pass on to Per OBlock Edit panel, includes a BlockPath table 958 log.error("Failed to open OBlock Path table for {}", blockSystemName); 959 } 960 } else { 961 openBlockPathFrame(blockSystemName); // an editable table of all paths on this block 962 } 963 } 964 965 // ***************** Block-Path Frame for _desktop ************************** 966 /** 967 * Open a block-specific Block-Path table in _desktop interface. 968 * 969 * @param blockSystemName of the OBlock 970 */ 971 protected void openBlockPathFrame(String blockSystemName) { 972 BlockPathFrame frame = _blockPathMap.get(blockSystemName); 973 if (frame == null) { 974 OBlock block = InstanceManager.getDefault(OBlockManager.class).getBySystemName(blockSystemName); 975 if (block == null) { 976 return; 977 } 978 frame = makeBlockPathFrame(block); 979 // store frame in Map 980 _blockPathMap.put(blockSystemName, frame); 981 frame.setVisible(true); 982 desktopframe.getContentPane().add(frame); 983 } else { 984 frame.setVisible(true); 985 try { 986 frame.setIcon(false); 987 } catch (PropertyVetoException pve) { 988 log.warn("BlockPath Table Frame for \"{}\" vetoed setIcon", blockSystemName, pve); 989 } 990 } 991 frame.moveToFront(); 992 } 993 994 // common dispose 995 protected void disposeBlockPathFrame(OBlock block) { 996 if (!_tabbed) { 997 //BlockPathFrame frame = _blockPathMap.get(block.getSystemName()); 998 // TODO frame.getModel().removeListener(); 999 //_blockPathMap.remove(block.getSystemName()); // block not stored in map, required to remove listener? 1000 // frame.dispose(); not required (closeable window) 1001 //} else { 1002 BlockPathFrame frame = _blockPathMap.get(block.getSystemName()); 1003 frame.getModel().removeListener(); 1004 _blockPathMap.remove(block.getSystemName()); 1005 frame.dispose(); 1006 } 1007 } 1008 1009 // *************** Block-Path InternalFrame for _desktop *********************** 1010 1011 protected BlockPathFrame makeBlockPathFrame(OBlock block) { 1012 String title = Bundle.getMessage("TitleBlockPathTable", block.getDisplayName()); 1013 // create table 1014 BlockPathTableModel model = new BlockPathTableModel(block, this); 1015 JPanel contentPane = makeBlockPathTablePanel(model); 1016 1017 BlockPathFrame frame = new BlockPathFrame(title, true, true, false, true); 1018 frame.setModel(model, block.getSystemName()); 1019 frame.addInternalFrameListener(this); 1020 frame.setContentPane(contentPane); 1021 //frame.setClosable(true); // set in ctor 1022 frame.setLocation(50, 30); 1023 frame.pack(); 1024 return frame; 1025 } 1026 1027 // *************** Block-Path Edit Panel for _tabbed *********************** 1028 1029 protected BlockPathJPanel makeBlockPathEditPanel(OBlock block) { 1030 // Path Table placed on jmri.jmrit.beanedit OBlockEditAction - Paths tab 1031 String title = Bundle.getMessage("TitleBlockPathEditor", block.getDisplayName()); 1032 // create table 1033 BlockPathTableModel model = new BlockPathTableModel(block, this); 1034 JPanel bpTablePane = makeBlockPathTablePanel(model); 1035 BlockPathJPanel panel = new BlockPathJPanel(title); 1036 panel.setModel(model, block.getSystemName()); 1037 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 1038 panel.add(bpTablePane); 1039 1040 // Add Path Button 1041 JPanel tblButtons = new JPanel(); 1042 tblButtons.setLayout(new BorderLayout(10, 10)); 1043 tblButtons.setBorder(BorderFactory.createEmptyBorder(2, 10, 2, 10)); 1044 tblButtons.setLayout(new BoxLayout(tblButtons, BoxLayout.Y_AXIS)); 1045 1046 JButton addPathButton = new JButton(Bundle.getMessage("ButtonAddPath")); 1047 ActionListener addPathAction = e -> { 1048 // New Path uses the same editor pane as Edit Path 1049 if (!isPathEdit()) { 1050 setPathEdit(true); 1051 log.debug("makeBlockPathEditPanel pathEdit=True"); 1052 openPathEditor(block.getDisplayName(), null, model); 1053 } else { 1054 log.warn("Close BlockPath Editor to reopen"); 1055 } 1056 }; 1057 addPathButton.addActionListener(addPathAction); 1058 addPathButton.setToolTipText(Bundle.getMessage("AddPathTabbedPrompt")); 1059 tblButtons.add(addPathButton); 1060 panel.add(tblButtons); 1061 1062 //panel.pack(); 1063 return panel; 1064 } 1065 1066 // prevent more than 1 edit pane being opened at the same time 1067 protected void setPathEdit(boolean edit) { 1068 pathEdit = edit; 1069 } 1070 1071 protected boolean isPathEdit() { 1072 return pathEdit; 1073 } 1074 1075 1076 // ***************** Block-Path Frame class for _desktop ************************** 1077 protected static class BlockPathFrame extends JInternalFrame { 1078 1079 BlockPathTableModel blockPathModel; 1080 1081 BlockPathFrame(String title, boolean resizable, boolean closable, 1082 boolean maximizable, boolean iconifiable) { 1083 super(title, resizable, closable, maximizable, iconifiable); 1084 } 1085 1086 BlockPathTableModel getModel() { 1087 return blockPathModel; 1088 } 1089 1090 void setModel(BlockPathTableModel model, String blockName) { 1091 blockPathModel = model; 1092 setName(blockName); 1093 } 1094 } 1095 1096 // ***************** Block-Path JPanel class for _tabbed ************************** 1097 public static class BlockPathJPanel extends JPanel { 1098 1099 BlockPathTableModel blockPathModel; 1100 1101 BlockPathJPanel(String title) { 1102 super(); 1103 super.setName(title); 1104 } 1105 1106 BlockPathTableModel getModel() { 1107 return blockPathModel; 1108 } 1109 1110 void setModel(BlockPathTableModel model, String blockName) { 1111 blockPathModel = model; 1112 setName(blockName); 1113 } 1114 } 1115 1116 /* 1117 * ********************* Block-Path Table Panel for _desktop and _tabbed *********************** 1118 */ 1119 protected JPanel makeBlockPathTablePanel(BlockPathTableModel _model) { 1120 JTable blockPathTable = makeBlockPathTable(_model); // styled 1121 1122 // get table 1123 JScrollPane tablePane = new JScrollPane(blockPathTable); 1124 JPanel contentPane = new JPanel(); 1125 contentPane.setLayout(new BorderLayout(5, 5)); 1126 if (_tabbed) { 1127 // a bit more styling 1128 blockPathTable.setPreferredScrollableViewportSize(new Dimension(600, 100)); 1129 } else { 1130 JLabel prompt = new JLabel(Bundle.getMessage("AddPathPrompt")); 1131 contentPane.add(prompt, BorderLayout.NORTH); 1132 } 1133 contentPane.add(tablePane, BorderLayout.CENTER); 1134 1135 return contentPane; 1136 } 1137 1138 protected JTable makeBlockPathTable(BlockPathTableModel _model) { 1139 JTable blockPathTable = new JTable(_model); 1140 // configure DnD 1141 blockPathTable.setTransferHandler(new jmri.util.DnDTableImportExportHandler(new int[]{BlockPathTableModel.EDIT_COL, BlockPathTableModel.DELETE_COL, BlockPathTableModel.UNITSCOL})); 1142 blockPathTable.setDragEnabled(true); 1143 // style table 1144 blockPathTable.getColumnModel().getColumn(BlockPathTableModel.UNITSCOL).setCellRenderer(new ToggleButtonRenderer(Bundle.getMessage("cm"), Bundle.getMessage("in"))); 1145 blockPathTable.getColumnModel().getColumn(BlockPathTableModel.UNITSCOL).setCellEditor(new ToggleButtonEditor(new JToggleButton(), Bundle.getMessage("cm"), Bundle.getMessage("in"))); 1146 blockPathTable.getColumnModel().getColumn(BlockPathTableModel.EDIT_COL).setCellEditor(new ButtonEditor(new JButton())); 1147 blockPathTable.getColumnModel().getColumn(BlockPathTableModel.EDIT_COL).setCellRenderer(new ButtonRenderer()); 1148 blockPathTable.getColumnModel().getColumn(BlockPathTableModel.DELETE_COL).setCellEditor(new ButtonEditor(new JButton())); 1149 blockPathTable.getColumnModel().getColumn(BlockPathTableModel.DELETE_COL).setCellRenderer(new ButtonRenderer()); 1150 // units, etc renderer 1151 1152 for (int i = 0; i < _model.getColumnCount(); i++) { 1153 int width = _model.getPreferredWidth(i); 1154 blockPathTable.getColumnModel().getColumn(i).setPreferredWidth(width); 1155 } 1156 blockPathTable.doLayout(); 1157 int tableWidth = blockPathTable.getPreferredSize().width; 1158 blockPathTable.setRowHeight(ROW_HEIGHT); 1159 blockPathTable.setPreferredScrollableViewportSize(new java.awt.Dimension(tableWidth, Math.min(TableFrames.ROW_HEIGHT * 10, maxHeight))); 1160 1161 return blockPathTable; 1162 } 1163 1164 /** 1165 * ********************* Path-Turnout Frame *********************************** 1166 */ 1167 1168 // ********************* Path-Turnout Frame class for _desktop **************** 1169 protected static class PathTurnoutFrame extends JInternalFrame { 1170 1171 /** 1172 * Remember the tableModel 1173 */ 1174 PathTurnoutTableModel pathTurnoutModel; 1175 1176 PathTurnoutFrame(String title, boolean resizable, boolean closable, 1177 boolean maximizable, boolean iconifiable) { 1178 super(title, resizable, closable, maximizable, iconifiable); 1179 } 1180 1181 PathTurnoutTableModel getModel() { 1182 return pathTurnoutModel; 1183 } 1184 1185 void setModel(PathTurnoutTableModel model) { 1186 pathTurnoutModel = model; 1187 } 1188 } 1189 1190 /** 1191 * ********************* Path-Turnout JPanel class for _tabbed ***************** 1192 */ 1193 protected static class PathTurnoutJPanel extends JPanel { 1194 1195 /** 1196 * Remember the tableModel 1197 */ 1198 PathTurnoutTableModel pathTurnoutModel; 1199 1200 PathTurnoutJPanel(String pathname) { 1201 super(); 1202 setName(pathname); 1203 } 1204 1205 PathTurnoutTableModel getModel() { 1206 return pathTurnoutModel; 1207 } 1208 1209 void setModel(PathTurnoutTableModel model) { 1210 pathTurnoutModel = model; 1211 } 1212 } 1213 1214 /* 1215 * ********************* Path-TurnoutFrame for _desktop ************************* 1216 */ 1217 protected PathTurnoutFrame makePathTurnoutFrame(OBlock block, String pathName) { 1218 String title = Bundle.getMessage("TitlePathTurnoutTable", block.getDisplayName(), pathName); 1219 PathTurnoutFrame frame = new PathTurnoutFrame(title, true, true, false, true); 1220 if (log.isDebugEnabled()) { 1221 log.debug("makePathTurnoutFrame for Block {} and Path {} on _desktop", block.getDisplayName(), pathName); 1222 } 1223 frame.setName(makePathTurnoutName(block.getSystemName(), pathName)); 1224 OPath path = block.getPathByName(pathName); 1225 if (path == null) { 1226 return null; 1227 } 1228 PathTurnoutTableModel pathTurnoutModel = new PathTurnoutTableModel(path, frame); 1229 frame.setModel(pathTurnoutModel); 1230 1231 JTable pathTurnoutTable = makePathTurnoutTable(pathTurnoutModel); 1232 1233 JScrollPane tablePane = new JScrollPane(pathTurnoutTable); 1234 1235 JPanel contentPane = new JPanel(); 1236 contentPane.setLayout(new BorderLayout(5, 5)); 1237 JLabel prompt = new JLabel(Bundle.getMessage("AddTurnoutPrompt")); 1238 contentPane.add(prompt, BorderLayout.NORTH); 1239 contentPane.add(tablePane, BorderLayout.CENTER); 1240 1241 frame.addInternalFrameListener(this); 1242 frame.setContentPane(contentPane); 1243 //frame.setClosable(true); // is set in ctor 1244 frame.setLocation(10, 270); 1245 frame.pack(); 1246 return frame; 1247 } 1248 1249 /* 1250 * ********************* Path-TurnoutPanel for _tabbed ***************************** 1251 */ 1252 protected PathTurnoutJPanel makePathTurnoutPanel(@Nonnull OBlock block, @CheckForNull String pathName) { 1253 String title = Bundle.getMessage("TitlePathTurnoutTable", block.getDisplayName(), pathName); 1254 PathTurnoutJPanel panel = new PathTurnoutJPanel(title); 1255 PathTurnoutTableModel pathTurnoutModel; 1256 JTable pathTurnoutTable; 1257 JButton addTurnoutButton = new JButton(Bundle.getMessage("ButtonAddTurnout")); 1258 addTurnoutButton.setToolTipText(Bundle.getMessage("AddTurnoutTabbedPrompt")); 1259 JLabel prompt = new JLabel(); 1260 prompt.setFont(prompt.getFont().deriveFont(0.9f * new JLabel().getFont().getSize())); // a bit smaller 1261 prompt.setForeground(Color.gray); 1262 1263 if (pathName == null) { 1264 panel.setName(makePathTurnoutName(block.getSystemName(), "<new Path>")); 1265 String[] columnHeaders = {Bundle.getMessage("Turnouts")}; 1266 String[][] emptyTable = new String[][] {{Bundle.getMessage("None")}}; 1267 pathTurnoutTable = new JTable(emptyTable, columnHeaders); // dummy table 1268 addTurnoutButton.setEnabled(false); 1269 prompt.setText(Bundle.getMessage("TurnoutTablePromptNew")); 1270 } else { 1271 panel.setName(makePathTurnoutName(block.getSystemName(), pathName)); 1272 final OPath path = block.getPathByName(pathName); // final for actionhandler 1273 if (path == null) { 1274 return null; // unexpected 1275 } 1276 pathTurnoutModel = new PathTurnoutTableModel(path); 1277 pathTurnoutTable = makePathTurnoutTable(pathTurnoutModel); 1278 panel.setModel(pathTurnoutModel); 1279 ActionListener addTurnoutAction= e -> addTurnoutPane(path, pathTurnoutModel); 1280 addTurnoutButton.addActionListener(addTurnoutAction); 1281 prompt.setText(Bundle.getMessage("TurnoutTablePrompt")); 1282 } 1283 JScrollPane tablePane = new JScrollPane(pathTurnoutTable); 1284 1285 JPanel tblButtons = new JPanel(); 1286 tblButtons.setLayout(new BorderLayout(10, 10)); 1287 tblButtons.setBorder(BorderFactory.createEmptyBorder(2, 10, 2, 10)); 1288 tblButtons.setLayout(new BoxLayout(tblButtons, BoxLayout.Y_AXIS)); 1289 tblButtons.add(addTurnoutButton); 1290 // add more to frame? 1291 1292 panel.setLayout(new BorderLayout(5, 5)); 1293 1294 panel.add(prompt, BorderLayout.NORTH); 1295 panel.add(tablePane, BorderLayout.CENTER); 1296 panel.add(tblButtons, BorderLayout.SOUTH); 1297 1298 return panel; 1299 } 1300 1301 /* 1302 * ********************* Path-Turnout Table ***************************** 1303 */ 1304 protected JTable makePathTurnoutTable(PathTurnoutTableModel model) { 1305 JTable pathTurnoutTable = new JTable(model); 1306 pathTurnoutTable.setTransferHandler(new jmri.util.DnDTableImportExportHandler( 1307 new int[]{PathTurnoutTableModel.STATE_COL, PathTurnoutTableModel.DELETE_COL})); 1308 pathTurnoutTable.setDragEnabled(true); 1309 1310 model.configTurnoutStateColumn(pathTurnoutTable); // use real combo 1311 pathTurnoutTable.getColumnModel().getColumn(PathTurnoutTableModel.DELETE_COL).setCellEditor(new ButtonEditor(new JButton())); 1312 pathTurnoutTable.getColumnModel().getColumn(PathTurnoutTableModel.DELETE_COL).setCellRenderer(new ButtonRenderer()); 1313 //pathTurnoutTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 1314 for (int i = 0; i < model.getColumnCount(); i++) { 1315 int width = model.getPreferredWidth(i); 1316 pathTurnoutTable.getColumnModel().getColumn(i).setPreferredWidth(width); 1317 } 1318 pathTurnoutTable.doLayout(); 1319 int tableWidth = pathTurnoutTable.getPreferredSize().width; 1320 pathTurnoutTable.setRowHeight(ROW_HEIGHT); 1321 pathTurnoutTable.setPreferredScrollableViewportSize(new java.awt.Dimension(tableWidth, 1322 Math.min(TableFrames.ROW_HEIGHT * 5, maxHeight))); 1323 1324 return pathTurnoutTable; 1325 } 1326 1327 /** 1328 * Create a coded id for a path turnout. 1329 * 1330 * @param blockSysName oblock system name 1331 * @param pathName the path through the oblock for which to display turnouts set 1332 * @return name of the pathTurnout, example "%path 1-3&block-1" 1333 */ 1334 protected String makePathTurnoutName(String blockSysName, String pathName) { 1335 return "%" + pathName + "&" + blockSysName; 1336 } 1337 1338 // ********************* Open Path-Turnout Frame for _desktop ***************************** 1339 /** 1340 * Open a block-specific PathTurnouts table as a JInternalFrame for _desktop from BlockPathTableModel 1341 * 1342 * @param pathTurnoutName name of turnout configured on Path 1343 */ 1344 protected void openPathTurnoutFrame(String pathTurnoutName) { 1345 PathTurnoutFrame frame = _pathTurnoutMap.get(pathTurnoutName); 1346 if (frame == null) { 1347 int index = pathTurnoutName.indexOf('&'); 1348 String pathName = pathTurnoutName.substring(1, index); 1349 String blockName = pathTurnoutName.substring(index + 1); 1350 OBlock block = InstanceManager.getDefault(OBlockManager.class).getBySystemName(blockName); 1351 if (block == null) { 1352 return; 1353 } 1354 frame = makePathTurnoutFrame(block, pathName); 1355 if (frame == null) { 1356 return; 1357 } 1358 _pathTurnoutMap.put(pathTurnoutName, frame); 1359 frame.setVisible(true); 1360 desktopframe.getContentPane().add(frame); 1361 } else { 1362 frame.setVisible(true); 1363 try { 1364 frame.setIcon(false); 1365 } catch (PropertyVetoException pve) { 1366 log.warn("PathTurnout Table Frame for \"{}\" vetoed setIcon", pathTurnoutName, pve); 1367 } 1368 } 1369 frame.moveToFront(); 1370 } 1371 1372 // *********** Open stand alone Path-Turnout Edit Panel for _tabbed ********************* 1373 /** 1374 * Open a block-specific PathTurnouts edit pane as a JmriJFrame for _tabbed from menu. 1375 * TODO fix menu access to pathturnouts on _tabbed in ListedTableView, single table menus OK 1376 * 1377 * @param pathTurnoutName name of turnout configured on Path 1378 */ 1379 protected void openPathTurnoutEditor(String pathTurnoutName) { 1380 int index = pathTurnoutName.indexOf('&'); 1381 String pathName = pathTurnoutName.substring(1, index); 1382 String blockName = pathTurnoutName.substring(index + 1); 1383 OBlock block = InstanceManager.getDefault(OBlockManager.class).getBySystemName(blockName); 1384 if (block == null) { 1385 return; 1386 } 1387 OPath path = block.getPathByName(pathName); 1388 if (path == null) { 1389 return; 1390 } 1391 PathTurnoutJPanel turnouttable = makePathTurnoutPanel(block, pathName); 1392 // shows the turnouts on this path, already includes [Add Turnout...] button 1393 JmriJFrame frame = new JmriJFrame(Bundle.getMessage("TitlePathTurnoutTable", block.getDisplayName(), pathName)); 1394 frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.PAGE_AXIS)); 1395 frame.setSize(370, 250); 1396 1397 JPanel p = new JPanel(); 1398 p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS)); 1399 p.add(turnouttable); 1400 JButton ok; 1401 p.add(ok = new JButton(Bundle.getMessage("ButtonOK"))); // no need to save things, handled by TurnoutTable 1402 ok.addActionListener((ActionEvent e) -> frame.dispose()); 1403 frame.getContentPane().add(p); 1404 frame.pack(); 1405 frame.setVisible(true); 1406 } 1407 1408 /** 1409 * Add new Turnout pane, called from makePathTurnoutPanel on _tabbed interface. 1410 * 1411 * @param path to link this turnout setting to 1412 * @param pathTurnoutModel displayed table of turnouts currently set on this path 1413 */ 1414 protected void addTurnoutPane(OPath path, PathTurnoutTableModel pathTurnoutModel) { 1415 JmriJFrame frame = new JmriJFrame(Bundle.getMessage("NewTurnoutTitle", path.getName())); 1416 frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.PAGE_AXIS)); 1417 frame.setSize(200, 150); 1418 1419 JPanel p = new JPanel(); 1420 1421 final NamedBeanComboBox<Turnout> turnoutBox = new NamedBeanComboBox<>(InstanceManager.getDefault(TurnoutManager.class), null, NamedBean.DisplayOptions.DISPLAYNAME); 1422 JComboBox<String> stateCombo = new JComboBox<>(); 1423 JLabel statusBar = new JLabel(Bundle.getMessage("AddXStatusInitial1", Bundle.getMessage("BeanNameTurnout"), Bundle.getMessage("ButtonOK")), JLabel.LEADING); 1424 stateCombo.addItem(SET_THROWN); 1425 stateCombo.addItem(SET_CLOSED); 1426 turnoutBox.setToolTipText(Bundle.getMessage("TurnoutEditToolTip")); 1427 1428 JPanel p1 = new JPanel(); 1429 p1.setLayout(new BoxLayout(p1, BoxLayout.LINE_AXIS)); 1430 p1.add(new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("BeanNameTurnout")))); 1431 p1.add(turnoutBox); 1432 p.add(p1); 1433 1434 p1 = new JPanel(); 1435 p1.add(new JLabel(Bundle.getMessage("MakeLabel", Bundle.getMessage("ColumnLabelSetState")))); 1436 p1.add(stateCombo); 1437 p.add(p1); 1438 1439 p.add(Box.createVerticalGlue()); 1440 1441 JPanel p2 = new JPanel(); 1442 statusBar.setFont(statusBar.getFont().deriveFont(0.9f * (new JLabel()).getFont().getSize())); // a bit smaller 1443 if (turnoutBox.getItemCount() < 1) { 1444 statusBar.setText(Bundle.getMessage("NotEnoughTurnouts")); 1445 statusBar.setForeground(Color.red); 1446 } else { 1447 statusBar.setForeground(Color.gray); 1448 } 1449 p2.add(statusBar); 1450 p.add(p2); 1451 1452 JPanel btns = new JPanel(); 1453 btns.setLayout(new BoxLayout(btns, BoxLayout.LINE_AXIS)); 1454 JButton cancel; 1455 btns.add(cancel = new JButton(Bundle.getMessage("ButtonCancel"))); 1456 cancel.addActionListener((ActionEvent e) -> frame.dispose()); 1457 JButton ok; 1458 btns.add(ok = new JButton(Bundle.getMessage("ButtonOK"))); 1459 ok.addActionListener((ActionEvent e) -> { 1460 if (turnoutBox.getSelectedItem() == null || turnoutBox.getSelectedIndex() < 0) { 1461 statusBar.setText(Bundle.getMessage("WarningSelectionEmpty")); 1462 statusBar.setForeground(Color.red); 1463 } else { 1464 String user = turnoutBox.getSelectedItemDisplayName(); 1465 Turnout t = InstanceManager.turnoutManagerInstance().getTurnout(user); 1466 if (t != null) { 1467 int s; 1468 if (stateCombo.getSelectedItem() != null && stateCombo.getSelectedItem().equals(SET_CLOSED)) { 1469 s = Turnout.CLOSED; 1470 } else { 1471 s = Turnout.THROWN; 1472 } 1473 BeanSetting bs = new BeanSetting(t, user, s); 1474 path.addSetting(bs); 1475 if (pathTurnoutModel != null) { 1476 pathTurnoutModel.fireTableDataChanged(); 1477 } 1478 } else { 1479 log.error("PathTurnout {} not found", user); 1480 } 1481 frame.dispose(); 1482 } 1483 }); 1484 p.add(btns, BorderLayout.SOUTH); 1485 1486 frame.getContentPane().add(p); 1487 frame.pack(); 1488 frame.setVisible(true); 1489 } 1490 1491 /* 1492 * ********************* End of tables and frames methods ***************************** 1493 */ 1494 1495 // Shared warning dialog method. Store user pref to suppress further mentions. 1496 protected int verifyWarning(String message) { 1497 int val = 0; 1498 if (_showWarnings) { 1499 // verify deletion 1500 val = JmriJOptionPane.showOptionDialog(null, 1501 message, Bundle.getMessage("WarningTitle"), 1502 JmriJOptionPane.YES_NO_CANCEL_OPTION, JmriJOptionPane.QUESTION_MESSAGE, null, 1503 new Object[]{Bundle.getMessage("ButtonYes"), 1504 Bundle.getMessage("ButtonYesPlus"), 1505 Bundle.getMessage("ButtonNo")}, 1506 Bundle.getMessage("ButtonNo")); // default choice = No 1507 if (val == 1) { // suppress future warnings 1508 _showWarnings = false; 1509 } 1510 } 1511 return val; 1512 } 1513 1514 /* 1515 * ********************* InternalFrameListener implementation for _desktop ***************** 1516 */ 1517 @Override 1518 public void internalFrameClosing(InternalFrameEvent e) { 1519 JInternalFrame frame = (JInternalFrame)e.getSource(); 1520 log.debug("Internal frame closing: {}", frame.getTitle()); 1521 if (frame.getTitle().equals(Bundle.getMessage("TitleBlockTable"))) { 1522 showHideFrame(_blockTableFrame, openBlock, "OpenBlockMenu"); 1523 } 1524 } 1525 1526 // clean up on close on _desktop 1527 // for _tabbed this is handled in the Edit pane applyPressed() method 1528 @Override 1529 public void internalFrameClosed(InternalFrameEvent e) { 1530 JInternalFrame frame = (JInternalFrame) e.getSource(); 1531 String name = frame.getName(); 1532 if (log.isDebugEnabled()) { 1533 log.debug("Internal frame closed: {}, name= {} size ({}, {})", 1534 frame.getTitle(), name, 1535 frame.getSize().getWidth(), frame.getSize().getHeight()); 1536 } 1537 if (name != null && name.startsWith("OB")) { 1538 _blockPathMap.remove(name); 1539 if (frame instanceof BlockPathFrame) { 1540 String msg = WarrantTableAction.getDefault().checkPathPortals(((BlockPathFrame) frame).getModel().getBlock()); 1541 if (!msg.isEmpty()) { 1542 JmriJOptionPane.showMessageDialog(desktopframe, msg, 1543 Bundle.getMessage("InfoTitle"), JmriJOptionPane.INFORMATION_MESSAGE); 1544 } 1545 ((BlockPathFrame) frame).getModel().removeListener(); 1546 } 1547 } else { 1548 if (frame instanceof PathTurnoutFrame) { 1549 ((PathTurnoutFrame) frame).getModel().removeListener(); 1550 } 1551 _pathTurnoutMap.remove(name); 1552 } 1553 } 1554 1555 @Override 1556 public void internalFrameOpened(InternalFrameEvent e) { 1557 /* JInternalFrame frame = (JInternalFrame)e.getSource(); 1558 if (log.isDebugEnabled()) { 1559 log.debug("Internal frame Opened: {}, name= {} size ({}, {})", 1560 frame.getTitle(), frame.getName(), 1561 frame.getSize().getWidth(), frame.getSize().getHeight()); 1562 }*/ 1563 } 1564 1565 @Override 1566 public void internalFrameIconified(InternalFrameEvent e) { 1567 JInternalFrame frame = (JInternalFrame) e.getSource(); 1568 String name = frame.getName(); 1569 if (log.isDebugEnabled()) { 1570 log.debug("Internal frame Iconified: {}, name= {} size ({}, {})", 1571 frame.getTitle(), name, 1572 frame.getSize().getWidth(), frame.getSize().getHeight()); 1573 } 1574 if (name != null && name.startsWith(oblockPrefix())) { 1575 if (frame instanceof BlockPathFrame) { 1576 String msg = WarrantTableAction.getDefault().checkPathPortals(((BlockPathFrame) frame).getModel().getBlock()); 1577 JmriJOptionPane.showMessageDialog(desktopframe, msg, 1578 Bundle.getMessage("InfoTitle"), JmriJOptionPane.INFORMATION_MESSAGE); 1579 } 1580 } 1581 } 1582 1583 @Override 1584 public void internalFrameDeiconified(InternalFrameEvent e) { 1585 //JInternalFrame frame = (JInternalFrame)e.getSource(); 1586 //log.debug("Internal frame deiconified: {}", frame.getTitle()); 1587 } 1588 1589 @Override 1590 public void internalFrameActivated(InternalFrameEvent e) { 1591 //JInternalFrame frame = (JInternalFrame)e.getSource(); 1592 //log.debug("Internal frame activated: {}", frame.getTitle()); 1593 } 1594 1595 @Override 1596 public void internalFrameDeactivated(InternalFrameEvent e) { 1597 //JInternalFrame frame = (JInternalFrame)e.getSource(); 1598 //log.debug("Internal frame deactivated: {}", frame.getTitle()); 1599 } 1600 1601 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TableFrames.class); 1602 1603}