001package jmri.jmrit.display.controlPanelEditor; 002 003import java.awt.Component; 004import java.awt.Dimension; 005import java.awt.FlowLayout; 006import java.beans.PropertyChangeEvent; 007import java.beans.PropertyChangeListener; 008import java.awt.event.ActionEvent; 009import java.util.ArrayList; 010import java.util.Iterator; 011import java.util.stream.Collectors; 012 013import javax.swing.AbstractListModel; 014import javax.swing.Box; 015import javax.swing.BoxLayout; 016import javax.swing.JButton; 017import javax.swing.JComponent; 018import javax.swing.JLabel; 019import javax.swing.JList; 020import javax.swing.JPanel; 021import javax.swing.JScrollPane; 022import javax.swing.JTextField; 023import javax.swing.ListCellRenderer; 024import javax.swing.event.ListSelectionEvent; 025import javax.swing.event.ListSelectionListener; 026 027import jmri.BeanSetting; 028import jmri.Path; 029import jmri.Sensor; 030import jmri.Turnout; 031import jmri.jmrit.display.IndicatorTrack; 032import jmri.jmrit.display.IndicatorTurnoutIcon; 033import jmri.jmrit.display.Positionable; 034import jmri.jmrit.logix.OBlock; 035import jmri.jmrit.logix.OPath; 036import jmri.jmrit.logix.Portal; 037import jmri.util.swing.JmriJOptionPane; 038 039/** 040 * @author Pete Cressman Copyright: Copyright (c) 2011 041 * 042 */ 043public class EditCircuitPaths extends EditFrame implements ListSelectionListener { 044 045 // mouse selections of track icons that define the path 046 private ArrayList<Positionable> _pathGroup = new ArrayList<>(); 047 private ArrayList<Positionable> _savePathGroup = new ArrayList<>(); 048 049 private JTextField _pathName; 050 private JList<OPath> _pathList; 051 private PathListModel _pathListModel; 052 private OPath _currentPath; 053 054 private LengthPanel _lengthPanel; 055 public static final String TEST_PATH = "TEST_PATH"; 056 057 public EditCircuitPaths(String title, CircuitBuilder parent, OBlock block) { 058 super(title, parent, block); 059 checkCircuitIcons("BlockPaths"); 060 pack(); 061 } 062 063 @Override 064 protected JPanel makeContentPanel() { 065 JPanel pathPanel = new JPanel(); 066 pathPanel.setLayout(new BoxLayout(pathPanel, BoxLayout.Y_AXIS)); 067 068 pathPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 069 JPanel panel = new JPanel(); 070 panel.add(new JLabel(Bundle.getMessage("PathTitle", _homeBlock.getDisplayName()))); 071 pathPanel.add(panel); 072 073 _pathListModel = new PathListModel(this); 074 _pathList = new JList<>(); 075 _pathList.setModel(_pathListModel); 076 _pathList.addListSelectionListener(this); 077 _homeBlock.addPropertyChangeListener(_pathListModel); 078 079 _pathList.setCellRenderer(new PathCellRenderer()); 080 _pathList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); 081 pathPanel.add(new JScrollPane(_pathList)); 082 pathPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 083 084 panel = new JPanel(); 085 panel.setLayout(new FlowLayout()); 086 087 JButton clearButton = new JButton(Bundle.getMessage("buttonClearSelection")); 088 clearButton.addActionListener((ActionEvent a) -> clearListSelection()); 089 clearButton.setToolTipText(Bundle.getMessage("ToolTipClearList")); 090 panel.add(clearButton); 091 pathPanel.add(panel); 092 pathPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 093 094 panel = new JPanel(); 095 _pathName = new JTextField(); 096 panel.add(CircuitBuilder.makeTextBoxPanel( 097 false, _pathName, "pathName", true, "TooltipPathName")); 098 _pathName.setPreferredSize(new Dimension(300, _pathName.getPreferredSize().height)); 099 pathPanel.add(panel); 100 101 panel = new JPanel(); 102 JButton addButton = new JButton(Bundle.getMessage("buttonAddPath")); 103 addButton.addActionListener((ActionEvent a) -> addNewPath(true)); 104 addButton.setToolTipText(Bundle.getMessage("ToolTipAddPath")); 105 panel.add(addButton); 106 107 JButton changeButton = new JButton(Bundle.getMessage("buttonChangeName")); 108 changeButton.addActionListener((ActionEvent a) -> changePathName()); 109 changeButton.setToolTipText(Bundle.getMessage("ToolTipChangeName")); 110 panel.add(changeButton); 111 112 JButton deleteButton = new JButton(Bundle.getMessage("buttonDeletePath")); 113 deleteButton.addActionListener((ActionEvent a) -> deletePath()); 114 deleteButton.setToolTipText(Bundle.getMessage("ToolTipDeletePath")); 115 panel.add(deleteButton); 116 117 pathPanel.add(panel); 118 pathPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 119 120 _lengthPanel = new LengthPanel(_homeBlock, LengthPanel.PATH_LENGTH, "TooltipPathLength"); 121 pathPanel.add(_lengthPanel); 122 pathPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 123 124 panel = new JPanel(); 125 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 126 JLabel l = new JLabel(Bundle.getMessage("enterNewPath")); 127 l.setAlignmentX(JComponent.LEFT_ALIGNMENT); 128 panel.add(l); 129 l = new JLabel(Bundle.getMessage("selectPathIcons")); 130 l.setAlignmentX(JComponent.LEFT_ALIGNMENT); 131 panel.add(l); 132 l = new JLabel(Bundle.getMessage("pressAddButton", Bundle.getMessage("buttonAddPath"))); 133 l.setAlignmentX(JComponent.LEFT_ALIGNMENT); 134 panel.add(l); 135 panel.add(Box.createVerticalStrut(STRUT_SIZE / 2)); 136 l = new JLabel(Bundle.getMessage("selectPath")); 137 l.setAlignmentX(JComponent.LEFT_ALIGNMENT); 138 panel.add(l); 139 l = new JLabel(Bundle.getMessage("editPathIcons")); 140 l.setAlignmentX(JComponent.LEFT_ALIGNMENT); 141 panel.add(l); 142 panel.add(Box.createVerticalStrut(STRUT_SIZE / 2)); 143 l = new JLabel(Bundle.getMessage("throwPathTO")); 144 l.setAlignmentX(JComponent.LEFT_ALIGNMENT); 145 panel.add(l); 146 l = new JLabel(Bundle.getMessage("holdShiftDown")); 147 l.setAlignmentX(JComponent.LEFT_ALIGNMENT); 148 panel.add(l); 149 JPanel p = new JPanel(); 150 p.add(panel); 151 pathPanel.add(p); 152 153 pathPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 154 pathPanel.add(makeDoneButtonPanel()); 155 _lengthPanel.changeUnits(); 156 return pathPanel; 157 } 158 159 private static class PathCellRenderer extends JLabel implements ListCellRenderer<OPath> { 160 161 @Override 162 public Component getListCellRendererComponent( 163 JList<? extends OPath> list, // the list 164 OPath value, // value to display 165 int index, // cell index 166 boolean isSelected, // is the cell selected 167 boolean cellHasFocus) // does the cell have focus 168 { 169 String s = value.getDescription(); 170 setText(s); 171 if (isSelected) { 172 setBackground(list.getSelectionBackground()); 173 setForeground(list.getSelectionForeground()); 174 } else { 175 setBackground(list.getBackground()); 176 setForeground(list.getForeground()); 177 } 178 setEnabled(list.isEnabled()); 179 setFont(list.getFont()); 180 setOpaque(true); 181 return this; 182 } 183 } 184 185 class PathListModel extends AbstractListModel<OPath> implements PropertyChangeListener { 186 187 EditFrame _parent; 188 189 PathListModel(EditFrame parent) { 190 _parent = parent; 191 } 192 193 @Override 194 public int getSize() { 195 return _homeBlock.getPaths().size(); 196 } 197 198 @Override 199 public OPath getElementAt(int index) { 200 return (OPath) _homeBlock.getPaths().get(index); 201 } 202 203 public void dataChange() { 204 fireContentsChanged(this, 0, 0); 205 } 206 207 @Override 208 public void propertyChange(PropertyChangeEvent e) { 209 if (e.getPropertyName().equals("deleted")) { 210 _parent.closingEvent(true); 211 } 212 fireContentsChanged(this, 0, 0); 213 } 214 } 215 216 @Override 217 public void valueChanged(ListSelectionEvent e) { 218 OPath path = _pathList.getSelectedValue(); 219 if (log.isDebugEnabled()) { 220 log.debug("valueChanged from _currentPath \"{}\" to path \"{}\"", 221 (_currentPath==null?"null":_currentPath.getName()), (path==null?"null":path.getName())); 222 } 223 String msg = checkForSavePath(); 224 if (msg.length() > 0) { 225 StringBuilder sb = new StringBuilder (msg); 226 sb.append("\n"); 227 sb.append(Bundle.getMessage("saveChanges")); 228 int answer = JmriJOptionPane.showConfirmDialog(this, sb.toString(), Bundle.getMessage("makePath"), 229 JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.QUESTION_MESSAGE); 230 if (answer == JmriJOptionPane.YES_OPTION) { 231 addNewPath(false); 232 } 233 } 234 clearPath(false); 235 _currentPath = path; 236 if (path != null) { 237 _pathName.setText(path.getName()); 238 _lengthPanel.setLength(path.getLengthMm()); 239 _pathGroup = showPath(path); 240 updatePath(); 241 } else { 242 _pathName.setText(null); 243 _lengthPanel.setLength(0); 244 } 245 int oldState = _homeBlock.getState(); 246 int newState = oldState | OBlock.ALLOCATED; 247 _homeBlock.pseudoPropertyChange("state", oldState, newState); 248 } 249 250 private ArrayList<Positionable> showPath(OPath path) { 251 if (log.isDebugEnabled()) { 252 log.debug("showPath \"{}\"", path.getName()); 253 } 254 path.setTurnouts(0, true, 0, false); 255 ArrayList<Positionable> pathGp = makePathGroup(path); 256 _savePathGroup = new ArrayList<>(); 257 for (Positionable pos :pathGp) { 258 _savePathGroup.add(pos); 259 } 260 return pathGp; 261 } 262 263 /** 264 * Construct the array of icons that displays the path 265 * <p> 266 */ 267 private ArrayList<Positionable> makePathGroup(OPath path) { 268 Portal fromPortal = path.getFromPortal(); 269 Portal toPortal = path.getToPortal(); 270 String name = path.getName(); 271 272 java.util.List<Positionable> list = _parent.getCircuitIcons(_homeBlock); 273 ArrayList<Positionable> pathGroup = new ArrayList<>(); 274 for (Positionable pos : list) { 275 if (pos instanceof IndicatorTrack) { 276 ArrayList<String> paths = ((IndicatorTrack) pos).getPaths(); 277 if (paths != null) { 278 for (String s : paths) { 279 if (name.equals(s)) { 280 ((IndicatorTrack) pos).setControlling(true); 281 pathGroup.add(pos); 282 } 283 } 284 } 285 } else if (pos instanceof PortalIcon) { 286 PortalIcon icon = (PortalIcon) pos; 287 Portal portal = icon.getPortal(); 288 if (portal.equals(fromPortal)) { 289 pathGroup.add(icon); 290 } else if (portal.equals(toPortal)) { 291 pathGroup.add(icon); 292 } 293 } 294 } 295 if (log.isDebugEnabled()) { 296 log.debug("makePathGroup for path \"{}\" from CircuitGroup size {} pathGroup size {}", name, list.size(), pathGroup.size()); 297 } 298 return pathGroup; 299 } 300 301 /** 302 * Can a path in this circuit be drawn through this icon? 303 */ 304 private boolean okPath(Positionable pos) { 305 if (pos instanceof PortalIcon) { 306 Portal portal = ((PortalIcon) pos).getPortal(); 307 if (portal != null) { 308 if (_homeBlock.equals(portal.getFromBlock()) || _homeBlock.equals(portal.getToBlock())) { 309 ((PortalIcon) pos).setStatus(PortalIcon.PATH); 310 return true; 311 } 312 } 313 JmriJOptionPane.showMessageDialog(this, java.text.MessageFormat.format( 314 Bundle.getMessage("portalNotInCircuit"), _homeBlock.getDisplayName()), 315 Bundle.getMessage("badPath"), JmriJOptionPane.WARNING_MESSAGE); 316 return false; 317 } 318 java.util.List<Positionable> icons = _parent.getCircuitIcons(_homeBlock); 319 if (!icons.contains(pos)) { 320 JmriJOptionPane.showMessageDialog(this, java.text.MessageFormat.format( 321 Bundle.getMessage("iconNotInCircuit"), _homeBlock.getDisplayName()), 322 Bundle.getMessage("badPath"), JmriJOptionPane.WARNING_MESSAGE); 323 return false; 324 } 325 return true; 326 } 327 328 /* 329 * CircuitBuilder calls from handleSelection to update icon display 330 */ 331 protected void updateSelections(boolean noShift, Positionable selection) { 332 // A temporary path "TEST_PATH" is used to display the icons representing a path 333 // the OBlock has allocated TEST_PATH 334 // pathGroup collects the icons and the actual path is edited or 335 // created with a save in _editPathsFrame 336 if (!canEdit()) { 337 return; 338 } 339 if (noShift) { 340 if (_pathGroup.contains(selection)) { 341 _pathGroup.remove(selection); 342 if (selection instanceof PortalIcon) { 343 ((PortalIcon) selection).setStatus(PortalIcon.VISIBLE); 344 } else { 345 ((IndicatorTrack) selection).setStatus(Sensor.INACTIVE); 346 ((IndicatorTrack) selection).removePath(TEST_PATH); 347 log.debug("removePath TEST_PATH"); 348 } 349 } else if (okPath(selection)) { 350 _pathGroup.add(selection); 351 // okPath() sets PortalIcons to status PortalIcon.PATH 352 if (selection instanceof IndicatorTrack) { 353 ((IndicatorTrack) selection).addPath(TEST_PATH); 354 } 355 } else { 356 return; 357 } 358 } else { 359 if (selection instanceof PortalIcon) { 360 ((PortalIcon) selection).setStatus(PortalIcon.VISIBLE); 361 } 362 } 363 int oldState = _homeBlock.getState(); 364 int newState = oldState | OBlock.ALLOCATED; 365 _homeBlock.pseudoPropertyChange("state", oldState, newState); 366 log.debug("updateSelections ALLOCATED _homeBlock"); 367 } 368 /** 369 * Set the path icons for display. 370 */ 371 private void updatePath() { 372 // to avoid ConcurrentModificationException now set data 373 for (Positionable pos : _pathGroup) { 374 if (pos instanceof IndicatorTrack) { 375 ((IndicatorTrack) pos).addPath(TEST_PATH); 376 } else { 377 ((PortalIcon) pos).setStatus(PortalIcon.PATH); 378 } 379 } 380 String name = _pathName.getText(); 381 if (!_pathGroup.isEmpty() && (name == null || name.length() == 0)) { 382 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("needPathName"), 383 Bundle.getMessage("makePath"), JmriJOptionPane.INFORMATION_MESSAGE); 384 } 385 } 386 387 private String findErrors() { 388 StringBuilder sb = new StringBuilder(); 389 java.util.List<Path> list = _homeBlock.getPaths(); 390 if (list.isEmpty()) { 391 sb.append(Bundle.getMessage("noPaths", _homeBlock.getDisplayName())); 392 } else { 393 list.stream().filter(o -> o instanceof OPath) 394 .map(o->(OPath) o).forEach( path -> { 395 ArrayList<Positionable> pathGp = makePathGroup(path); 396 if (pathGp.isEmpty()) { 397 sb.append(Bundle.getMessage("noPathIcons", path.getName())); 398 sb.append("\n"); 399 } else { 400 String msg = checkIcons(path.getName(), pathGp); 401 if (msg != null) { 402 sb.append(msg); 403 sb.append("\n"); 404 } 405 } 406 }); 407 } 408 return sb.toString(); 409 } 410 411 private boolean pathIconsEqual(ArrayList<Positionable> pathGp1, ArrayList<Positionable> pathGp2) { 412 if (pathGp1.size() != pathGp2.size()) { 413 return false; 414 } 415 for (Positionable pos : pathGp1) { 416 if (!pathGp2.contains(pos)) { 417 return false; 418 } 419 } 420 return true; 421 } 422 423 /** 424 * Checks if icons of path are different 425 */ 426 private String checkForSavePath() { 427 String name = _pathName.getText(); 428 StringBuilder sb = new StringBuilder(); 429 if (_currentPath != null) { 430 String curName = _currentPath.getName(); 431 if (!pathIconsEqual(_pathGroup, _savePathGroup)) { 432 sb.append(Bundle.getMessage("pathIconsChanged", curName)); 433 sb.append("\n"); 434 } 435 if (_lengthPanel.isChanged(_currentPath.getLengthMm())) { 436 sb.append(Bundle.getMessage("pathlengthChanged", curName)); 437 sb.append("\n"); 438 } 439 if (name.length() > 0 && !name.equals(_currentPath.getName())) { 440 sb.append(Bundle.getMessage("changeName", name, curName)); 441 sb.append("\n"); 442 } 443 } 444 return sb.toString(); 445 } 446 447 //////////////////////////// end setup //////////////////////////// 448 @Override 449 protected void clearListSelection() { 450 _pathList.clearSelection(); 451 _lengthPanel.setLength(0); 452 _pathName.setText(null); 453 } 454 455 private String checkIcons(String name, ArrayList<Positionable> pathGp) { 456 Iterator<Positionable> it = pathGp.iterator(); 457 boolean hasTrack = false; 458 boolean hasPortal = false; 459 while (it.hasNext()) { 460 Positionable pos = it.next(); 461 if (pos instanceof IndicatorTrack) { 462 hasTrack = true; 463 } else if (pos instanceof PortalIcon) { 464 hasPortal = true; 465 } 466 } 467 if (!hasTrack) { 468 return Bundle.getMessage("noTrackIconsForPath", name); 469 } else if (!hasPortal) { 470 return Bundle.getMessage("noPortalIconsForPath", name); 471 } 472 return null; 473 } 474 475 /** 476 * Make the OPath from the icons in the Iterator 477 */ 478 private OPath makeOPath(String name, ArrayList<Positionable> pathGp) { 479 if (pathGp.isEmpty()) { 480 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("noPathIcons", name), 481 Bundle.getMessage("makePath"), JmriJOptionPane.INFORMATION_MESSAGE); 482 return null; 483 } 484 Iterator<Positionable> it = pathGp.iterator(); 485 ArrayList<BeanSetting> settings = new ArrayList<>(); 486 Portal fromPortal = null; 487 Portal toPortal = null; 488 boolean hasTrack = false; 489 int portalIconCount = 0; 490 StringBuilder sb = new StringBuilder (); 491 while (it.hasNext()) { 492 Positionable pos = it.next(); 493 if (pos instanceof IndicatorTurnoutIcon) { 494 jmri.Turnout t = ((IndicatorTurnoutIcon) pos).getTurnout(); 495 String turnoutName = t.getDisplayName(); 496 int state = t.getKnownState(); 497 if (state != Turnout.CLOSED && state != Turnout.THROWN) { 498 if (sb.length() > 0) { 499 sb.append("\n"); 500 } 501 sb.append(Bundle.getMessage("turnoutNotSet", turnoutName)); 502 } else { 503 settings.add(new BeanSetting(t, turnoutName, state)); 504 hasTrack = true; 505 } 506 } else if (pos instanceof PortalIcon) { 507 if (toPortal == null) { 508 toPortal = ((PortalIcon) pos).getPortal(); 509 } else if (fromPortal == null) { 510 fromPortal = ((PortalIcon) pos).getPortal(); 511 } 512 portalIconCount++; 513 } else if (pos instanceof IndicatorTrack) { 514 hasTrack = true; 515 } 516 } 517 if (!hasTrack) { 518 if (sb.length() > 0) { 519 sb.append("\n"); 520 } 521 sb.append(Bundle.getMessage("noTrackIconsForPath", name)); 522 } 523 if (toPortal == null && fromPortal == null) { 524 if (sb.length() > 0) { 525 sb.append("\n"); 526 } 527 sb.append(Bundle.getMessage("tooFewPortals")); 528 } 529 if (portalIconCount == 0) { 530 if (sb.length() > 0) { 531 sb.append("\n"); 532 } 533 sb.append(Bundle.getMessage("noPortalIconsForPath", name)); 534 } 535 if (portalIconCount > 2) { 536 if (sb.length() > 0) { 537 sb.append("\n"); 538 } 539 sb.append(Bundle.getMessage("tooManyPortals")); 540 } 541 if (sb.length() > 0) { 542 JmriJOptionPane.showMessageDialog(this, sb.toString(), 543 Bundle.getMessage("makePath"), JmriJOptionPane.INFORMATION_MESSAGE); 544 return null; 545 } 546 547 if (log.isDebugEnabled()) { 548 log.debug("makeOPath for path \"{}\" from {} icons", name, pathGp.size()); 549 } 550 return new OPath(name, _homeBlock, fromPortal, toPortal, settings); 551 } 552 553 /** 554 * Create or update the selected path named in the text field Checks that 555 * icons have been selected for the path 556 */ 557 private void addNewPath(boolean prompt) { 558 String name = _pathName.getText(); 559 if (log.isDebugEnabled()) { 560 log.debug("addPath({}) for path \"{}\"", prompt, name); 561 } 562 if (name == null || name.trim().length() == 0) { 563 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TooltipPathName"), 564 Bundle.getMessage("makePath"), JmriJOptionPane.INFORMATION_MESSAGE); 565 return; 566 } 567 OPath otherPath = null; 568 OPath newPath = makeOPath(name, _pathGroup); 569 if (newPath == null) { 570 return; 571 } 572 // is this path already defined? OPath equality is equal turnout settings and portals, not icons 573 for (OPath loopPath : _homeBlock.getPaths().stream() 574 .filter(o -> o instanceof OPath).map(o -> (OPath)o) 575 .collect(Collectors.toList())) { 576 if (newPath.equals(loopPath)) { 577 otherPath = loopPath; 578 break; 579 } 580 } 581 if (log.isDebugEnabled()) { 582 log.debug("newPath= {}", newPath.toString()); 583 log.debug("otherPath= {}", (otherPath==null?"null":otherPath.toString())); 584 log.debug("_currentPath= {}", (_currentPath==null?"null":_currentPath.toString())); 585 log.debug("current path {} changed", (pathIconsEqual(_pathGroup, _savePathGroup)? "not" : "IS")); 586 } 587 588 if (otherPath != null && !otherPath.equals(_currentPath)) { 589 ArrayList<Positionable> otherPathGrp = makePathGroup(otherPath); 590 String otherName = otherPath.getName(); 591 StringBuilder sb = new StringBuilder (Bundle.getMessage("pathDefined", otherName)); 592 sb.append("\n"); 593 if (name.length() > 0 && !name.equals(otherName)) { 594 sb.append(Bundle.getMessage("changeName", name, otherName)); 595 sb.append("\n"); 596 } 597 if (!pathIconsEqual(_pathGroup, otherPathGrp)) { 598 sb.append(Bundle.getMessage("pathIconsChanged", otherName)); 599 sb.append("\n"); 600 } 601 if (_lengthPanel.isChanged(otherPath.getLengthMm())) { 602 sb.append(Bundle.getMessage("pathlengthChanged", otherName)); 603 sb.append("\n"); 604 } 605 if (sb.length() > 0 && prompt) { 606 sb.append(Bundle.getMessage("saveChanges")); 607 int result = JmriJOptionPane.showConfirmDialog(this, sb.toString(), 608 Bundle.getMessage("makePath"), JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.QUESTION_MESSAGE); 609 if (result == JmriJOptionPane.YES_OPTION) { 610 _currentPath = otherPath; 611 } 612 } else { 613 return; 614 } 615 } 616 617 // match icons to current selections 618 changePathNameInIcons(name, _pathGroup); 619 620 if (_currentPath != null) { 621 _currentPath.setName(name); 622 Portal toPortal = newPath.getToPortal(); 623 toPortal.addPath(_currentPath); 624 Portal fromPortal = newPath.getFromPortal(); 625 if (fromPortal != null) { 626 fromPortal.addPath(_currentPath); 627 } 628 _currentPath.setToPortal(toPortal); 629 _currentPath.setFromPortal(fromPortal); 630 _currentPath.setLength(_lengthPanel.getLength()); 631 _currentPath.clearSettings(); 632 for (BeanSetting beanSetting : newPath.getSettings()) { 633 _currentPath.addSetting(beanSetting); 634 } 635 _savePathGroup = _pathGroup; 636 log.debug("update _currentPath"); 637 } else { 638 newPath.setLength(_lengthPanel.getLength()); 639 _homeBlock.addPath(newPath); // OBlock adds path to portals and checks for duplicate path names 640 log.debug("add newPath"); 641 } 642 } 643 644 private void changePathName() { 645 String name = _pathName.getText(); 646 if (name == null || name.trim().length() == 0 || _currentPath == null) { 647 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("changePathName", Bundle.getMessage("buttonChangeName")), 648 Bundle.getMessage("makePath"), JmriJOptionPane.INFORMATION_MESSAGE); 649 return; 650 } 651 OPath aPath = _homeBlock.getPathByName(name); 652 if (aPath != null) { 653 if (name.equals(_currentPath.getName())) { 654 _pathList.setSelectedValue(aPath, true); 655 return; 656 } 657 JmriJOptionPane.showMessageDialog(this, 658 Bundle.getMessage("duplicatePathName", name, _homeBlock.getDisplayName()), 659 Bundle.getMessage("makePath"), JmriJOptionPane.INFORMATION_MESSAGE); 660 clearPath(false); 661 _pathName.setText(null); 662 return; 663 } 664 _currentPath.setName(name); // sends propertyChange to track icons 665 if (!pathIconsEqual(_pathGroup, _savePathGroup)) { 666 StringBuilder sb = new StringBuilder (); 667 sb.append(Bundle.getMessage("pathIconsChanged", name)); 668 sb.append("\n"); 669 sb.append(Bundle.getMessage("saveIcons")); 670 int result = JmriJOptionPane.showConfirmDialog(this, sb.toString(), 671 Bundle.getMessage("makePath"), JmriJOptionPane.YES_NO_OPTION, JmriJOptionPane.QUESTION_MESSAGE); 672 if (result == JmriJOptionPane.YES_OPTION) { 673 changePathNameInIcons(name, _pathGroup); 674 _savePathGroup = _pathGroup; 675 } else { 676 changePathNameInIcons(name, _savePathGroup); 677 clearPath(false); 678 _pathGroup = _savePathGroup; 679 updatePath(); 680 } 681 } else { 682 changePathNameInIcons(name, _pathGroup); 683 } 684 _pathList.setSelectedValue(_currentPath, true); 685 } 686 687 private void changePathNameInIcons(String name, ArrayList<Positionable> pathGp) { 688 log.debug("changePathNameInIcons for {}. {} icons", name, pathGp.size()); 689 // add or remove path name from IndicatorTrack icons 690 for (Positionable pos : _parent.getCircuitIcons(_homeBlock)) { 691 if (pathGp.contains(pos)) { 692 if (pos instanceof IndicatorTrack) { 693 ((IndicatorTrack) pos).addPath(name); 694 } 695 } else { 696 if (pos instanceof IndicatorTrack) { 697 ((IndicatorTrack) pos).removePath(name); 698 } 699 } 700 } 701 } 702 703 private void deletePath() { 704 OPath path = _pathList.getSelectedValue(); 705 if (path == null) { 706 // check that name was typed in and not selected 707 path = _homeBlock.getPathByName(_pathName.getText()); 708 } 709 if (path == null) { 710 return; 711 } 712 if (_homeBlock.removeOPath(path)) { 713 clearListSelection(); 714 _pathListModel.dataChange(); 715 } 716 } 717 718 @Override 719 protected void closingEvent(boolean close) { 720 StringBuilder sb = new StringBuilder (); 721 String msg = checkForSavePath(); 722 if(msg.length() > 0) { 723 sb.append(msg); 724 sb.append("\n"); 725 } 726 msg = findErrors(); 727 if (msg.length() > 0) { 728 sb.append(msg); 729 } 730 if (closingEvent(close, sb.toString())) { 731 _pathName.setText(null); 732 clearPath(true); 733 int oldState = _homeBlock.getState(); 734 int newState = oldState | OBlock.ALLOCATED; 735 _homeBlock.pseudoPropertyChange("state", oldState, newState); 736 _homeBlock.removePropertyChangeListener(_pathListModel); 737 }// else... Don't clear current selections, if continuing to edit 738 } 739 740 private void clearPath(boolean hidePortals) { 741 if (_pathGroup != null) { 742 log.debug("clearPath deAllocate _pathGroup with {} icons", _pathGroup.size()); 743 for (Positionable pos : _pathGroup) { 744 if (pos instanceof PortalIcon) { 745 PortalIcon pi = (PortalIcon) pos; 746 if (hidePortals) { 747 pi.setStatus(PortalIcon.HIDDEN); 748 } else { 749 pi.setStatus(PortalIcon.VISIBLE); 750 } 751 } else if (pos instanceof IndicatorTrack) { 752 ((IndicatorTrack)pos).removePath(TEST_PATH); 753 } 754 } 755 _pathGroup.clear(); 756 int oldState = _homeBlock.getState(); 757 int newState = oldState & ~OBlock.ALLOCATED; 758 _homeBlock.pseudoPropertyChange("state", oldState, newState); 759 _currentPath = null; 760 } else { 761 log.debug("clearPath pathGroup null"); 762 } 763 } 764 765 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(EditCircuitPaths.class); 766 767}