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.table.ButtonEditor; 033import jmri.util.table.ButtonRenderer; 034import jmri.util.table.ToggleButtonEditor; 035import jmri.util.table.ToggleButtonRenderer; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039/** 040 * GUI to define OBlocks. 041 * <p> 042 * Core code can be used with two interfaces: 043 * <ul> 044 * <li>original "desktop" InternalFrames (displays as InternalJFrames inside a JmriJFrame) 045 * <li>JMRI standard Tabbed tables (displays as Js inside a ListedTableFrame) 046 * </ul> 047 * The _tabbed field decides, it is set in prefs (restart required). TableFrames itself has no UI. 048 * <hr> 049 * This file is part of JMRI. 050 * <p> 051 * JMRI is free software; you can redistribute it and/or modify it under the 052 * terms of version 2 of the GNU General Public License as published by the Free 053 * Software Foundation. See the "COPYING" file for a copy of this license. 054 * <p> 055 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY 056 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 057 * A PARTICULAR PURPOSE. See the GNU General Public License for more details. 058 * 059 * @author Pete Cressman (C) 2010 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 * @author Egbert Broerse 2019 355 */ 356 protected void importBlocks() throws IllegalArgumentException { 357 Manager<Block> bm = InstanceManager.getDefault(jmri.BlockManager.class); 358 OBlockManager obm = InstanceManager.getDefault(OBlockManager.class); 359 PortalManager pom = InstanceManager.getDefault(PortalManager.class); 360 SortedSet<Block> blkList = bm.getNamedBeanSet(); 361 // don't return an element if there are no Blocks to include 362 if (blkList.isEmpty()) { 363 log.warn("no Blocks to convert"); // NOI18N 364 JOptionPane.showMessageDialog(desktopframe, Bundle.getMessage("ImportNoBlocks"), 365 Bundle.getMessage("InfoTitle"), JOptionPane.INFORMATION_MESSAGE); 366 return; 367 } else { 368 if (_showWarnings) { 369 int reply = JOptionPane.showOptionDialog(null, 370 Bundle.getMessage("ImportBlockConfirm", oblockPrefix(), blkList.size()), 371 Bundle.getMessage("QuestionTitle"), 372 JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, 373 new Object[]{Bundle.getMessage("ButtonYes"), 374 Bundle.getMessage("ButtonCancel")}, 375 Bundle.getMessage("ButtonYes")); // standard JOptionPane can't be found in Jemmy log4J 376 if (reply > 0) { 377 return; 378 } 379 } 380 } 381 for (Block b : blkList) { 382 try { 383 // read Block properties 384 String sName = b.getSystemName(); 385 String uName = b.getUserName(); 386 String blockNumber = sName.substring(sName.startsWith("IB:AUTO:") ? 8 : 3); 387 String oBlockName = oblockPrefix() + blockNumber; 388 String sensor = ""; 389 Sensor s = b.getSensor(); 390 if (s != null) { 391 sensor = s.getDisplayName(); 392 } 393 float length = b.getLengthMm(); // length is stored in Mm in OBlock.setLength(float) 394 int curve = b.getCurvature(); 395 List<Path> blockPaths = b.getPaths(); 396 String toBlockName; 397 Portal port = null; 398 int n = 0; 399 Portal prevPortal = null; 400 401 log.debug("start creating OBlock {} from Block {}", oBlockName, sName); 402 if ((uName != null) && (obm.getOBlock(uName) != null)) { 403 log.warn("an OBlock with this user name already exists, replacing {}", uName); 404 } 405 // create the OBlock by systemName 406 OBlock oBlock = obm.provideOBlock(oBlockName); 407 oBlock.setUserName(uName); 408 if (!sensor.isEmpty()) { 409 oBlock.setSensor(sensor); 410 } 411 oBlock.setMetricUnits(true); // length always stored in Mm in Block, so copy that for OBlock 412 oBlock.setLength(length); 413 oBlock.setCurvature(curve); 414 415 for (Path pa : blockPaths) { 416 log.debug("Start loop: Path {} on Block {}", n, oBlockName); 417 String toBlockNumber = pa.getBlock().getSystemName().substring(sName.startsWith("IB:AUTO:") ? 8 : 3); 418 toBlockName = oblockPrefix() + toBlockNumber; 419 String portalName = portalPrefix + toBlockNumber + "-" + blockNumber; // reversed name for new Portal 420 port = pom.getPortal(portalName); 421 if (port == null) { 422 portalName = portalPrefix + blockNumber + "-" + toBlockNumber; // normal name for new Portal 423 log.debug("new Portal {} on block {}, path #{}", portalName, toBlockName, n); 424 port = pom.providePortal(portalName); // normally, will create a new Portal 425 port.setFromBlock(oBlock, false); 426 port.setToBlock(obm.provideOBlock(toBlockName), false); // create one if required 427 } else { 428 log.debug("duplicate Portal {} on block {}, path #{}", portalName, toBlockName, n); 429 // Portal port already set 430 } 431 oBlock.addPortal(port); 432 433 // create OPath from this Path 434 OPath opa = new OPath(oBlock, "IP" + n++); // only needs to be unique within oBlock 435 opa.setLength(oBlock.getLengthMm()); // simple assumption, works for default OBlock/OPath 436 log.debug("new OPath #{} - {} on OBlock {}", n, opa.getName(), opa.getBlock().getDisplayName()); 437 oBlock.addPath(opa); // checks for duplicates, will add OPath to any Portals on oBlock as well 438 log.debug("number of paths: {}", oBlock.getPaths().size()); 439 440 // set _fromPortal and _toPortal for each OPath in OBlock 441 if (opa.getFromPortal() == null) { 442 opa.setFromPortal(port); 443 } 444 for (BeanSetting bs : pa.getSettings()) { 445 opa.addSetting(bs); 446 } 447 if ((opa.getToPortal() == null) && (prevPortal != null)) { 448 opa.setToPortal(prevPortal); 449 // leaves ToPortal in previously (first) created OPath n-1 empty 450 } 451 prevPortal = port; // remember the new portal for use as ToPortal in opposing OPath 452 // user must remove nonsense manually unless... 453 } 454 // we use the last FromPortal as ToPortal in OPath P0 455 OPath p0 = oBlock.getPathByName("IP0"); 456 if ((p0 != null) && (n > 1) && (p0.getToPortal() == null)) { 457 p0.setToPortal(port); 458 } 459 } catch (IllegalArgumentException iae) { 460 log.error("Could not convert Block {} to OBlock. {}", 461 b.getDisplayName(NamedBean.DisplayOptions.USERNAME_SYSTEMNAME), iae.getMessage()); 462 } 463 // finished setting up 1 OBlock 464 } 465 // add recursive Path elements to FromBlock/ToBlock 466 SortedSet<OBlock> oblkList = obm.getNamedBeanSet(); 467 for (OBlock oblk : oblkList) { 468 for (Portal po : oblk.getPortals()) { 469 OBlock oob = obm.getByUserName(po.getFromBlockName()); 470 if (oob !=null) { 471 oob.addPortal(po); 472 } 473 oob = obm.getByUserName(po.getToBlockName()); 474 if (oob !=null) { 475 oob.addPortal(po); 476 } 477 } 478 } 479 // storing and reloading will add in these items 480 WarrantTableAction.getDefault().errorCheck(); 481 if (_showWarnings) { 482 JOptionPane.showMessageDialog(null, 483 Bundle.getMessage("ImportBlockComplete", blkList.size(), oblkList.size()), 484 Bundle.getMessage("MessageTitle"), 485 JOptionPane.INFORMATION_MESSAGE); // standard JOptionPane can't be found in Jemmy log4J 486 } 487 } 488 // End of importBlocks() menu method 489 490 protected void setShowWarnings(String cmd) { 491 if (cmd.equals("ShowWarning")) { 492 _showWarnings = true; 493 _showWarnItem.setActionCommand("SuppressWarning"); 494 _showWarnItem.setText(Bundle.getMessage("SuppressWarning")); 495 } else { 496 _showWarnings = false; 497 _showWarnItem.setActionCommand("ShowWarning"); 498 _showWarnItem.setText(Bundle.getMessage("ShowWarning")); 499 } 500 log.debug("setShowWarnings: _showWarnings= {}", _showWarnings); 501 } 502 503 private void setUnits() { 504 _oBlockModel.changeUnits(); 505 _setUnits.setText(Bundle.getMessage("changeUnits", 506 (_oBlockModel.isMetric() ? Bundle.getMessage("LengthInches") : Bundle.getMessage("LengthCentimeters")))); 507 } 508 509 // listen for _desktopframe closing 510 void addCloseListener(JmriJFrame desktop) { 511 desktop.addWindowListener(new java.awt.event.WindowAdapter() { 512 @Override 513 public void windowClosing(java.awt.event.WindowEvent e) { 514 WarrantTableAction.getDefault().errorCheck(); 515 desktop.setDefaultCloseOperation(javax.swing.WindowConstants.HIDE_ON_CLOSE); 516 // closing instead of hiding removes name from Windows menu.handle menu to read Show... 517 log.debug("windowClosing: {}", toString()); 518 desktop.dispose(); 519 } 520 }); 521 } 522 523 private String getTitle() { 524 return _title; 525 } 526 527 private void setTitle(String title) { 528 _title = title; 529 } 530 531 /** 532 * Fill in the Open/Hide Tables menu on tablesMenu. 533 */ 534 protected void updateOBlockTablesMenu() { 535 if (tablesMenu == null) { 536 return; 537 } 538 tablesMenu.removeAll(); 539 if (!_tabbed) { // full menu in _desktop, open/show not available in _tabbed interface 540 // use string Bundle.getMessage("HideTable") to correct action in menu for all table open at start 541 openBlock = new JMenuItem(Bundle.getMessage("OpenBlockMenu", Bundle.getMessage("HideTable"))); 542 tablesMenu.add(openBlock); 543 openBlock.addActionListener(event -> showHideFrame(_blockTableFrame, openBlock, "OpenBlockMenu")); 544 545 openPortal = new JMenuItem(Bundle.getMessage("OpenPortalMenu", Bundle.getMessage("HideTable"))); 546 tablesMenu.add(openPortal); 547 openPortal.addActionListener(event -> showHideFrame(_portalTableFrame, openPortal, "OpenPortalMenu")); 548 549 openXRef = new JMenuItem(Bundle.getMessage("OpenXRefMenu", Bundle.getMessage("ShowTable"))); 550 tablesMenu.add(openXRef); 551 openXRef.addActionListener(event -> showHideFrame(_blockPortalXRefFrame, openXRef, "OpenXRefMenu")); 552 553 openSignal = new JMenuItem(Bundle.getMessage("OpenSignalMenu", Bundle.getMessage("ShowTable"))); 554 tablesMenu.add(openSignal); 555 openSignal.addActionListener(event -> showHideFrame(_signalTableFrame, openSignal, "OpenSignalMenu")); 556 } 557 558 OBlockManager manager = InstanceManager.getDefault(OBlockManager.class); 559 560 // Block-Path submenus 561 JMenu openBlockPath = new JMenu(Bundle.getMessage("OpenBlockPathMenu")); 562 ActionListener openFrameAction = e -> { 563 String blockSystemName = e.getActionCommand(); 564 openBlockPathPane(blockSystemName, Bundle.getMessage("TitlePaths")); // handles both interfaces 565 }; 566 567 if (manager.getNamedBeanSet().size() == 0) { 568 JMenuItem mi = new JMenuItem(Bundle.getMessage("NoBlockPathYet")); 569 mi.setEnabled(false); 570 openBlockPath.add(mi); 571 } else { 572 for (OBlock block : manager.getNamedBeanSet()) { 573 JMenuItem mi = new JMenuItem(Bundle.getMessage("OpenPathMenu", block.getDisplayName())); 574 mi.setActionCommand(block.getSystemName()); 575 mi.addActionListener(openFrameAction); 576 openBlockPath.add(mi); 577 } 578 } 579 tablesMenu.add(openBlockPath); 580 581 // Path-Turnout submenus 582 JMenu openTurnoutPath = new JMenu(Bundle.getMessage("OpenBlockPathTurnoutMenu")); 583 if (manager.getNamedBeanSet().size() == 0) { 584 JMenuItem mi = new JMenuItem(Bundle.getMessage("NoPathTurnoutYet")); 585 mi.setEnabled(false); 586 openTurnoutPath.add(mi); 587 } else { 588 for (OBlock block : manager.getNamedBeanSet()) { 589 JMenu openTurnoutMenu = new JMenu(Bundle.getMessage("OpenTurnoutMenu", block.getDisplayName())); 590 openTurnoutPath.add(openTurnoutMenu); 591 openFrameAction = e -> { 592 String pathTurnoutName = e.getActionCommand(); 593 openPathTurnoutEditPane(pathTurnoutName); // handles both interfaces 594 }; 595 for (Path p : block.getPaths()) { 596 if (p instanceof OPath) { 597 OPath path = (OPath) p; 598 JMenuItem mi = new JMenuItem(Bundle.getMessage("OpenPathTurnoutMenu", path.getName())); 599 mi.setActionCommand(makePathTurnoutName(block.getSystemName(), path.getName())); 600 mi.addActionListener(openFrameAction); 601 openTurnoutMenu.add(mi); 602 } 603 } 604 } 605 } 606 tablesMenu.add(openTurnoutPath); 607 } 608 609 public void openPathTurnoutEditPane(String pathTurnoutName) { 610 if (_tabbed) { 611 log.debug("openPathTurnoutEditPane for {}", pathTurnoutName); 612 openPathTurnoutEditor(pathTurnoutName); 613 } else { // stand alone frame only used for _desktop, created from/stored in Portal 614 openPathTurnoutFrame(pathTurnoutName); 615 } 616 } 617 618 /** 619 * Show or hide a table in the _desktop interface. 620 * 621 * @param frame JInternalFrame to show (or hide, name property value contains {} var handled by frame) 622 * @param menu menu item object 623 * @param menuName base i18n string containing table name 624 */ 625 private void showHideFrame(JInternalFrame frame, JMenuItem menu, String menuName) { 626 if (!frame.isVisible()) { 627 frame.setVisible(true); 628 try { 629 frame.setIcon(false); 630 } catch (PropertyVetoException pve) { 631 log.warn("{} Frame vetoed setIcon {}", frame.getTitle(), pve.toString()); 632 } 633 frame.moveToFront(); 634 } else { 635 frame.setVisible(false); 636 } 637 menu.setText(Bundle.getMessage(menuName, 638 (frame.isVisible() ? Bundle.getMessage("HideTable") : Bundle.getMessage("ShowTable")))); 639 } 640 641 /** 642 * Wrapper for shared code around each Table in a JInternal window on _desktop interface. 643 * 644 * @param tableModel underlying model for the table 645 * @param title text displayed as title of frame 646 * @param prompt text below bottom line 647 * @return iframe to put on _desktop interface 648 */ 649 protected JInternalFrame buildFrame(AbstractTableModel tableModel, String title, String prompt) { 650 JInternalFrame iframe = new JInternalFrame(title, true, false, false, true); 651 652 // specifics for table 653 JTable table = new JTable(); 654 if (tableModel instanceof OBlockTableModel) { 655 table = makeOBlockTable((OBlockTableModel) tableModel); 656 } else if (tableModel instanceof PortalTableModel) { 657 table = makePortalTable((PortalTableModel) tableModel); 658 } else if (tableModel instanceof BlockPortalTableModel) { 659 table = makeBlockPortalTable((BlockPortalTableModel) tableModel); 660 } else if (tableModel instanceof SignalTableModel) { 661 table = makeSignalTable((SignalTableModel) tableModel); 662 } // no case here for BlockPathTableModel, it is handled directly from OBlockTable 663 664 JScrollPane scroll = new JScrollPane(table); 665 JPanel contentPane = new JPanel(); 666 contentPane.setLayout(new BorderLayout(5, 5)); 667 JLabel _prompt = new JLabel(prompt); 668 contentPane.add(_prompt, BorderLayout.NORTH); 669 contentPane.add(scroll, BorderLayout.CENTER); 670 671 iframe.setContentPane(contentPane); 672 iframe.pack(); 673 return iframe; 674 } 675 676 /* 677 * ********************* OBlock Table for _desktop **************** 678 */ 679 protected JTable makeOBlockTable(OBlockTableModel model) { 680 _oBlockTable = new JTable(model); 681 TableRowSorter<OBlockTableModel> sorter = new TableRowSorter<>(_oBlockModel); 682 // use NamedBean's built-in Comparator interface for sorting 683 _oBlockTable.setRowSorter(sorter); 684 _oBlockTable.setTransferHandler(new jmri.util.DnDTableImportExportHandler(new int[]{OBlockTableModel.EDIT_COL, 685 OBlockTableModel.DELETE_COL, OBlockTableModel.REPORT_CURRENTCOL, OBlockTableModel.SPEEDCOL, 686 OBlockTableModel.PERMISSIONCOL, OBlockTableModel.UNITSCOL})); 687 _oBlockTable.setDragEnabled(true); 688 689 // Use XTableColumnModel so we can control which columns are visible 690 XTableColumnModel tcm = new XTableColumnModel(); 691 _oBlockTable.setColumnModel(tcm); 692 _oBlockTable.getTableHeader().setReorderingAllowed(true); 693 _oBlockTable.createDefaultColumnsFromModel(); 694 _oBlockModel.addHeaderListener(_oBlockTable); 695 696 _oBlockTable.setDefaultEditor(JComboBox.class, new jmri.jmrit.symbolicprog.ValueEditor()); 697 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.EDIT_COL).setCellEditor(new ButtonEditor(new JButton())); 698 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.EDIT_COL).setCellRenderer(new ButtonRenderer()); 699 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.DELETE_COL).setCellEditor(new ButtonEditor(new JButton())); 700 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.DELETE_COL).setCellRenderer(new ButtonRenderer()); 701 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.UNITSCOL).setCellRenderer( 702 new ToggleButtonRenderer(Bundle.getMessage("cm"), Bundle.getMessage("in"))); 703 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.UNITSCOL).setCellEditor( 704 new ToggleButtonEditor(new JToggleButton(), Bundle.getMessage("cm"), Bundle.getMessage("in"))); 705 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.REPORT_CURRENTCOL).setCellRenderer( 706 new ToggleButtonRenderer(Bundle.getMessage("Current"), Bundle.getMessage("Last"))); 707 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.REPORT_CURRENTCOL).setCellEditor( 708 new ToggleButtonEditor(new JToggleButton(), Bundle.getMessage("Current"), Bundle.getMessage("Last"))); 709 model.configSpeedColumn(_oBlockTable); // use real combo 710 // JComboBox<String> box = new JComboBox<>(OBlockTableModel.curveOptions); 711 // _oBlockTable.getColumnModel().getColumn(OBlockTableModel.CURVECOL).setCellEditor(new DefaultCellEditor(box)); 712 model.configCurveColumn(_oBlockTable); // use real combo 713 // box = new JComboBox<>(jmri.InstanceManager.getDefault(SignalSpeedMap.class).getValidSpeedNames()); 714// box.addItem(""); 715// _oBlockTable.getColumnModel().getColumn(OBlockTableModel.SPEEDCOL).setCellRenderer(new DefaultCellRenderer(new _oBlockModel.SpeedComboBoxPanel())); 716// _oBlockTable.getColumnModel().getColumn(OBlockTableModel.SPEEDCOL).setCellEditor(new DefaultCellEditor(box)); 717 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.PERMISSIONCOL).setCellRenderer( 718 new ToggleButtonRenderer(Bundle.getMessage("Permissive"), Bundle.getMessage("Absolute"))); 719 _oBlockTable.getColumnModel().getColumn(OBlockTableModel.PERMISSIONCOL).setCellEditor( 720 new ToggleButtonEditor(new JToggleButton(), Bundle.getMessage("Permissive"), Bundle.getMessage("Absolute"))); 721 _oBlockTable.addMouseListener(new MouseAdapter() { 722 @Override 723 public void mousePressed(MouseEvent me) { // for macOS, Linux 724 showPopup(me); 725 } 726 727 @Override 728 public void mouseReleased(MouseEvent me) { // for Windows 729 showPopup(me); 730 } 731 }); 732 733 for (int i = 0; i < _oBlockModel.getColumnCount(); i++) { 734 int width = _oBlockModel.getPreferredWidth(i); 735 _oBlockTable.getColumnModel().getColumn(i).setPreferredWidth(width); 736 } 737 _oBlockTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 738 _oBlockTable.setRowHeight(ROW_HEIGHT); 739 740 TableColumn column = tcm.getColumnByModelIndex(OBlockTableModel.REPORTERCOL); 741 tcm.setColumnVisible(column, false); 742 column = tcm.getColumnByModelIndex(OBlockTableModel.REPORT_CURRENTCOL); 743 tcm.setColumnVisible(column, false); 744 column = tcm.getColumnByModelIndex(OBlockTableModel.PERMISSIONCOL); 745 tcm.setColumnVisible(column, false); 746 column = tcm.getColumnByModelIndex(OBlockTableModel.ERR_SENSORCOL); 747 tcm.setColumnVisible(column, false); 748 column = tcm.getColumnByModelIndex(OBlockTableModel.CURVECOL); 749 tcm.setColumnVisible(column, false); 750 751 _oBlockTable.setPreferredScrollableViewportSize(new java.awt.Dimension(_oBlockTable.getPreferredSize().width, 752 ROW_HEIGHT * Math.min(20, InstanceManager.getDefault(OBlockManager.class).getObjectCount()))); 753 return _oBlockTable; 754 } 755 756 private void showPopup(MouseEvent me) { 757 Point p = me.getPoint(); 758 int col = _oBlockTable.columnAtPoint(p); 759 if (!me.isPopupTrigger() && !me.isMetaDown() && !me.isAltDown() && col == OBlockTableModel.STATECOL) { 760 int row = _oBlockTable.rowAtPoint(p); 761 String stateStr = (String) _oBlockModel.getValueAt(row, col); 762 int state = Integer.parseInt(stateStr, 2); 763 stateStr = OBlockTableModel.getValue(state); 764 JPopupMenu popupMenu = new JPopupMenu(); 765 popupMenu.add(new JMenuItem(stateStr)); 766 popupMenu.show(_oBlockTable, me.getX(), me.getY()); 767 } 768 } 769 770 // Opens the Edit OBlock panel for _tabbed 771 protected boolean openOBlockEditor(String blockSystemName, String tabname) { 772 boolean result = false; 773 if (blockSystemName != null) { 774 // this is for Edit (new OBlocks are created from [Add OBlock...] button in table) 775 OBlock oblock = InstanceManager.getDefault(OBlockManager.class).getBySystemName(blockSystemName); 776 if (oblock != null) { 777 BlockPathJPanel panel = makeBlockPathEditPanel(oblock); 778 // BeanEdit UI, adapted from jmri.jmrit.beantable.BlockTableAction 779 jmri.jmrit.beantable.beanedit.OBlockEditAction beanEdit = new jmri.jmrit.beantable.beanedit.OBlockEditAction(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, tabname)); 780 beanEdit.setBean(oblock); 781 beanEdit.setTablePanel(panel); 782 beanEdit.actionPerformed(null); 783 // run on separate thread? does not update new Paths in table! 784 // class WindowMaker implements Runnable { 785 // final OBlock ob; 786 // final BlockPathJPanel panel; 787 // WindowMaker(OBlock oblock, BlockPathJPanel panel) { 788 // ob = oblock; 789 // this.panel = panel; 790 // } 791 // @Override 792 // public void run() { 793 // jmri.jmrit.beantable.beanedit.OBlockEditAction beanEdit = new jmri.jmrit.beantable.beanedit.OBlockEditAction(); 794 // beanEdit.setBean(oblock); 795 // beanEdit.setTablePanel(panel); 796 // beanEdit.actionPerformed(null); 797 // } 798 // } 799 // WindowMaker t = new WindowMaker(oblock, panel); 800 // javax.swing.SwingUtilities.invokeLater(t); 801 log.debug("path table created for oblock {}", blockSystemName); 802 result = true; 803 } 804 } 805 return result; 806 } 807 808 /** 809 * Open the Edit Path panel for _tabbed. 810 * Compare with openOBlockEditor(block, selectedtabname) and OBlockTableAction. 811 * 812 * @param blockName system or user name of the owning oblock 813 * @param pathName name of the path under edit, or null to create a new path 814 * @param bpmodel blockpathtablemodel that should be informed about changes 815 * @return true if successful 816 */ 817 protected boolean openPathEditor(@Nonnull String blockName, @CheckForNull String pathName, BlockPathTableModel bpmodel) { 818 OBlock block = InstanceManager.getDefault(OBlockManager.class).getOBlock(blockName); 819 if (block == null) { 820 log.error("OBlock {} not found", blockName); 821 return false; 822 } 823 OPath path; 824 String title; 825 PathTurnoutJPanel turnouttable = makePathTurnoutPanel(block, pathName); // shows the turnouts on path, includes Add Turnout button, checks for null path 826 if (pathName == null) { // new Path, empty TurnoutTable 827 // a new Path is created from [Add Path...] button in Path table on OBlock Editor pane. 828 path = null; 829 title = Bundle.getMessage("AddPathTitle", blockName); 830 } else { 831 path = block.getPathByName(pathName); 832 title = Bundle.getMessage("EditPathTitle", pathName, blockName); 833 } 834 BlockPathEditFrame bpef = new BlockPathEditFrame(title, block, path, turnouttable, bpmodel, this); 835 bpef.setVisible(true); 836 // run on separate thread? combos are final, difficult to store Partals in Path/see them show up in the table 837 // class WindowMaker implements Runnable { 838 // final String title; 839 // final OBlock ob; 840 // final OPath path; 841 // final PathTurnoutTableModel tomodel; 842 // final BlockPathTableModel bpmodel; 843 // final TableFrames parent; 844 // WindowMaker(String title, OBlock ob, OPath path, PathTurnoutTableModel turnoutmodel, BlockPathTableModel blockpathmodel, TableFrames tf) { 845 // this.title = title; 846 // this.ob = ob; 847 // this.path = path; 848 // this.tomodel = turnoutmodel; 849 // this.bpmodel = blockpathmodel; 850 // parent = tf; 851 // } 852 // @Override 853 // public void run() { 854 // BlockPathEditFrame bpef = new BlockPathEditFrame(title, block, path, turnouttable, bpmodel, parent); 855 // bpef.setVisible(true); 856 // } 857 // } 858 // WindowMaker t = new WindowMaker(title, block, path, turnouttable.getModel(), bpmodel, this); 859 // javax.swing.SwingUtilities.invokeLater(t); 860 861 log.debug("Path editor created for path {} on block {}", pathName, blockName); 862 return true; 863 } 864 865 /* 866 * ********************* PortalTable for _desktop ***************************** 867 */ 868 protected JTable makePortalTable(PortalTableModel model) { 869 _portalTable = new JTable(model); 870 TableRowSorter<PortalTableModel> sorter = new TableRowSorter<>(model); 871 _portalTable.setRowSorter(sorter); 872 _portalTable.setTransferHandler(new jmri.util.DnDTableImportExportHandler(new int[]{PortalTableModel.DELETE_COL})); 873 _portalTable.setDragEnabled(true); 874 875 _portalTable.getColumnModel().getColumn(PortalTableModel.DELETE_COL).setCellEditor(new ButtonEditor(new JButton())); 876 _portalTable.getColumnModel().getColumn(PortalTableModel.DELETE_COL).setCellRenderer(new ButtonRenderer()); 877 for (int i = 0; i < model.getColumnCount(); i++) { 878 int width = model.getPreferredWidth(i); 879 _portalTable.getColumnModel().getColumn(i).setPreferredWidth(width); 880 } 881 _portalTable.doLayout(); 882 int tableWidth = _portalTable.getPreferredSize().width; 883 _portalTable.setRowHeight(ROW_HEIGHT); 884 _portalTable.setPreferredScrollableViewportSize(new java.awt.Dimension(tableWidth, 885 ROW_HEIGHT * Math.min(20, InstanceManager.getDefault(PortalManager.class).getPortalCount()))); 886 return _portalTable; 887 } 888 889 /* 890 * ********************* Block-Portal (XRef) Table for _desktop ***************************** 891 */ 892 protected JTable makeBlockPortalTable(BlockPortalTableModel model) { 893 _blockPortalTable = new JTable(model); 894 _blockPortalTable.setTransferHandler(new jmri.util.DnDTableExportHandler()); 895 _blockPortalTable.setDragEnabled(true); 896 897 _blockPortalTable.setDefaultRenderer(String.class, new jmri.jmrit.symbolicprog.ValueRenderer()); 898 _blockPortalTable.setDefaultEditor(String.class, new jmri.jmrit.symbolicprog.ValueEditor()); // useful on non-editable cell? 899 for (int i = 0; i < model.getColumnCount(); i++) { 900 int width = model.getPreferredWidth(i); 901 _blockPortalTable.getColumnModel().getColumn(i).setPreferredWidth(width); 902 } 903 _blockPortalTable.doLayout(); 904 _blockPortalTable.setRowHeight(ROW_HEIGHT); 905 int tableWidth = _blockPortalTable.getPreferredSize().width; 906 _blockPortalTable.setPreferredScrollableViewportSize(new java.awt.Dimension(tableWidth, 907 ROW_HEIGHT * Math.min(20, InstanceManager.getDefault(PortalManager.class).getPortalCount()))); 908 909 return _blockPortalTable; 910 } 911 912 /* 913 * ********************* Signal Table for _desktop ***************************** 914 */ 915 protected JTable makeSignalTable(SignalTableModel model) { 916 _signalTable = new JTable(model); 917 TableRowSorter<SignalTableModel> sorter = new TableRowSorter<>(model); 918 _signalTable.setRowSorter(sorter); 919 _signalTable.setTransferHandler(new jmri.util.DnDTableImportExportHandler( 920 new int[]{SignalTableModel.UNITSCOL, SignalTableModel.DELETE_COL})); 921 _signalTable.setDragEnabled(true); 922 923 _signalTable.getColumnModel().getColumn(SignalTableModel.UNITSCOL).setCellRenderer( 924 new ToggleButtonRenderer(Bundle.getMessage("cm"), Bundle.getMessage("in"))); 925 _signalTable.getColumnModel().getColumn(SignalTableModel.UNITSCOL).setCellEditor( 926 new ToggleButtonEditor(new JToggleButton(), Bundle.getMessage("cm"), Bundle.getMessage("in"))); 927 _signalTable.getColumnModel().getColumn(SignalTableModel.DELETE_COL).setCellEditor(new ButtonEditor(new JButton())); 928 _signalTable.getColumnModel().getColumn(SignalTableModel.DELETE_COL).setCellRenderer(new ButtonRenderer()); 929 for (int i = 0; i < model.getColumnCount(); i++) { 930 int width = SignalTableModel.getPreferredWidth(i); 931 _signalTable.getColumnModel().getColumn(i).setPreferredWidth(width); 932 } 933 _signalTable.doLayout(); 934 int tableWidth = _signalTable.getPreferredSize().width; 935 _signalTable.setRowHeight(ROW_HEIGHT); 936 _signalTable.setPreferredScrollableViewportSize(new java.awt.Dimension(tableWidth, 937 ROW_HEIGHT * Math.min(10, _signalTable.getRowCount()))); 938 return _signalTable; 939 } 940 941 /* 942 * ***************** end of permanent Tables + InternalFrame definitions ***************** 943 */ 944 945 946 /* 947 * ***************** On Demand Tables + InternalFrame definitions ***************** 948 */ 949 950 /* 951 * ********************* Block-Path Frame ***************************** 952 */ 953 954 // called from Tables menu and the OBlockTable EDIT buttons 955 public void openBlockPathPane(String blockSystemName, String editorTabName) { 956 if (_tabbed) { 957 if (!openOBlockEditor(blockSystemName, editorTabName)) { 958 // pass on to Per OBlock Edit panel, includes a BlockPath table 959 log.error("Failed to open OBlock Path table for {}", blockSystemName); 960 } 961 } else { 962 openBlockPathFrame(blockSystemName); // an editable table of all paths on this block 963 } 964 } 965 966 // ***************** Block-Path Frame for _desktop ************************** 967 /** 968 * Open a block-specific Block-Path table in _desktop interface. 969 * 970 * @param blockSystemName of the OBlock 971 */ 972 protected void openBlockPathFrame(String blockSystemName) { 973 BlockPathFrame frame = _blockPathMap.get(blockSystemName); 974 if (frame == null) { 975 OBlock block = InstanceManager.getDefault(OBlockManager.class).getBySystemName(blockSystemName); 976 if (block == null) { 977 return; 978 } 979 frame = makeBlockPathFrame(block); 980 // store frame in Map 981 _blockPathMap.put(blockSystemName, frame); 982 frame.setVisible(true); 983 desktopframe.getContentPane().add(frame); 984 } else { 985 frame.setVisible(true); 986 try { 987 frame.setIcon(false); 988 } catch (PropertyVetoException pve) { 989 log.warn("BlockPath Table Frame for \"{}\" vetoed setIcon", blockSystemName, pve); 990 } 991 } 992 frame.moveToFront(); 993 } 994 995 // common dispose 996 protected void disposeBlockPathFrame(OBlock block) { 997 if (!_tabbed) { 998 //BlockPathFrame frame = _blockPathMap.get(block.getSystemName()); 999 // TODO frame.getModel().removeListener(); 1000 //_blockPathMap.remove(block.getSystemName()); // block not stored in map, required to remove listener? 1001 // frame.dispose(); not required (closeable window) 1002 //} else { 1003 BlockPathFrame frame = _blockPathMap.get(block.getSystemName()); 1004 frame.getModel().removeListener(); 1005 _blockPathMap.remove(block.getSystemName()); 1006 frame.dispose(); 1007 } 1008 } 1009 1010 // *************** Block-Path InternalFrame for _desktop *********************** 1011 1012 protected BlockPathFrame makeBlockPathFrame(OBlock block) { 1013 String title = Bundle.getMessage("TitleBlockPathTable", block.getDisplayName()); 1014 // create table 1015 BlockPathTableModel model = new BlockPathTableModel(block, this); 1016 JPanel contentPane = makeBlockPathTablePanel(model); 1017 1018 BlockPathFrame frame = new BlockPathFrame(title, true, true, false, true); 1019 frame.setModel(model, block.getSystemName()); 1020 frame.addInternalFrameListener(this); 1021 frame.setContentPane(contentPane); 1022 //frame.setClosable(true); // set in ctor 1023 frame.setLocation(50, 30); 1024 frame.pack(); 1025 return frame; 1026 } 1027 1028 // *************** Block-Path Edit Panel for _tabbed *********************** 1029 1030 protected BlockPathJPanel makeBlockPathEditPanel(OBlock block) { 1031 // Path Table placed on jmri.jmrit.beanedit OBlockEditAction - Paths tab 1032 String title = Bundle.getMessage("TitleBlockPathEditor", block.getDisplayName()); 1033 // create table 1034 BlockPathTableModel model = new BlockPathTableModel(block, this); 1035 JPanel bpTablePane = makeBlockPathTablePanel(model); 1036 BlockPathJPanel panel = new BlockPathJPanel(title); 1037 panel.setModel(model, block.getSystemName()); 1038 panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); 1039 panel.add(bpTablePane); 1040 1041 // Add Path Button 1042 JPanel tblButtons = new JPanel(); 1043 tblButtons.setLayout(new BorderLayout(10, 10)); 1044 tblButtons.setBorder(BorderFactory.createEmptyBorder(2, 10, 2, 10)); 1045 tblButtons.setLayout(new BoxLayout(tblButtons, BoxLayout.Y_AXIS)); 1046 1047 JButton addPathButton = new JButton(Bundle.getMessage("ButtonAddPath")); 1048 ActionListener addPathAction = e -> { 1049 // New Path uses the same editor pane as Edit Path 1050 if (!isPathEdit()) { 1051 setPathEdit(true); 1052 log.debug("makeBlockPathEditPanel pathEdit=True"); 1053 openPathEditor(block.getDisplayName(), null, model); 1054 } else { 1055 log.warn("Close BlockPath Editor to reopen"); 1056 } 1057 }; 1058 addPathButton.addActionListener(addPathAction); 1059 addPathButton.setToolTipText(Bundle.getMessage("AddPathTabbedPrompt")); 1060 tblButtons.add(addPathButton); 1061 panel.add(tblButtons); 1062 1063 //panel.pack(); 1064 return panel; 1065 } 1066 1067 // prevent more than 1 edit pane being opened at the same time 1068 protected void setPathEdit(boolean edit) { 1069 pathEdit = edit; 1070 } 1071 1072 protected boolean isPathEdit() { 1073 return pathEdit; 1074 } 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, maxHeight))); 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, maxHeight))); 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; 1402 p.add(ok = new JButton(Bundle.getMessage("ButtonOK"))); // no need to save things, handled by TurnoutTable 1403 ok.addActionListener((ActionEvent 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; 1456 btns.add(cancel = new JButton(Bundle.getMessage("ButtonCancel"))); 1457 cancel.addActionListener((ActionEvent e) -> frame.dispose()); 1458 JButton ok; 1459 btns.add(ok = new JButton(Bundle.getMessage("ButtonOK"))); 1460 ok.addActionListener((ActionEvent 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 = JOptionPane.showOptionDialog(null, 1502 message, Bundle.getMessage("WarningTitle"), 1503 JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.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 JOptionPane.showMessageDialog(desktopframe, msg, 1544 Bundle.getMessage("InfoTitle"), JOptionPane.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 JOptionPane.showMessageDialog(desktopframe, msg, 1579 Bundle.getMessage("InfoTitle"), JOptionPane.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 final static Logger log = LoggerFactory.getLogger(TableFrames.class); 1603 1604}