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