001package jmri.jmrit.display; 002 003import java.awt.*; 004import java.awt.datatransfer.DataFlavor; 005import java.awt.event.*; 006import java.awt.geom.Rectangle2D; 007import java.beans.PropertyChangeEvent; 008import java.beans.PropertyVetoException; 009import java.beans.VetoableChangeListener; 010import java.lang.reflect.InvocationTargetException; 011import java.text.MessageFormat; 012import java.util.*; 013import java.util.List; 014 015import javax.annotation.Nonnull; 016import javax.swing.*; 017import javax.swing.Timer; 018import javax.swing.border.Border; 019import javax.swing.border.CompoundBorder; 020import javax.swing.border.LineBorder; 021import javax.swing.event.ListSelectionEvent; 022 023import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 024 025import javax.annotation.CheckForNull; 026 027import jmri.*; 028import jmri.jmrit.catalog.CatalogPanel; 029import jmri.jmrit.catalog.DirectorySearcher; 030import jmri.jmrit.catalog.ImageIndexEditor; 031import jmri.jmrit.catalog.NamedIcon; 032import jmri.jmrit.display.controlPanelEditor.shape.PositionableShape; 033import jmri.jmrit.logixng.*; 034import jmri.jmrit.logixng.tools.swing.DeleteBean; 035import jmri.jmrit.logixng.tools.swing.LogixNGEditor; 036import jmri.jmrit.operations.trains.TrainIcon; 037import jmri.jmrit.picker.PickListModel; 038import jmri.jmrit.roster.Roster; 039import jmri.jmrit.roster.RosterEntry; 040import jmri.jmrit.roster.swing.RosterEntrySelectorPanel; 041import jmri.util.DnDStringImportHandler; 042import jmri.util.JmriJFrame; 043import jmri.util.ThreadingUtil; 044import jmri.util.swing.JmriColorChooser; 045import jmri.util.swing.JmriJOptionPane; 046import jmri.util.swing.JmriMouseEvent; 047import jmri.util.swing.JmriMouseListener; 048import jmri.util.swing.JmriMouseMotionListener; 049 050/** 051 * This is the Model and a Controller for panel editor Views. (Panel Editor, 052 * Layout Editor or any subsequent editors) The Model is simply a list of 053 * Positionable objects added to a "target panel". Control of the display 054 * attributes of the Positionable objects is done here. However, control of 055 * mouse events is passed to the editor views, so control is also done by the 056 * editor views. 057 * <p> 058 * The "contents" List keeps track of all the objects added to the target frame 059 * for later manipulation. This class only locates and moves "target panel" 060 * items, and does not control their appearance - that is left for the editor 061 * views. 062 * <p> 063 * The Editor has tri-state "flags" to control the display of Positionable 064 * object attributes globally - i.e. "on" or "off" for all - or as a third 065 * state, permits the display control "locally" by corresponding flags in each 066 * Positionable object 067 * <p> 068 * The title of the target and the editor panel are kept consistent via the 069 * {#setTitle} method. 070 * <p> 071 * Mouse events are initial handled here, rather than in the individual 072 * displayed objects, so that selection boxes for moving multiple objects can be 073 * provided. 074 * <p> 075 * This class also implements an effective ToolTipManager replacement, because 076 * the standard Swing one can't deal with the coordinate changes used to zoom a 077 * panel. It works by controlling the contents of the _tooltip instance 078 * variable, and triggering repaint of the target window when the tooltip 079 * changes. The window painting then explicitly draws the tooltip for the 080 * underlying object. 081 * 082 * @author Bob Jacobsen Copyright: Copyright (c) 2002, 2003, 2007 083 * @author Dennis Miller 2004 084 * @author Howard G. Penny Copyright: Copyright (c) 2005 085 * @author Matthew Harris Copyright: Copyright (c) 2009 086 * @author Pete Cressman Copyright: Copyright (c) 2009, 2010, 2011 087 * 088 */ 089public abstract class Editor extends JmriJFrameWithPermissions 090 implements JmriMouseListener, JmriMouseMotionListener, ActionListener, 091 KeyListener, VetoableChangeListener { 092 093 public static final int BKG = 1; 094 public static final int TEMP = 2; 095 public static final int ICONS = 3; 096 public static final int LABELS = 4; 097 public static final int MEMORIES = 5; 098 public static final int REPORTERS = 5; 099 public static final int SECURITY = 6; 100 public static final int TURNOUTS = 7; 101 public static final int LIGHTS = 8; 102 public static final int SIGNALS = 9; 103 public static final int SENSORS = 10; 104 public static final int CLOCK = 10; 105 public static final int MARKERS = 10; 106 public static final int NUM_LEVELS = 10; 107 108 public static final int SCROLL_NONE = 0; 109 public static final int SCROLL_BOTH = 1; 110 public static final int SCROLL_HORIZONTAL = 2; 111 public static final int SCROLL_VERTICAL = 3; 112 113 public static final Color HIGHLIGHT_COLOR = new Color(204, 207, 88); 114 115 public static final String POSITIONABLE_FLAVOR = DataFlavor.javaJVMLocalObjectMimeType 116 + ";class=jmri.jmrit.display.Positionable"; 117 118 private boolean _loadFailed = false; 119 120 private ArrayList<Positionable> _contents = new ArrayList<>(); 121 private Map<String, Positionable> _idContents = new HashMap<>(); 122 private Map<String, Set<Positionable>> _classContents = new HashMap<>(); 123 protected JLayeredPane _targetPanel; 124 private JFrame _targetFrame; 125 private JScrollPane _panelScrollPane; 126 127 // Option menu items 128 protected int _scrollState = SCROLL_NONE; 129 protected boolean _editable = true; 130 private boolean _positionable = true; 131 private boolean _controlLayout = true; 132 private boolean _showHidden = true; 133 private boolean _showToolTip = true; 134// private boolean _showCoordinates = true; 135 136 public static final int OPTION_POSITION = 1; 137 public static final int OPTION_CONTROLS = 2; 138 public static final int OPTION_HIDDEN = 3; 139 public static final int OPTION_TOOLTIP = 4; 140// public static final int OPTION_COORDS = 5; 141 142 private boolean _globalSetsLocal = true; // pre 2.9.6 behavior 143 private boolean _useGlobalFlag = false; // pre 2.9.6 behavior 144 145 // mouse methods variables 146 protected int _lastX; 147 protected int _lastY; 148 BasicStroke DASHED_LINE = new BasicStroke(1f, BasicStroke.CAP_BUTT, 149 BasicStroke.JOIN_BEVEL, 150 10f, new float[]{10f, 10f}, 0f); 151 152 protected Rectangle _selectRect = null; 153 protected Rectangle _highlightcomponent = null; 154 protected boolean _dragging = false; 155 protected ArrayList<Positionable> _selectionGroup = null; // items gathered inside fence 156 157 protected Positionable _currentSelection; 158 private ToolTip _defaultToolTip; 159 private ToolTip _tooltip = null; 160 161 // Accessible to editor views 162 protected int xLoc = 0; // x coord of selected Positionable 163 protected int yLoc = 0; // y coord of selected Positionable 164 protected int _anchorX; // x coord when mousePressed 165 protected int _anchorY; // y coord when mousePressed 166 167// private boolean delayedPopupTrigger = false; // Used to delay the request of a popup, on a mouse press as this may conflict with a drag event 168 protected double _paintScale = 1.0; // scale for _targetPanel drawing 169 170 protected Color defaultBackgroundColor = Color.lightGray; 171 protected boolean _pastePending = false; 172 173 // map of icon editor frames (incl, icon editor) keyed by name 174 protected HashMap<String, JFrameItem> _iconEditorFrame = new HashMap<>(); 175 176 // store panelMenu state so preference is retained on headless systems 177 private boolean panelMenuIsVisible = true; 178 179 private boolean _inEditInlineLogixNGMode = false; 180 private LogixNGEditor _inlineLogixNGEdit; 181 182 public Editor() { 183 } 184 185 public Editor(String name, boolean saveSize, boolean savePosition) { 186 super(name, saveSize, savePosition); 187 setName(name); 188 _defaultToolTip = new ToolTip(null, 0, 0, null); 189 setVisible(false); 190 InstanceManager.getDefault(SignalHeadManager.class).addVetoableChangeListener(this); 191 InstanceManager.getDefault(SignalMastManager.class).addVetoableChangeListener(this); 192 InstanceManager.turnoutManagerInstance().addVetoableChangeListener(this); 193 InstanceManager.sensorManagerInstance().addVetoableChangeListener(this); 194 InstanceManager.memoryManagerInstance().addVetoableChangeListener(this); 195 InstanceManager.getDefault(BlockManager.class).addVetoableChangeListener(this); 196 InstanceManager.getDefault(EditorManager.class).add(this); 197 } 198 199 public Editor(String name) { 200 this(name, true, true); 201 } 202 203 /** 204 * Set <strong>white</strong> as the default background color for panels created using the <strong>New Panel</strong> menu item. 205 * Overriden by LE to use a different default background color and set other initial defaults. 206 */ 207 public void newPanelDefaults() { 208 setBackgroundColor(Color.WHITE); 209 } 210 211 public void loadFailed() { 212 _loadFailed = true; 213 } 214 215 NamedIcon _newIcon; 216 boolean _ignore = false; 217 boolean _delete; 218 HashMap<String, String> _urlMap = new HashMap<>(); 219 220 public NamedIcon loadFailed(String msg, String url) { 221 log.debug("loadFailed _ignore= {} {}", _ignore, msg); 222 if (_urlMap == null) { 223 _urlMap = new HashMap<>(); 224 } 225 String goodUrl = _urlMap.get(url); 226 if (goodUrl != null) { 227 return NamedIcon.getIconByName(goodUrl); 228 } 229 if (_ignore) { 230 _loadFailed = true; 231 return NamedIcon.getIconByName(url); 232 } 233 _newIcon = null; 234 _delete = false; 235 (new UrlErrorDialog(msg, url)).setVisible(true); 236 237 if (_delete) { 238 return null; 239 } 240 if (_newIcon == null) { 241 _loadFailed = true; 242 _newIcon = NamedIcon.getIconByName(url); 243 } 244 return _newIcon; 245 } 246 247 private String getDisableLocoMarkerPopupRef() { 248 return "DisableLocoMarkerPopup__"+getWindowFrameRef(); 249 } 250 251 public void setLocoMarkerPopupDisabled(boolean value) { 252 var prefsMgr = InstanceManager.getOptionalDefault(UserPreferencesManager.class); 253 if (prefsMgr.isPresent()) { 254 prefsMgr.get().setCheckboxPreferenceState(getDisableLocoMarkerPopupRef(), value); 255 } 256 } 257 258 public boolean isLocoMarkerPopupDisabled() { 259 var prefsMgr = InstanceManager.getOptionalDefault(UserPreferencesManager.class); 260 if (prefsMgr.isPresent()) { 261 return prefsMgr.get().getCheckboxPreferenceState(getDisableLocoMarkerPopupRef(), false); 262 } else { 263 return false; 264 } 265 } 266 267 public class UrlErrorDialog extends JDialog { 268 269 private final JTextField _urlField; 270 private final CatalogPanel _catalog; 271 private final String _badUrl; 272 273 UrlErrorDialog(String msg, String url) { 274 super(_targetFrame, Bundle.getMessage("BadIcon"), true); 275 _badUrl = url; 276 JPanel content = new JPanel(); 277 JPanel panel = new JPanel(); 278 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 279 panel.add(Box.createVerticalStrut(10)); 280 panel.add(new JLabel(MessageFormat.format(Bundle.getMessage("IconUrlError"), msg))); 281 panel.add(new JLabel(Bundle.getMessage("UrlErrorPrompt1"))); 282 panel.add(new JLabel(Bundle.getMessage("UrlErrorPrompt1A"))); 283 panel.add(new JLabel(Bundle.getMessage("UrlErrorPrompt1B"))); 284 panel.add(Box.createVerticalStrut(10)); 285 panel.add(new JLabel(Bundle.getMessage("UrlErrorPrompt2", Bundle.getMessage("ButtonContinue")))); 286 panel.add(new JLabel(Bundle.getMessage("UrlErrorPrompt3", Bundle.getMessage("ButtonDelete")))); 287 panel.add(new JLabel(Bundle.getMessage("UrlErrorPrompt3A"))); 288 panel.add(Box.createVerticalStrut(10)); 289 panel.add(new JLabel(Bundle.getMessage("UrlErrorPrompt4", Bundle.getMessage("ButtonIgnore")))); 290 panel.add(Box.createVerticalStrut(10)); 291 _urlField = new JTextField(url); 292 _urlField.setDragEnabled(true); 293 _urlField.setTransferHandler(new DnDStringImportHandler()); 294 panel.add(_urlField); 295 panel.add(makeDoneButtonPanel()); 296 _urlField.setToolTipText(Bundle.getMessage("TooltipFixUrl")); 297 panel.setToolTipText(Bundle.getMessage("TooltipFixUrl")); 298 _catalog = CatalogPanel.makeDefaultCatalog(); 299 _catalog.setToolTipText(Bundle.getMessage("ToolTipDragIconToText")); 300 panel.add(_catalog); 301 content.add(panel); 302 setContentPane(content); 303 setLocation(200, 100); 304 pack(); 305 } 306 307 private JPanel makeDoneButtonPanel() { 308 JPanel result = new JPanel(); 309 result.setLayout(new FlowLayout()); 310 JButton doneButton = new JButton(Bundle.getMessage("ButtonContinue")); 311 doneButton.addActionListener(a -> { 312 _newIcon = NamedIcon.getIconByName(_urlField.getText()); 313 if (_newIcon != null) { 314 _urlMap.put(_badUrl, _urlField.getText()); 315 } 316 UrlErrorDialog.this.dispose(); 317 }); 318 doneButton.setToolTipText(Bundle.getMessage("TooltipContinue")); 319 result.add(doneButton); 320 321 JButton deleteButton = new JButton(Bundle.getMessage("ButtonDelete")); 322 deleteButton.addActionListener(a -> { 323 _delete = true; 324 UrlErrorDialog.this.dispose(); 325 }); 326 result.add(deleteButton); 327 deleteButton.setToolTipText(Bundle.getMessage("TooltipDelete")); 328 329 JButton cancelButton = new JButton(Bundle.getMessage("ButtonIgnore")); 330 cancelButton.addActionListener(a -> { 331 _ignore = true; 332 UrlErrorDialog.this.dispose(); 333 }); 334 result.add(cancelButton); 335 cancelButton.setToolTipText(Bundle.getMessage("TooltipIgnore")); 336 return result; 337 } 338 } 339 340 public void disposeLoadData() { 341 _urlMap = null; 342 } 343 344 public boolean loadOK() { 345 return !_loadFailed; 346 } 347 348 public List<Positionable> getContents() { 349 return Collections.unmodifiableList(_contents); 350 } 351 352 public Map<String, Positionable> getIdContents() { 353 return Collections.unmodifiableMap(_idContents); 354 } 355 356 public Set<String> getClassNames() { 357 return Collections.unmodifiableSet(_classContents.keySet()); 358 } 359 360 public Set<Positionable> getPositionablesByClassName(String className) { 361 Set<Positionable> set = _classContents.get(className); 362 if (set == null) { 363 return null; 364 } 365 return Collections.unmodifiableSet(set); 366 } 367 368 public void setDefaultToolTip(ToolTip dtt) { 369 _defaultToolTip = dtt; 370 } 371 372 // 373 // *************** setting the main panel and frame *************** 374 // 375 /** 376 * Set the target panel. 377 * <p> 378 * An Editor may or may not choose to use 'this' as its frame or the 379 * interior class 'TargetPane' for its targetPanel. 380 * 381 * @param targetPanel the panel to be edited 382 * @param frame the frame to embed the panel in 383 */ 384 protected void setTargetPanel(JLayeredPane targetPanel, JmriJFrame frame) { 385 if (targetPanel == null) { 386 _targetPanel = new TargetPane(); 387 } else { 388 _targetPanel = targetPanel; 389 } 390 // If on a headless system, set heavyweight components to null 391 // and don't attach mouse and keyboard listeners to the panel 392 if (GraphicsEnvironment.isHeadless()) { 393 _panelScrollPane = null; 394 _targetFrame = null; 395 return; 396 } 397 if (frame == null) { 398 _targetFrame = this; 399 } else { 400 _targetFrame = frame; 401 } 402 _targetFrame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); 403 _panelScrollPane = new JScrollPane(_targetPanel); 404 Container contentPane = _targetFrame.getContentPane(); 405 contentPane.add(_panelScrollPane); 406 _targetFrame.addWindowListener(new WindowAdapter() { 407 @Override 408 public void windowClosing(WindowEvent e) { 409 targetWindowClosingEvent(e); 410 } 411 }); 412 _targetPanel.addMouseListener(JmriMouseListener.adapt(this)); 413 _targetPanel.addMouseMotionListener(JmriMouseMotionListener.adapt(this)); 414 _targetPanel.setFocusable(true); 415 _targetPanel.addKeyListener(this); 416 //_targetFrame.pack(); 417 } 418 419 protected void setTargetPanelSize(int w, int h) { 420// log.debug("setTargetPanelSize now w={}, h={}", w, h); 421 _targetPanel.setSize(w, h); 422 _targetPanel.invalidate(); 423 } 424 425 protected Dimension getTargetPanelSize() { 426 return _targetPanel.getSize(); 427 } 428 429 /** 430 * Allow public access to the target (content) panel for external 431 * modification, particularly from scripts. 432 * 433 * @return the target panel 434 */ 435 public final JComponent getTargetPanel() { 436 return _targetPanel; 437 } 438 439 /** 440 * Allow public access to the scroll pane for external control of position, 441 * particularly from scripts. 442 * 443 * @return the scroll pane containing the target panel 444 */ 445 public final JScrollPane getPanelScrollPane() { 446 return _panelScrollPane; 447 } 448 449 public final JFrame getTargetFrame() { 450 return _targetFrame; 451 } 452 453 public Color getBackgroundColor() { 454 if (_targetPanel instanceof TargetPane) { 455 TargetPane tmp = (TargetPane) _targetPanel; 456 return tmp.getBackgroundColor(); 457 } else { 458 return null; 459 } 460 } 461 462 public void setBackgroundColor(Color col) { 463 if (_targetPanel instanceof TargetPane) { 464 TargetPane tmp = (TargetPane) _targetPanel; 465 tmp.setBackgroundColor(col); 466 } 467 JmriColorChooser.addRecentColor(col); 468 } 469 470 public void clearBackgroundColor() { 471 if (_targetPanel instanceof TargetPane) { 472 TargetPane tmp = (TargetPane) _targetPanel; 473 tmp.clearBackgroundColor(); 474 } 475 } 476 477 /** 478 * Get scale for TargetPane drawing. 479 * 480 * @return the scale 481 */ 482 public final double getPaintScale() { 483 return _paintScale; 484 } 485 486 protected final void setPaintScale(double newScale) { 487 double ratio = newScale / _paintScale; 488 _paintScale = newScale; 489 setScrollbarScale(ratio); 490 } 491 492 private ToolTipTimer _tooltipTimer; 493 494 protected void setToolTip(ToolTip tt) { 495 if (tt != null) { 496 var pos = tt.getPositionable(); 497 if (pos != null) { // LE turnout tooltips do not have a Positionable 498 if (pos.isHidden() && !isEditable()) { 499 // Skip hidden objects 500 return; 501 } 502 } 503 } 504 505 if (tt == null) { 506 _tooltip = null; 507 if (_tooltipTimer != null) { 508 _tooltipTimer.stop(); 509 _tooltipTimer = null; 510 _targetPanel.repaint(); 511 } 512 513 } else if (_tooltip == null && _tooltipTimer == null) { 514 log.debug("start :: tt = {}, tooltip = {}, timer = {}", tt, _tooltip, _tooltipTimer); 515 _tooltipTimer = new ToolTipTimer(TOOLTIPSHOWDELAY, this, tt); 516 _tooltipTimer.setRepeats(false); 517 _tooltipTimer.start(); 518 } 519 } 520 521 static int TOOLTIPSHOWDELAY = 1000; // msec 522 static int TOOLTIPDISMISSDELAY = 4000; // msec 523 524 /* 525 * Wait TOOLTIPSHOWDELAY then show tooltip. Wait TOOLTIPDISMISSDELAY and 526 * disappear. 527 */ 528 @Override 529 public void actionPerformed(ActionEvent event) { 530 //log.debug("_tooltipTimer actionPerformed: Timer on= {}", (_tooltipTimer!=null)); 531 if (_tooltipTimer != null) { 532 _tooltip = _tooltipTimer.getToolTip(); 533 _tooltipTimer.stop(); 534 } 535 if (_tooltip != null) { 536 _tooltipTimer = new ToolTipTimer(TOOLTIPDISMISSDELAY, this, null); 537 _tooltipTimer.setRepeats(false); 538 _tooltipTimer.start(); 539 } else { 540 _tooltipTimer = null; 541 } 542 _targetPanel.repaint(); 543 } 544 545 static class ToolTipTimer extends Timer { 546 547 private final ToolTip tooltip; 548 549 ToolTipTimer(int delay, ActionListener listener, ToolTip tip) { 550 super(delay, listener); 551 tooltip = tip; 552 } 553 554 ToolTip getToolTip() { 555 return tooltip; 556 } 557 } 558 559 /** 560 * Special internal class to allow drawing of layout to a JLayeredPane. This 561 * is the 'target' pane where the layout is displayed. 562 */ 563 public class TargetPane extends JLayeredPane { 564 565 private int h = 100; 566 private int w = 150; 567 568 public TargetPane() { 569 setLayout(null); 570 } 571 572 @Override 573 public void setSize(int width, int height) { 574// log.debug("size now w={}, h={}", width, height); 575 this.h = height; 576 this.w = width; 577 super.setSize(width, height); 578 } 579 580 @Override 581 public Dimension getSize() { 582 return new Dimension(w, h); 583 } 584 585 @Override 586 public Dimension getPreferredSize() { 587 return new Dimension(w, h); 588 } 589 590 @Override 591 public Dimension getMinimumSize() { 592 return getPreferredSize(); 593 } 594 595 @Override 596 public Dimension getMaximumSize() { 597 return getPreferredSize(); 598 } 599 600 @Override 601 public Component add(@Nonnull Component c, int i) { 602 int hnew = Math.max(this.h, c.getLocation().y + c.getSize().height); 603 int wnew = Math.max(this.w, c.getLocation().x + c.getSize().width); 604 if (hnew > h || wnew > w) { 605// log.debug("size was {},{} - i ={}", w, h, i); 606 setSize(wnew, hnew); 607 } 608 return super.add(c, i); 609 } 610 611 @Override 612 public void add(@Nonnull Component c, Object o) { 613 super.add(c, o); 614 int hnew = Math.max(h, c.getLocation().y + c.getSize().height); 615 int wnew = Math.max(w, c.getLocation().x + c.getSize().width); 616 if (hnew > h || wnew > w) { 617 // log.debug("adding of {} with Object - i=", c.getSize(), o); 618 setSize(wnew, hnew); 619 } 620 } 621 622 private Color _highlightColor = HIGHLIGHT_COLOR; 623 private Color _selectGroupColor = HIGHLIGHT_COLOR; 624 private Color _selectRectColor = Color.red; 625 private transient Stroke _selectRectStroke = DASHED_LINE; 626 627 public void setHighlightColor(Color color) { 628 _highlightColor = color; 629 } 630 631 public Color getHighlightColor() { 632 return _highlightColor; 633 } 634 635 public void setSelectGroupColor(Color color) { 636 _selectGroupColor = color; 637 } 638 639 public void setSelectRectColor(Color color) { 640 _selectRectColor = color; 641 } 642 643 public void setSelectRectStroke(Stroke stroke) { 644 _selectRectStroke = stroke; 645 } 646 647 public void setDefaultColors() { 648 _highlightColor = HIGHLIGHT_COLOR; 649 _selectGroupColor = HIGHLIGHT_COLOR; 650 _selectRectColor = Color.red; 651 _selectRectStroke = DASHED_LINE; 652 } 653 654 @Override 655 public void paint(Graphics g) { 656 Graphics2D g2d = null; 657 if (g instanceof Graphics2D) { 658 g2d = (Graphics2D) g; 659 g2d.scale(_paintScale, _paintScale); 660 } 661 super.paint(g); 662 663 Stroke stroke = new BasicStroke(); 664 if (g2d != null) { 665 stroke = g2d.getStroke(); 666 } 667 Color color = g.getColor(); 668 if (_selectRect != null) { 669 //Draw a rectangle on top of the image. 670 if (g2d != null) { 671 g2d.setStroke(_selectRectStroke); 672 } 673 g.setColor(_selectRectColor); 674 g.drawRect(_selectRect.x, _selectRect.y, _selectRect.width, _selectRect.height); 675 } 676 if (_selectionGroup != null) { 677 g.setColor(_selectGroupColor); 678 if (g2d != null) { 679 g2d.setStroke(new BasicStroke(2.0f)); 680 } 681 for (Positionable p : _selectionGroup) { 682 if (p != null) { 683 if (!(p instanceof PositionableShape)) { 684 g.drawRect(p.getX(), p.getY(), p.maxWidth(), p.maxHeight()); 685 } else { 686 PositionableShape s = (PositionableShape) p; 687 s.drawHandles(); 688 } 689 } 690 } 691 } 692 //Draws a border around the highlighted component 693 if (_highlightcomponent != null) { 694 g.setColor(_highlightColor); 695 if (g2d != null) { 696 g2d.setStroke(new BasicStroke(2.0f)); 697 } 698 g.drawRect(_highlightcomponent.x, _highlightcomponent.y, 699 _highlightcomponent.width, _highlightcomponent.height); 700 } 701 paintTargetPanel(g); 702 703 g.setColor(color); 704 if (g2d != null) { 705 g2d.setStroke(stroke); 706 } 707 if (_tooltip != null) { 708 _tooltip.paint(g2d, _paintScale); 709 } 710 } 711 712 public void setBackgroundColor(Color col) { 713 setBackground(col); 714 setOpaque(true); 715 JmriColorChooser.addRecentColor(col); 716 } 717 718 public void clearBackgroundColor() { 719 setOpaque(false); 720 } 721 722 public Color getBackgroundColor() { 723 if (isOpaque()) { 724 return getBackground(); 725 } 726 return null; 727 } 728 } 729 730 private void setScrollbarScale(double ratio) { 731 //resize the panel to reflect scaling 732 Dimension dim = _targetPanel.getSize(); 733 int tpWidth = (int) ((dim.width) * ratio); 734 int tpHeight = (int) ((dim.height) * ratio); 735 _targetPanel.setSize(tpWidth, tpHeight); 736 log.debug("setScrollbarScale: ratio= {}, tpWidth= {}, tpHeight= {}", ratio, tpWidth, tpHeight); 737 // compute new scroll bar positions to keep upper left same 738 JScrollBar horScroll = _panelScrollPane.getHorizontalScrollBar(); 739 JScrollBar vertScroll = _panelScrollPane.getVerticalScrollBar(); 740 int hScroll = (int) (horScroll.getValue() * ratio); 741 int vScroll = (int) (vertScroll.getValue() * ratio); 742 // set scrollbars maximum range (otherwise setValue may fail); 743 horScroll.setMaximum((int) ((horScroll.getMaximum()) * ratio)); 744 vertScroll.setMaximum((int) ((vertScroll.getMaximum()) * ratio)); 745 // set scroll bar positions 746 horScroll.setValue(hScroll); 747 vertScroll.setValue(vScroll); 748 } 749 750 /* 751 * ********************** Options setup ********************* 752 */ 753 /** 754 * Control whether target panel items are editable. Does this by invoke the 755 * {@link Positionable#setEditable(boolean)} function of each item on the 756 * target panel. This also controls the relevant pop-up menu items (which 757 * are the primary way that items are edited). 758 * 759 * @param state true for editable. 760 */ 761 public void setAllEditable(boolean state) { 762 _editable = state; 763 for (Positionable _content : _contents) { 764 _content.setEditable(state); 765 } 766 if (!_editable) { 767 _highlightcomponent = null; 768 deselectSelectionGroup(); 769 } 770 } 771 772 public void deselectSelectionGroup() { 773 if (_selectionGroup == null) { 774 return; 775 } 776 for (Positionable p : _selectionGroup) { 777 if (p instanceof PositionableShape) { 778 PositionableShape s = (PositionableShape) p; 779 s.removeHandles(); 780 } 781 } 782 _selectionGroup = null; 783 } 784 785 // accessor routines for persistent information 786 public boolean isEditable() { 787 return _editable; 788 } 789 790 /** 791 * Set which flag should be used, global or local for Positioning and 792 * Control of individual items. Items call getFlag() to return the 793 * appropriate flag it should use. 794 * 795 * @param set True if global flags should be used for positioning. 796 */ 797 public void setUseGlobalFlag(boolean set) { 798 _useGlobalFlag = set; 799 } 800 801 public boolean useGlobalFlag() { 802 return _useGlobalFlag; 803 } 804 805 /** 806 * Get the setting for the specified option. 807 * 808 * @param whichOption The option to get 809 * @param localFlag is the current setting of the item 810 * @return The setting for the option 811 */ 812 public boolean getFlag(int whichOption, boolean localFlag) { 813 //log.debug("getFlag Option= {}, _useGlobalFlag={} localFlag={}", whichOption, _useGlobalFlag, localFlag); 814 if (_useGlobalFlag) { 815 switch (whichOption) { 816 case OPTION_POSITION: 817 return _positionable; 818 case OPTION_CONTROLS: 819 return _controlLayout; 820 case OPTION_HIDDEN: 821 return _showHidden; 822 case OPTION_TOOLTIP: 823 return _showToolTip; 824// case OPTION_COORDS: 825// return _showCoordinates; 826 default: 827 log.warn("Unhandled which option code: {}", whichOption); 828 break; 829 } 830 } 831 return localFlag; 832 } 833 834 /** 835 * Set if {@link #setAllControlling(boolean)} and 836 * {@link #setAllPositionable(boolean)} are set for existing as well as new 837 * items. 838 * 839 * @param set true if setAllControlling() and setAllPositionable() are set 840 * for existing items 841 */ 842 public void setGlobalSetsLocalFlag(boolean set) { 843 _globalSetsLocal = set; 844 } 845 846 /** 847 * Control whether panel items can be positioned. Markers can always be 848 * positioned. 849 * 850 * @param state true to set all items positionable; false otherwise 851 */ 852 public void setAllPositionable(boolean state) { 853 _positionable = state; 854 if (_globalSetsLocal) { 855 for (Positionable p : _contents) { 856 // don't allow backgrounds to be set positionable by global flag 857 if (!state || p.getDisplayLevel() != BKG) { 858 p.setPositionable(state); 859 } 860 } 861 } 862 } 863 864 public boolean allPositionable() { 865 return _positionable; 866 } 867 868 /** 869 * Control whether target panel items are controlling layout items. 870 * <p> 871 * Does this by invoking the {@link Positionable#setControlling} function of 872 * each item on the target panel. This also controls the relevant pop-up 873 * menu items. 874 * 875 * @param state true for controlling. 876 */ 877 public void setAllControlling(boolean state) { 878 _controlLayout = state; 879 if (_globalSetsLocal) { 880 for (Positionable _content : _contents) { 881 _content.setControlling(state); 882 } 883 } 884 } 885 886 public boolean allControlling() { 887 return _controlLayout; 888 } 889 890 /** 891 * Control whether target panel hidden items are visible or not. Does this 892 * by invoke the {@link Positionable#setHidden} function of each item on the 893 * target panel. 894 * 895 * @param state true for Visible. 896 */ 897 public void setShowHidden(boolean state) { 898 _showHidden = state; 899 if (_showHidden) { 900 for (Positionable _content : _contents) { 901 _content.setVisible(true); 902 } 903 } else { 904 for (Positionable _content : _contents) { 905 _content.showHidden(); 906 } 907 } 908 } 909 910 public boolean showHidden() { 911 return _showHidden; 912 } 913 914 public void setAllShowToolTip(boolean state) { 915 _showToolTip = state; 916 for (Positionable _content : _contents) { 917 _content.setShowToolTip(state); 918 } 919 } 920 921 public boolean showToolTip() { 922 return _showToolTip; 923 } 924 925 /* 926 * Control whether target panel items will show their coordinates in their 927 * popup menu. 928 * 929 * @param state true for show coordinates. 930 */ 931 /* 932 public void setShowCoordinates(boolean state) { 933 _showCoordinates = state; 934 for (int i = 0; i<_contents.size(); i++) { 935 _contents.get(i).setViewCoordinates(state); 936 } 937 } 938 public boolean showCoordinates() { 939 return _showCoordinates; 940 } 941 */ 942 943 /** 944 * Hide or show menus on the target panel. 945 * 946 * @param state true to show menus; false to hide menus 947 * @since 3.9.5 948 */ 949 public void setPanelMenuVisible(boolean state) { 950 this.panelMenuIsVisible = state; 951 if (!GraphicsEnvironment.isHeadless() && this._targetFrame != null) { 952 _targetFrame.getJMenuBar().setVisible(state); 953 this.revalidate(); 954 } 955 } 956 957 /** 958 * Is the menu on the target panel shown? 959 * 960 * @return true if menu is visible 961 * @since 3.9.5 962 */ 963 public boolean isPanelMenuVisible() { 964 if (!GraphicsEnvironment.isHeadless() && this._targetFrame != null) { 965 this.panelMenuIsVisible = _targetFrame.getJMenuBar().isVisible(); 966 } 967 return this.panelMenuIsVisible; 968 } 969 970 protected void setScroll(int state) { 971 log.debug("setScroll {}", state); 972 switch (state) { 973 case SCROLL_NONE: 974 _panelScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 975 _panelScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 976 break; 977 case SCROLL_BOTH: 978 _panelScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 979 _panelScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 980 break; 981 case SCROLL_HORIZONTAL: 982 _panelScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 983 _panelScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 984 break; 985 case SCROLL_VERTICAL: 986 _panelScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 987 _panelScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 988 break; 989 default: 990 log.warn("Unexpected setScroll state of {}", state); 991 break; 992 } 993 _scrollState = state; 994 } 995 996 public void setScroll(String strState) { 997 int state = SCROLL_BOTH; 998 if (strState.equalsIgnoreCase("none") || strState.equalsIgnoreCase("no")) { 999 state = SCROLL_NONE; 1000 } else if (strState.equals("horizontal")) { 1001 state = SCROLL_HORIZONTAL; 1002 } else if (strState.equals("vertical")) { 1003 state = SCROLL_VERTICAL; 1004 } 1005 log.debug("setScroll: strState= {}, state= {}", strState, state); 1006 setScroll(state); 1007 } 1008 1009 public String getScrollable() { 1010 String value = ""; 1011 switch (_scrollState) { 1012 case SCROLL_NONE: 1013 value = "none"; 1014 break; 1015 case SCROLL_BOTH: 1016 value = "both"; 1017 break; 1018 case SCROLL_HORIZONTAL: 1019 value = "horizontal"; 1020 break; 1021 case SCROLL_VERTICAL: 1022 value = "vertical"; 1023 break; 1024 default: 1025 log.warn("Unexpected _scrollState of {}", _scrollState); 1026 break; 1027 } 1028 return value; 1029 } 1030 /* 1031 * *********************** end Options setup ********************** 1032 */ 1033 /* 1034 * Handle closing (actually hiding due to HIDE_ON_CLOSE) the target window. 1035 * <p> 1036 * The target window has been requested to close, don't delete it at this 1037 * time. Deletion must be accomplished via the Delete this panel menu item. 1038 */ 1039 protected void targetWindowClosing() { 1040 String name = _targetFrame.getTitle(); 1041 if (!InstanceManager.getDefault(ShutDownManager.class).isShuttingDown()) { 1042 InstanceManager.getDefault(UserPreferencesManager.class).showInfoMessage( 1043 Bundle.getMessage("PanelHideTitle"), Bundle.getMessage("PanelHideNotice", name), // NOI18N 1044 "jmri.jmrit.display.EditorManager", "skipHideDialog"); // NOI18N 1045 InstanceManager.getDefault(UserPreferencesManager.class).setPreferenceItemDetails( 1046 "jmri.jmrit.display.EditorManager", "skipHideDialog", Bundle.getMessage("PanelHideSkip")); // NOI18N 1047 } 1048 } 1049 1050 protected Editor changeView(String className) { 1051 JFrame frame = getTargetFrame(); 1052 1053 try { 1054 Editor ed = (Editor) Class.forName(className).getDeclaredConstructor().newInstance(); 1055 1056 ed.setName(getName()); 1057 ed.init(getName()); 1058 1059 ed._contents = new ArrayList<>(_contents); 1060 ed._idContents = new HashMap<>(_idContents); 1061 ed._classContents = new HashMap<>(_classContents); 1062 1063 for (Positionable p : _contents) { 1064 p.setEditor(ed); 1065 ed.addToTarget(p); 1066 if (log.isDebugEnabled()) { 1067 log.debug("changeView: {} addToTarget class= {}", p.getNameString(), p.getClass().getName()); 1068 } 1069 } 1070 ed.setAllEditable(isEditable()); 1071 //ed.setAllPositionable(allPositionable()); 1072 //ed.setShowCoordinates(showCoordinates()); 1073 ed.setAllShowToolTip(showToolTip()); 1074 //ed.setAllControlling(allControlling()); 1075 ed.setShowHidden(isVisible()); 1076 ed.setPanelMenuVisible(frame.getJMenuBar().isVisible()); 1077 ed.setScroll(getScrollable()); 1078 ed.setTitle(); 1079 ed.setBackgroundColor(getBackgroundColor()); 1080 ed.getTargetFrame().setLocation(frame.getLocation()); 1081 ed.getTargetFrame().setSize(frame.getSize()); 1082 ed.setSize(getSize()); 1083// ed.pack(); 1084 ed.setVisible(true); 1085 dispose(); 1086 InstanceManager.getDefault(EditorManager.class).add(ed); 1087 return ed; 1088 } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException cnfe) { 1089 log.error("changeView exception {}", cnfe.toString()); 1090 } 1091 return null; 1092 } 1093 1094 /* 1095 * *********************** Popup Item Methods ********************** 1096 * 1097 * These methods are to be called from the editor view's showPopUp method 1098 */ 1099 /** 1100 * Add a checkbox to lock the position of the Positionable item. 1101 * 1102 * @param p the item 1103 * @param popup the menu to add the lock menu item to 1104 */ 1105 public void setPositionableMenu(Positionable p, JPopupMenu popup) { 1106 JCheckBoxMenuItem lockItem = new JCheckBoxMenuItem(Bundle.getMessage("LockPosition")); 1107 lockItem.setSelected(!p.isPositionable()); 1108 lockItem.addActionListener(new ActionListener() { 1109 private Positionable comp; 1110 private JCheckBoxMenuItem checkBox; 1111 1112 @Override 1113 public void actionPerformed(ActionEvent e) { 1114 comp.setPositionable(!checkBox.isSelected()); 1115 setSelectionsPositionable(!checkBox.isSelected(), comp); 1116 } 1117 1118 ActionListener init(Positionable pos, JCheckBoxMenuItem cb) { 1119 comp = pos; 1120 checkBox = cb; 1121 return this; 1122 } 1123 }.init(p, lockItem)); 1124 popup.add(lockItem); 1125 } 1126 1127 /** 1128 * Display the {@literal X & Y} coordinates of the Positionable item and 1129 * provide a dialog menu item to edit them. 1130 * 1131 * @param p The item to add the menu item to 1132 * @param popup The menu item to add the action to 1133 * @return always returns true 1134 */ 1135 public boolean setShowCoordinatesMenu(Positionable p, JPopupMenu popup) { 1136 1137 JMenuItem edit; 1138 if ((p instanceof MemoryOrGVIcon) && (p.getPopupUtility().getFixedWidth() == 0)) { 1139 MemoryOrGVIcon pm = (MemoryOrGVIcon) p; 1140 1141 edit = new JMenuItem(Bundle.getMessage( 1142 "EditLocationXY", pm.getOriginalX(), pm.getOriginalY())); 1143 1144 edit.addActionListener(MemoryIconCoordinateEdit.getCoordinateEditAction(pm)); 1145 } else { 1146 edit = new JMenuItem(Bundle.getMessage( 1147 "EditLocationXY", p.getX(), p.getY())); 1148 edit.addActionListener(CoordinateEdit.getCoordinateEditAction(p)); 1149 } 1150 popup.add(edit); 1151 return true; 1152 } 1153 1154 /** 1155 * Offer actions to align the selected Positionable items either 1156 * Horizontally (at average y coordinates) or Vertically (at average x 1157 * coordinates). 1158 * 1159 * @param p The positionable item 1160 * @param popup The menu to add entries to 1161 * @return true if entries added to menu 1162 */ 1163 public boolean setShowAlignmentMenu(Positionable p, JPopupMenu popup) { 1164 if (showAlignPopup(p)) { 1165 JMenu edit = new JMenu(Bundle.getMessage("EditAlignment")); 1166 edit.add(new AbstractAction(Bundle.getMessage("AlignX")) { 1167 private int _x; 1168 1169 @Override 1170 public void actionPerformed(ActionEvent e) { 1171 if (_selectionGroup == null) { 1172 return; 1173 } 1174 for (Positionable comp : _selectionGroup) { 1175 if (!getFlag(OPTION_POSITION, comp.isPositionable())) { 1176 continue; 1177 } 1178 comp.setLocation(_x, comp.getY()); 1179 } 1180 } 1181 1182 AbstractAction init(int x) { 1183 _x = x; 1184 return this; 1185 } 1186 }.init(p.getX())); 1187 edit.add(new AbstractAction(Bundle.getMessage("AlignMiddleX")) { 1188 private int _x; 1189 1190 @Override 1191 public void actionPerformed(ActionEvent e) { 1192 if (_selectionGroup == null) { 1193 return; 1194 } 1195 for (Positionable comp : _selectionGroup) { 1196 if (!getFlag(OPTION_POSITION, comp.isPositionable())) { 1197 continue; 1198 } 1199 comp.setLocation(_x - comp.getWidth() / 2, comp.getY()); 1200 } 1201 } 1202 1203 AbstractAction init(int x) { 1204 _x = x; 1205 return this; 1206 } 1207 }.init(p.getX() + p.getWidth() / 2)); 1208 edit.add(new AbstractAction(Bundle.getMessage("AlignOtherX")) { 1209 private int _x; 1210 1211 @Override 1212 public void actionPerformed(ActionEvent e) { 1213 if (_selectionGroup == null) { 1214 return; 1215 } 1216 for (Positionable comp : _selectionGroup) { 1217 if (!getFlag(OPTION_POSITION, comp.isPositionable())) { 1218 continue; 1219 } 1220 comp.setLocation(_x - comp.getWidth(), comp.getY()); 1221 } 1222 } 1223 1224 AbstractAction init(int x) { 1225 _x = x; 1226 return this; 1227 } 1228 }.init(p.getX() + p.getWidth())); 1229 edit.add(new AbstractAction(Bundle.getMessage("AlignY")) { 1230 private int _y; 1231 1232 @Override 1233 public void actionPerformed(ActionEvent e) { 1234 if (_selectionGroup == null) { 1235 return; 1236 } 1237 for (Positionable comp : _selectionGroup) { 1238 if (!getFlag(OPTION_POSITION, comp.isPositionable())) { 1239 continue; 1240 } 1241 comp.setLocation(comp.getX(), _y); 1242 } 1243 } 1244 1245 AbstractAction init(int y) { 1246 _y = y; 1247 return this; 1248 } 1249 }.init(p.getY())); 1250 edit.add(new AbstractAction(Bundle.getMessage("AlignMiddleY")) { 1251 private int _y; 1252 1253 @Override 1254 public void actionPerformed(ActionEvent e) { 1255 if (_selectionGroup == null) { 1256 return; 1257 } 1258 for (Positionable comp : _selectionGroup) { 1259 if (!getFlag(OPTION_POSITION, comp.isPositionable())) { 1260 continue; 1261 } 1262 comp.setLocation(comp.getX(), _y - comp.getHeight() / 2); 1263 } 1264 } 1265 1266 AbstractAction init(int y) { 1267 _y = y; 1268 return this; 1269 } 1270 }.init(p.getY() + p.getHeight() / 2)); 1271 edit.add(new AbstractAction(Bundle.getMessage("AlignOtherY")) { 1272 private int _y; 1273 1274 @Override 1275 public void actionPerformed(ActionEvent e) { 1276 if (_selectionGroup == null) { 1277 return; 1278 } 1279 for (Positionable comp : _selectionGroup) { 1280 if (!getFlag(OPTION_POSITION, comp.isPositionable())) { 1281 continue; 1282 } 1283 comp.setLocation(comp.getX(), _y - comp.getHeight()); 1284 } 1285 } 1286 1287 AbstractAction init(int y) { 1288 _y = y; 1289 return this; 1290 } 1291 }.init(p.getY() + p.getHeight())); 1292 edit.add(new AbstractAction(Bundle.getMessage("AlignXFirst")) { 1293 1294 @Override 1295 public void actionPerformed(ActionEvent e) { 1296 if (_selectionGroup == null) { 1297 return; 1298 } 1299 int x = _selectionGroup.get(0).getX(); 1300 for (int i = 1; i < _selectionGroup.size(); i++) { 1301 Positionable comp = _selectionGroup.get(i); 1302 if (!getFlag(OPTION_POSITION, comp.isPositionable())) { 1303 continue; 1304 } 1305 comp.setLocation(x, comp.getY()); 1306 } 1307 } 1308 }); 1309 edit.add(new AbstractAction(Bundle.getMessage("AlignYFirst")) { 1310 1311 @Override 1312 public void actionPerformed(ActionEvent e) { 1313 if (_selectionGroup == null) { 1314 return; 1315 } 1316 int y = _selectionGroup.get(0).getX(); 1317 for (int i = 1; i < _selectionGroup.size(); i++) { 1318 Positionable comp = _selectionGroup.get(i); 1319 if (!getFlag(OPTION_POSITION, comp.isPositionable())) { 1320 continue; 1321 } 1322 comp.setLocation(comp.getX(), y); 1323 } 1324 } 1325 }); 1326 popup.add(edit); 1327 return true; 1328 } 1329 return false; 1330 } 1331 1332 /** 1333 * Display 'z' level of the Positionable item and provide a dialog 1334 * menu item to edit it. 1335 * 1336 * @param p The item 1337 * @param popup the menu to add entries to 1338 */ 1339 public void setDisplayLevelMenu(Positionable p, JPopupMenu popup) { 1340 JMenuItem edit = new JMenuItem(Bundle.getMessage("EditLevel_", p.getDisplayLevel())); 1341 edit.addActionListener(CoordinateEdit.getLevelEditAction(p)); 1342 popup.add(edit); 1343 } 1344 1345 /** 1346 * Add a menu entry to set visibility of the Positionable item 1347 * 1348 * @param p the item 1349 * @param popup the menu to add the entry to 1350 */ 1351 public void setHiddenMenu(Positionable p, JPopupMenu popup) { 1352 if (p.getDisplayLevel() == BKG) { 1353 return; 1354 } 1355 JCheckBoxMenuItem hideItem = new JCheckBoxMenuItem(Bundle.getMessage("SetHidden")); 1356 hideItem.setSelected(p.isHidden()); 1357 hideItem.addActionListener(new ActionListener() { 1358 private Positionable comp; 1359 private JCheckBoxMenuItem checkBox; 1360 1361 @Override 1362 public void actionPerformed(ActionEvent e) { 1363 comp.setHidden(checkBox.isSelected()); 1364 setSelectionsHidden(checkBox.isSelected(), comp); 1365 } 1366 1367 ActionListener init(Positionable pos, JCheckBoxMenuItem cb) { 1368 comp = pos; 1369 checkBox = cb; 1370 return this; 1371 } 1372 }.init(p, hideItem)); 1373 popup.add(hideItem); 1374 } 1375 1376 /** 1377 * Add a menu entry to set visibility of the Positionable item based on the presence of contents. 1378 * If the value is null or empty, the icon is not visible. 1379 * This is applicable to memory, block content and LogixNG global variable labels. 1380 * 1381 * @param p the item 1382 * @param popup the menu to add the entry to 1383 */ 1384 public void setEmptyHiddenMenu(Positionable p, JPopupMenu popup) { 1385 if (p.getDisplayLevel() == BKG) { 1386 return; 1387 } 1388 if (p instanceof BlockContentsIcon || p instanceof MemoryIcon 1389 || p instanceof GlobalVariableIcon || p instanceof LogixNGTableIcon) { 1390 JCheckBoxMenuItem hideEmptyItem = new JCheckBoxMenuItem(Bundle.getMessage("SetEmptyHidden")); 1391 hideEmptyItem.setSelected(p.isEmptyHidden()); 1392 hideEmptyItem.addActionListener(new ActionListener() { 1393 private Positionable comp; 1394 private JCheckBoxMenuItem checkBox; 1395 1396 @Override 1397 public void actionPerformed(ActionEvent e) { 1398 comp.setEmptyHidden(checkBox.isSelected()); 1399 } 1400 1401 ActionListener init(Positionable pos, JCheckBoxMenuItem cb) { 1402 comp = pos; 1403 checkBox = cb; 1404 return this; 1405 } 1406 }.init(p, hideEmptyItem)); 1407 popup.add(hideEmptyItem); 1408 } 1409 } 1410 1411 /** 1412 * Add a menu entry to disable double click value edits. This applies when not in panel edit mode. 1413 * This is applicable to memory, block content and LogixNG global variable labels. 1414 * 1415 * @param p the item 1416 * @param popup the menu to add the entry to 1417 */ 1418 public void setValueEditDisabledMenu(Positionable p, JPopupMenu popup) { 1419 if (p.getDisplayLevel() == BKG) { 1420 return; 1421 } 1422 if (p instanceof BlockContentsIcon || p instanceof MemoryIcon 1423 || p instanceof GlobalVariableIcon || p instanceof LogixNGTableIcon) { 1424 JCheckBoxMenuItem valueEditDisableItem = new JCheckBoxMenuItem(Bundle.getMessage("SetValueEditDisabled")); 1425 valueEditDisableItem.setSelected(p.isValueEditDisabled()); 1426 valueEditDisableItem.addActionListener(new ActionListener() { 1427 private Positionable comp; 1428 private JCheckBoxMenuItem checkBox; 1429 1430 @Override 1431 public void actionPerformed(ActionEvent e) { 1432 comp.setValueEditDisabled(checkBox.isSelected()); 1433 } 1434 1435 ActionListener init(Positionable pos, JCheckBoxMenuItem cb) { 1436 comp = pos; 1437 checkBox = cb; 1438 return this; 1439 } 1440 }.init(p, valueEditDisableItem)); 1441 popup.add(valueEditDisableItem); 1442 } 1443 } 1444 1445 /** 1446 * Add a menu entry to edit Id of the Positionable item 1447 * 1448 * @param p the item 1449 * @param popup the menu to add the entry to 1450 */ 1451 public void setEditIdMenu(Positionable p, JPopupMenu popup) { 1452 if (p.getDisplayLevel() == BKG) { 1453 return; 1454 } 1455 1456 popup.add(CoordinateEdit.getIdEditAction(p, "EditId", this)); 1457 } 1458 1459 /** 1460 * Add a menu entry to edit Classes of the Positionable item 1461 * 1462 * @param p the item 1463 * @param popup the menu to add the entry to 1464 */ 1465 public void setEditClassesMenu(Positionable p, JPopupMenu popup) { 1466 if (p.getDisplayLevel() == BKG) { 1467 return; 1468 } 1469 1470 popup.add(CoordinateEdit.getClassesEditAction(p, "EditClasses", this)); 1471 } 1472 1473 /** 1474 * Check if edit of a conditional is in progress. 1475 * 1476 * @return true if this is the case, after showing dialog to user 1477 */ 1478 private boolean checkEditConditionalNG() { 1479 if (_inEditInlineLogixNGMode) { 1480 // Already editing a LogixNG, ask for completion of that edit 1481 JmriJOptionPane.showMessageDialog(null, 1482 Bundle.getMessage("Error_InlineLogixNGInEditMode"), // NOI18N 1483 Bundle.getMessage("ErrorTitle"), // NOI18N 1484 JmriJOptionPane.ERROR_MESSAGE); 1485 _inlineLogixNGEdit.bringToFront(); 1486 return true; 1487 } 1488 return false; 1489 } 1490 1491 /** 1492 * Add a menu entry to edit Id of the Positionable item 1493 * 1494 * @param p the item 1495 * @param popup the menu to add the entry to 1496 */ 1497 public void setLogixNGPositionableMenu(Positionable p, JPopupMenu popup) { 1498 if (p.getDisplayLevel() == BKG) { 1499 return; 1500 } 1501 1502 JMenu logixNG_Menu = new JMenu("LogixNG"); 1503 popup.add(logixNG_Menu); 1504 1505 logixNG_Menu.add(new AbstractAction(Bundle.getMessage("LogixNG_Inline")) { 1506 @Override 1507 public void actionPerformed(ActionEvent e) { 1508 if (checkEditConditionalNG()) { 1509 return; 1510 } 1511 1512 if (p.getLogixNG() == null) { 1513 LogixNG logixNG = InstanceManager.getDefault(LogixNG_Manager.class) 1514 .createLogixNG(null, true); 1515 logixNG.setInlineLogixNG(p); 1516 logixNG.activate(); 1517 logixNG.setEnabled(true); 1518 logixNG.clearStartup(); 1519 p.setLogixNG(logixNG); 1520 } 1521 LogixNGEditor logixNGEditor = new LogixNGEditor(null, p.getLogixNG().getSystemName()); 1522 logixNGEditor.addEditorEventListener((HashMap<String, String> data) -> { 1523 _inEditInlineLogixNGMode = false; 1524 data.forEach((key, value) -> { 1525 if (key.equals("Finish")) { // NOI18N 1526 _inlineLogixNGEdit = null; 1527 _inEditInlineLogixNGMode = false; 1528 } else if (key.equals("Delete")) { // NOI18N 1529 _inEditInlineLogixNGMode = false; 1530 deleteLogixNG(p.getLogixNG()); 1531 } else if (key.equals("chgUname")) { // NOI18N 1532 p.getLogixNG().setUserName(value); 1533 } 1534 }); 1535 if (p.getLogixNG() != null && p.getLogixNG().getNumConditionalNGs() == 0) { 1536 deleteLogixNG_Internal(p.getLogixNG()); 1537 } 1538 }); 1539 logixNGEditor.bringToFront(); 1540 _inEditInlineLogixNGMode = true; 1541 _inlineLogixNGEdit = logixNGEditor; 1542 } 1543 }); 1544 } 1545 1546 private void deleteLogixNG(LogixNG logixNG) { 1547 DeleteBean<LogixNG> deleteBean = new DeleteBean<>( 1548 InstanceManager.getDefault(LogixNG_Manager.class)); 1549 1550 boolean hasChildren = logixNG.getNumConditionalNGs() > 0; 1551 1552 deleteBean.delete(logixNG, hasChildren, t -> deleteLogixNG_Internal(t), 1553 (t,list) -> logixNG.getListenerRefsIncludingChildren(list), 1554 jmri.jmrit.logixng.LogixNG_UserPreferences.class.getName()); 1555 } 1556 1557 private void deleteLogixNG_Internal(LogixNG logixNG) { 1558 logixNG.setEnabled(false); 1559 try { 1560 InstanceManager.getDefault(LogixNG_Manager.class).deleteBean(logixNG, "DoDelete"); 1561 logixNG.getInlineLogixNG().setLogixNG(null); 1562 } catch (PropertyVetoException e) { 1563 //At this stage the DoDelete shouldn't fail, as we have already done a can delete, which would trigger a veto 1564 log.error("{} : Could not Delete.", e.getMessage()); 1565 } 1566 } 1567 1568 /** 1569 * Check if it's possible to change the id of the Positionable to the 1570 * desired string. 1571 * @param p the Positionable 1572 * @param newId the desired new id 1573 * @throws jmri.jmrit.display.Positionable.DuplicateIdException if another 1574 * Positionable in the editor already has this id 1575 */ 1576 public void positionalIdChange(Positionable p, String newId) 1577 throws Positionable.DuplicateIdException { 1578 1579 if (Objects.equals(newId, p.getId())) { 1580 return; 1581 } 1582 1583 if ((newId != null) && (_idContents.containsKey(newId))) { 1584 throw new Positionable.DuplicateIdException(); 1585 } 1586 1587 if (p.getId() != null) { 1588 _idContents.remove(p.getId()); 1589 } 1590 if (newId != null) { 1591 _idContents.put(newId, p); 1592 } 1593 } 1594 1595 /** 1596 * Add a class name to the Positionable 1597 * @param p the Positionable 1598 * @param className the class name 1599 * @throws IllegalArgumentException if the name contains a comma 1600 */ 1601 public void positionalAddClass(Positionable p, String className) { 1602 1603 if (className == null) { 1604 throw new IllegalArgumentException("Class name must not be null"); 1605 } 1606 if (className.isBlank()) { 1607 throw new IllegalArgumentException("Class name must not be blank"); 1608 } 1609 if (className.contains(",")) { 1610 throw new IllegalArgumentException("Class name must not contain a comma"); 1611 } 1612 1613 if (p.getClasses().contains(className)) { 1614 return; 1615 } 1616 1617 _classContents.computeIfAbsent(className, o -> new HashSet<>()).add(p); 1618 } 1619 1620 /** 1621 * Removes a class name from the Positionable 1622 * @param p the Positionable 1623 * @param className the class name 1624 */ 1625 public void positionalRemoveClass(Positionable p, String className) { 1626 1627 if (p.getClasses().contains(className)) { 1628 return; 1629 } 1630 _classContents.get(className).remove(p); 1631 } 1632 1633 /** 1634 * Add a checkbox to display a tooltip for the Positionable item and if 1635 * showable, provide a dialog menu to edit it. 1636 * 1637 * @param p the item to set the menu for 1638 * @param popup the menu to add for p 1639 */ 1640 public void setShowToolTipMenu(Positionable p, JPopupMenu popup) { 1641 if (p.getDisplayLevel() == BKG) { 1642 return; 1643 } 1644 1645 JMenu edit = new JMenu(Bundle.getMessage("EditTooltip")); 1646 1647 JCheckBoxMenuItem showToolTipItem = new JCheckBoxMenuItem(Bundle.getMessage("ShowTooltip")); 1648 showToolTipItem.setSelected(p.showToolTip()); 1649 showToolTipItem.addActionListener(new ActionListener() { 1650 private Positionable comp; 1651 private JCheckBoxMenuItem checkBox; 1652 1653 @Override 1654 public void actionPerformed(ActionEvent e) { 1655 comp.setShowToolTip(checkBox.isSelected()); 1656 } 1657 1658 ActionListener init(Positionable pos, JCheckBoxMenuItem cb) { 1659 comp = pos; 1660 checkBox = cb; 1661 return this; 1662 } 1663 }.init(p, showToolTipItem)); 1664 edit.add(showToolTipItem); 1665 1666 edit.add(CoordinateEdit.getToolTipEditAction(p)); 1667 1668 JCheckBoxMenuItem prependToolTipWithDisplayNameItem = 1669 new JCheckBoxMenuItem(Bundle.getMessage("PrependTooltipWithDisplayName")); 1670 prependToolTipWithDisplayNameItem.setSelected(p.getToolTip().getPrependToolTipWithDisplayName()); 1671 prependToolTipWithDisplayNameItem.addActionListener(new ActionListener() { 1672 private Positionable comp; 1673 private JCheckBoxMenuItem checkBox; 1674 1675 @Override 1676 public void actionPerformed(ActionEvent e) { 1677 comp.getToolTip().setPrependToolTipWithDisplayName(checkBox.isSelected()); 1678 } 1679 1680 ActionListener init(Positionable pos, JCheckBoxMenuItem cb) { 1681 comp = pos; 1682 checkBox = cb; 1683 return this; 1684 } 1685 }.init(p, prependToolTipWithDisplayNameItem)); 1686 edit.add(prependToolTipWithDisplayNameItem); 1687 1688 popup.add(edit); 1689 } 1690 1691 /** 1692 * Add an action to remove the Positionable item. 1693 * 1694 * @param p the item to set the menu for 1695 * @param popup the menu to add for p 1696 */ 1697 public void setRemoveMenu(Positionable p, JPopupMenu popup) { 1698 popup.add(new AbstractAction(Bundle.getMessage("Remove")) { 1699 private Positionable comp; 1700 1701 @Override 1702 public void actionPerformed(ActionEvent e) { 1703 comp.remove(); 1704 removeSelections(comp); 1705 } 1706 1707 AbstractAction init(Positionable pos) { 1708 comp = pos; 1709 return this; 1710 } 1711 }.init(p)); 1712 } 1713 1714 /* 1715 * *********************** End Popup Methods ********************** 1716 */ 1717 /* 1718 * ****************** Marker Menu *************************** 1719 */ 1720 protected void locoMarkerFromRoster() { 1721 final JmriJFrame locoRosterFrame = new JmriJFrame(); 1722 locoRosterFrame.getContentPane().setLayout(new FlowLayout()); 1723 locoRosterFrame.setTitle(Bundle.getMessage("LocoFromRoster")); 1724 JLabel mtext = new JLabel(); 1725 mtext.setText(Bundle.getMessage("SelectLoco") + ":"); 1726 locoRosterFrame.getContentPane().add(mtext); 1727 final RosterEntrySelectorPanel rosterBox = new RosterEntrySelectorPanel(); 1728 rosterBox.addPropertyChangeListener("selectedRosterEntries", pce -> { 1729 if (rosterBox.getSelectedRosterEntries().length != 0) { 1730 selectLoco(rosterBox.getSelectedRosterEntries()[0]); 1731 } 1732 }); 1733 locoRosterFrame.getContentPane().add(rosterBox); 1734 locoRosterFrame.addWindowListener(new WindowAdapter() { 1735 @Override 1736 public void windowClosing(WindowEvent e) { 1737 locoRosterFrame.dispose(); 1738 } 1739 }); 1740 locoRosterFrame.pack(); 1741 locoRosterFrame.setVisible(true); 1742 } 1743 1744 protected LocoIcon selectLoco(String rosterEntryTitle) { 1745 if ("".equals(rosterEntryTitle)) { 1746 return null; 1747 } 1748 return selectLoco(Roster.getDefault().entryFromTitle(rosterEntryTitle)); 1749 } 1750 1751 protected LocoIcon selectLoco(RosterEntry entry) { 1752 LocoIcon l = null; 1753 if (entry == null) { 1754 return null; 1755 } 1756 // try getting road number, else use DCC address 1757 String rn = entry.getRoadNumber(); 1758 if ((rn == null) || rn.equals("")) { 1759 rn = entry.getDccAddress(); 1760 } 1761 if (rn != null) { 1762 l = addLocoIcon(rn); 1763 l.setRosterEntry(entry); 1764 } 1765 return l; 1766 } 1767 1768 protected void locoMarkerFromInput() { 1769 final JmriJFrame locoFrame = new JmriJFrame(); 1770 locoFrame.getContentPane().setLayout(new FlowLayout()); 1771 locoFrame.setTitle(Bundle.getMessage("EnterLocoMarker")); 1772 1773 JLabel textId = new JLabel(); 1774 textId.setText(Bundle.getMessage("LocoID") + ":"); 1775 locoFrame.getContentPane().add(textId); 1776 1777 final JTextField locoId = new JTextField(7); 1778 locoFrame.getContentPane().add(locoId); 1779 locoId.setText(""); 1780 locoId.setToolTipText(Bundle.getMessage("EnterLocoID")); 1781 JButton okay = new JButton(); 1782 okay.setText(Bundle.getMessage("ButtonOK")); 1783 okay.addActionListener(e -> { 1784 String nameID = locoId.getText(); 1785 if ((nameID != null) && !(nameID.trim().equals(""))) { 1786 addLocoIcon(nameID.trim()); 1787 } else { 1788 JmriJOptionPane.showMessageDialog(locoFrame, Bundle.getMessage("ErrorEnterLocoID"), 1789 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 1790 } 1791 }); 1792 locoFrame.getContentPane().add(okay); 1793 locoFrame.addWindowListener(new WindowAdapter() { 1794 @Override 1795 public void windowClosing(WindowEvent e) { 1796 locoFrame.dispose(); 1797 } 1798 }); 1799 locoFrame.pack(); 1800 if (_targetFrame != null) { 1801 locoFrame.setLocation(_targetFrame.getLocation()); 1802 } 1803 locoFrame.setVisible(true); 1804 } 1805 1806 /** 1807 * Remove marker icons from panel 1808 */ 1809 protected void removeMarkers() { 1810 log.debug("Remove markers"); 1811 for (int i = _contents.size() - 1; i >= 0; i--) { 1812 Positionable il = _contents.get(i); 1813 if (il instanceof LocoIcon) { 1814 il.remove(); 1815 if (il.getId() != null) { 1816 _idContents.remove(il.getId()); 1817 } 1818 for (String className : il.getClasses()) { 1819 _classContents.get(className).remove(il); 1820 } 1821 } 1822 } 1823 } 1824 1825 /* 1826 * *********************** End Marker Menu Methods ********************** 1827 */ 1828 /* 1829 * ************ Adding content to the panel ********************** 1830 */ 1831 public PositionableLabel setUpBackground(String name) { 1832 NamedIcon icon = NamedIcon.getIconByName(name); 1833 PositionableLabel l = new PositionableLabel(icon, this); 1834 l.setPopupUtility(null); // no text 1835 l.setPositionable(false); 1836 l.setShowToolTip(false); 1837 l.setSize(icon.getIconWidth(), icon.getIconHeight()); 1838 l.setDisplayLevel(BKG); 1839 l.setLocation(getNextBackgroundLeft(), 0); 1840 try { 1841 putItem(l); 1842 } catch (Positionable.DuplicateIdException e) { 1843 // This should never happen 1844 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 1845 } 1846 return l; 1847 } 1848 1849 protected PositionableLabel addLabel(String text) { 1850 PositionableLabel l = new PositionableLabel(text, this); 1851 l.setSize(l.getPreferredSize().width, l.getPreferredSize().height); 1852 l.setDisplayLevel(LABELS); 1853 setNextLocation(l); 1854 try { 1855 putItem(l); 1856 } catch (Positionable.DuplicateIdException e) { 1857 // This should never happen 1858 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 1859 } 1860 return l; 1861 } 1862 1863 /** 1864 * Determine right side x of furthest right background 1865 */ 1866 private int getNextBackgroundLeft() { 1867 int left = 0; 1868 // place to right of background images, if any 1869 for (Positionable p : _contents) { 1870 if (p instanceof PositionableLabel) { 1871 PositionableLabel l = (PositionableLabel) p; 1872 if (l.isBackground()) { 1873 int test = l.getX() + l.maxWidth(); 1874 if (test > left) { 1875 left = test; 1876 } 1877 } 1878 } 1879 } 1880 return left; 1881 } 1882 1883 /** 1884 * Positionable has set a new level. 1885 * Editor must change it in the target panel. 1886 * @param l the positionable to display. 1887 */ 1888 public void displayLevelChange(Positionable l) { 1889 ThreadingUtil.runOnGUI( () -> { 1890 removeFromTarget(l); 1891 addToTarget(l); 1892 }); 1893 } 1894 1895 public TrainIcon addTrainIcon(String name) { 1896 TrainIcon l = new TrainIcon(this); 1897 putLocoIcon(l, name); 1898 return l; 1899 } 1900 1901 public LocoIcon addLocoIcon(String name) { 1902 LocoIcon l = new LocoIcon(this); 1903 putLocoIcon(l, name); 1904 return l; 1905 } 1906 1907 public void putLocoIcon(LocoIcon l, String name) { 1908 l.setText(name); 1909 l.setHorizontalTextPosition(SwingConstants.CENTER); 1910 l.setSize(l.getPreferredSize().width, l.getPreferredSize().height); 1911 l.setEditable(isEditable()); // match popup mode to editor mode 1912 l.setLocation(75, 75); // fixed location 1913 try { 1914 putItem(l); 1915 } catch (Positionable.DuplicateIdException e) { 1916 // This should never happen 1917 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 1918 } 1919 } 1920 1921 public void putItem(@Nonnull Positionable l) throws Positionable.DuplicateIdException { 1922 putItem(l, false); 1923 } 1924 1925 public void putItem(@Nonnull Positionable l, boolean factoryPositionable) 1926 throws Positionable.DuplicateIdException { 1927 1928 ThreadingUtil.runOnGUI( () -> { 1929 l.invalidate(); 1930 l.setPositionable(true); 1931 l.setVisible(true); 1932 if (l.getToolTip() == null) { 1933 l.setToolTip(new ToolTip(_defaultToolTip, l)); 1934 } 1935 addToTarget(l); 1936 }); 1937 if (!_contents.add(l)) { 1938 log.error("Unable to add {} to _contents", l.getNameString()); 1939 } 1940 if (l.getId() != null) { 1941 if (_idContents.containsKey(l.getId())) { 1942 throw new Positionable.DuplicateIdException(); 1943 } 1944 _idContents.put(l.getId(), l); 1945 } 1946 for (String className : l.getClasses()) { 1947 _classContents.get(className).add(l); 1948 } 1949 if (log.isDebugEnabled()) { 1950 log.debug("putItem {} to _contents. level= {}", l.getNameString(), l.getDisplayLevel()); 1951 } 1952 } 1953 1954 protected void addToTarget(Positionable l) { 1955 JComponent c = (JComponent) l; 1956 c.invalidate(); 1957 _targetPanel.remove(c); 1958 _targetPanel.add(c, Integer.valueOf(l.getDisplayLevel())); 1959 _targetPanel.moveToFront(c); 1960 c.repaint(); 1961 _targetPanel.revalidate(); 1962 } 1963 1964 /* 1965 * ************ Icon editors for adding content *********** 1966 */ 1967 static final String[] ICON_EDITORS = {"Sensor", "RightTurnout", "LeftTurnout", 1968 "SlipTOEditor", "SignalHead", "SignalMast", "Memory", "Light", 1969 "Reporter", "Background", "MultiSensor", "Icon", "Text", "Block Contents"}; 1970 1971 /** 1972 * Create editor for a given item type. 1973 * Paths to default icons are fixed in code. Compare to respective icon package, 1974 * eg. {@link #addSensorEditor()} and {@link SensorIcon} 1975 * 1976 * @param name Icon editor's name 1977 * @return a window 1978 */ 1979 public JFrameItem getIconFrame(String name) { 1980 JFrameItem frame = _iconEditorFrame.get(name); 1981 if (frame == null) { 1982 if ("Sensor".equals(name)) { 1983 addSensorEditor(); 1984 } else if ("RightTurnout".equals(name)) { 1985 addRightTOEditor(); 1986 } else if ("LeftTurnout".equals(name)) { 1987 addLeftTOEditor(); 1988 } else if ("SlipTOEditor".equals(name)) { 1989 addSlipTOEditor(); 1990 } else if ("SignalHead".equals(name)) { 1991 addSignalHeadEditor(); 1992 } else if ("SignalMast".equals(name)) { 1993 addSignalMastEditor(); 1994 } else if ("Memory".equals(name)) { 1995 addMemoryEditor(); 1996 } else if ("GlobalVariable".equals(name)) { 1997 addGlobalVariableEditor(); 1998 } else if ("LogixNGTable".equals(name)) { 1999 addLogixNGTableEditor(); 2000 } else if ("Reporter".equals(name)) { 2001 addReporterEditor(); 2002 } else if ("Light".equals(name)) { 2003 addLightEditor(); 2004 } else if ("Background".equals(name)) { 2005 addBackgroundEditor(); 2006 } else if ("MultiSensor".equals(name)) { 2007 addMultiSensorEditor(); 2008 } else if ("Icon".equals(name)) { 2009 addIconEditor(); 2010 } else if ("Text".equals(name)) { 2011 addTextEditor(); 2012 } else if ("BlockLabel".equals(name)) { 2013 addBlockContentsEditor(); 2014 } else if ("Audio".equals(name)) { 2015 addAudioEditor(); 2016 } else if ("LogixNG".equals(name)) { 2017 addLogixNGEditor(); 2018 } else { 2019 // log.error("No such Icon Editor \"{}\"", name); 2020 return null; 2021 } 2022 // frame added in the above switch 2023 frame = _iconEditorFrame.get(name); 2024 2025 if (frame == null) { // addTextEditor does not create a usable frame 2026 return null; 2027 } 2028 //frame.setLocationRelativeTo(this); 2029 frame.setLocation(frameLocationX, frameLocationY); 2030 frameLocationX += DELTA; 2031 frameLocationY += DELTA; 2032 } 2033 frame.setVisible(true); 2034 return frame; 2035 } 2036 public int frameLocationX = 0; 2037 public int frameLocationY = 0; 2038 static final int DELTA = 20; 2039 2040 public IconAdder getIconEditor(String name) { 2041 return _iconEditorFrame.get(name).getEditor(); 2042 } 2043 2044 public void putIconEditor(String name, Editor.JFrameItem frame) { 2045 _iconEditorFrame.put(name, frame); 2046 } 2047 2048 /** 2049 * Add a label to the target. 2050 */ 2051 protected void addTextEditor() { 2052 String newLabel = JmriJOptionPane.showInputDialog(this, Bundle.getMessage("PromptNewLabel"),""); 2053 if (newLabel == null) { 2054 return; // canceled 2055 } 2056 PositionableLabel l = addLabel(newLabel); 2057 // always allow new items to be moved 2058 l.setPositionable(true); 2059 } 2060 2061 protected void addRightTOEditor() { 2062 IconAdder editor = new IconAdder("RightTurnout"); 2063 editor.setIcon(3, "TurnoutStateClosed", 2064 "resources/icons/smallschematics/tracksegments/os-righthand-west-closed.gif"); 2065 editor.setIcon(2, "TurnoutStateThrown", 2066 "resources/icons/smallschematics/tracksegments/os-righthand-west-thrown.gif"); 2067 editor.setIcon(0, "BeanStateInconsistent", 2068 "resources/icons/smallschematics/tracksegments/os-righthand-west-error.gif"); 2069 editor.setIcon(1, "BeanStateUnknown", 2070 "resources/icons/smallschematics/tracksegments/os-righthand-west-unknown.gif"); 2071 2072 JFrameItem frame = makeAddIconFrame("RightTurnout", true, true, editor); 2073 _iconEditorFrame.put("RightTurnout", frame); 2074 editor.setPickList(PickListModel.turnoutPickModelInstance()); 2075 2076 ActionListener addIconAction = a -> addTurnoutR(); 2077 editor.makeIconPanel(true); 2078 editor.complete(addIconAction, true, true, false); 2079 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2080 } 2081 2082 protected void addLeftTOEditor() { 2083 IconAdder editor = new IconAdder("LeftTurnout"); 2084 editor.setIcon(3, "TurnoutStateClosed", 2085 "resources/icons/smallschematics/tracksegments/os-lefthand-east-closed.gif"); 2086 editor.setIcon(2, "TurnoutStateThrown", 2087 "resources/icons/smallschematics/tracksegments/os-lefthand-east-thrown.gif"); 2088 editor.setIcon(0, "BeanStateInconsistent", 2089 "resources/icons/smallschematics/tracksegments/os-lefthand-east-error.gif"); 2090 editor.setIcon(1, "BeanStateUnknown", 2091 "resources/icons/smallschematics/tracksegments/os-lefthand-east-unknown.gif"); 2092 2093 JFrameItem frame = makeAddIconFrame("LeftTurnout", true, true, editor); 2094 _iconEditorFrame.put("LeftTurnout", frame); 2095 editor.setPickList(PickListModel.turnoutPickModelInstance()); 2096 2097 ActionListener addIconAction = a -> addTurnoutL(); 2098 editor.makeIconPanel(true); 2099 editor.complete(addIconAction, true, true, false); 2100 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2101 } 2102 2103 protected void addSlipTOEditor() { 2104 SlipIconAdder editor = new SlipIconAdder("SlipTOEditor"); 2105 editor.setIcon(3, "LowerWestToUpperEast", 2106 "resources/icons/smallschematics/tracksegments/os-slip-lower-west-upper-east.gif"); 2107 editor.setIcon(2, "UpperWestToLowerEast", 2108 "resources/icons/smallschematics/tracksegments/os-slip-upper-west-lower-east.gif"); 2109 editor.setIcon(4, "LowerWestToLowerEast", 2110 "resources/icons/smallschematics/tracksegments/os-slip-lower-west-lower-east.gif"); 2111 editor.setIcon(5, "UpperWestToUpperEast", 2112 "resources/icons/smallschematics/tracksegments/os-slip-upper-west-upper-east.gif"); 2113 editor.setIcon(0, "BeanStateInconsistent", 2114 "resources/icons/smallschematics/tracksegments/os-slip-error-full.gif"); 2115 editor.setIcon(1, "BeanStateUnknown", 2116 "resources/icons/smallschematics/tracksegments/os-slip-unknown-full.gif"); 2117 editor.setTurnoutType(SlipTurnoutIcon.DOUBLESLIP); 2118 JFrameItem frame = makeAddIconFrame("SlipTOEditor", true, true, editor); 2119 _iconEditorFrame.put("SlipTOEditor", frame); 2120 editor.setPickList(PickListModel.turnoutPickModelInstance()); 2121 2122 ActionListener addIconAction = a -> addSlip(); 2123 editor.makeIconPanel(true); 2124 editor.complete(addIconAction, true, true, false); 2125 frame.addHelpMenu("package.jmri.jmrit.display.SlipTurnoutIcon", true); 2126 } 2127 2128 protected void addSensorEditor() { 2129 IconAdder editor = new IconAdder("Sensor"); 2130 editor.setIcon(3, "SensorStateActive", 2131 "resources/icons/smallschematics/tracksegments/circuit-occupied.gif"); 2132 editor.setIcon(2, "SensorStateInactive", 2133 "resources/icons/smallschematics/tracksegments/circuit-empty.gif"); 2134 editor.setIcon(0, "BeanStateInconsistent", 2135 "resources/icons/smallschematics/tracksegments/circuit-error.gif"); 2136 editor.setIcon(1, "BeanStateUnknown", 2137 "resources/icons/smallschematics/tracksegments/circuit-error.gif"); 2138 2139 JFrameItem frame = makeAddIconFrame("Sensor", true, true, editor); 2140 _iconEditorFrame.put("Sensor", frame); 2141 editor.setPickList(PickListModel.sensorPickModelInstance()); 2142 2143 ActionListener addIconAction = a -> putSensor(); 2144 editor.makeIconPanel(true); 2145 editor.complete(addIconAction, true, true, false); 2146 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2147 } 2148 2149 protected void addSignalHeadEditor() { 2150 IconAdder editor = getSignalHeadEditor(); 2151 JFrameItem frame = makeAddIconFrame("SignalHead", true, true, editor); 2152 _iconEditorFrame.put("SignalHead", frame); 2153 editor.setPickList(PickListModel.signalHeadPickModelInstance()); 2154 2155 ActionListener addIconAction = a -> putSignalHead(); 2156 editor.makeIconPanel(true); 2157 editor.complete(addIconAction, true, false, false); 2158 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2159 } 2160 2161 protected IconAdder getSignalHeadEditor() { 2162 // note that all these icons will be refreshed when user clicks a specific signal head in the table 2163 IconAdder editor = new IconAdder("SignalHead"); 2164 editor.setIcon(0, "SignalHeadStateRed", 2165 "resources/icons/smallschematics/searchlights/left-red-marker.gif"); 2166 editor.setIcon(1, "SignalHeadStateYellow", 2167 "resources/icons/smallschematics/searchlights/left-yellow-marker.gif"); 2168 editor.setIcon(2, "SignalHeadStateGreen", 2169 "resources/icons/smallschematics/searchlights/left-green-marker.gif"); 2170 editor.setIcon(3, "SignalHeadStateDark", 2171 "resources/icons/smallschematics/searchlights/left-dark-marker.gif"); 2172 editor.setIcon(4, "SignalHeadStateHeld", 2173 "resources/icons/smallschematics/searchlights/left-held-marker.gif"); 2174 editor.setIcon(5, "SignalHeadStateLunar", 2175 "resources/icons/smallschematics/searchlights/left-lunar-marker.gif"); 2176 editor.setIcon(6, "SignalHeadStateFlashingRed", 2177 "resources/icons/smallschematics/searchlights/left-flashred-marker.gif"); 2178 editor.setIcon(7, "SignalHeadStateFlashingYellow", 2179 "resources/icons/smallschematics/searchlights/left-flashyellow-marker.gif"); 2180 editor.setIcon(8, "SignalHeadStateFlashingGreen", 2181 "resources/icons/smallschematics/searchlights/left-flashgreen-marker.gif"); 2182 editor.setIcon(9, "SignalHeadStateFlashingLunar", 2183 "resources/icons/smallschematics/searchlights/left-flashlunar-marker.gif"); 2184 return editor; 2185 } 2186 2187 protected void addSignalMastEditor() { 2188 IconAdder editor = new IconAdder("SignalMast"); 2189 2190 JFrameItem frame = makeAddIconFrame("SignalMast", true, true, editor); 2191 _iconEditorFrame.put("SignalMast", frame); 2192 editor.setPickList(PickListModel.signalMastPickModelInstance()); 2193 2194 ActionListener addIconAction = a -> putSignalMast(); 2195 editor.makeIconPanel(true); 2196 editor.complete(addIconAction, true, false, false); 2197 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2198 } 2199 2200 private final SpinnerNumberModel _spinCols = new SpinnerNumberModel(3, 1, 100, 1); 2201 2202 protected void addMemoryEditor() { 2203 IconAdder editor = new IconAdder("Memory") { 2204 final JButton bSpin = new JButton(Bundle.getMessage("AddSpinner")); 2205 final JButton bBox = new JButton(Bundle.getMessage("AddInputBox")); 2206 final JSpinner spinner = new JSpinner(_spinCols); 2207 2208 @Override 2209 protected void addAdditionalButtons(JPanel p) { 2210 bSpin.addActionListener(a -> addMemorySpinner()); 2211 JPanel p1 = new JPanel(); 2212 //p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS)); 2213 bBox.addActionListener(a -> addMemoryInputBox()); 2214 ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().setColumns(2); 2215 spinner.setMaximumSize(spinner.getPreferredSize()); 2216 JPanel p2 = new JPanel(); 2217 p2.add(new JLabel(Bundle.getMessage("NumColsLabel"))); 2218 p2.add(spinner); 2219 p1.add(p2); 2220 p1.add(bBox); 2221 p.add(p1); 2222 p1 = new JPanel(); 2223 p1.add(bSpin); 2224 p.add(p1); 2225 } 2226 2227 @Override 2228 public void valueChanged(ListSelectionEvent e) { 2229 super.valueChanged(e); 2230 bSpin.setEnabled(addIconIsEnabled()); 2231 bBox.setEnabled(addIconIsEnabled()); 2232 } 2233 }; 2234 ActionListener addIconAction = a -> putMemory(); 2235 JFrameItem frame = makeAddIconFrame("Memory", true, true, editor); 2236 _iconEditorFrame.put("Memory", frame); 2237 editor.setPickList(PickListModel.memoryPickModelInstance()); 2238 editor.makeIconPanel(true); 2239 editor.complete(addIconAction, false, true, false); 2240 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2241 } 2242 2243 protected void addGlobalVariableEditor() { 2244 IconAdder editor = new IconAdder("GlobalVariable") { 2245 final JButton bSpin = new JButton(Bundle.getMessage("AddSpinner")); 2246 final JButton bBox = new JButton(Bundle.getMessage("AddInputBox")); 2247 final JSpinner spinner = new JSpinner(_spinCols); 2248 2249 @Override 2250 protected void addAdditionalButtons(JPanel p) { 2251 bSpin.addActionListener(a -> addGlobalVariableSpinner()); 2252 JPanel p1 = new JPanel(); 2253 //p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS)); 2254 bBox.addActionListener(a -> addGlobalVariableInputBox()); 2255 ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().setColumns(2); 2256 spinner.setMaximumSize(spinner.getPreferredSize()); 2257 JPanel p2 = new JPanel(); 2258 p2.add(new JLabel(Bundle.getMessage("NumColsLabel"))); 2259 p2.add(spinner); 2260 p1.add(p2); 2261 p1.add(bBox); 2262 p.add(p1); 2263 p1 = new JPanel(); 2264 p1.add(bSpin); 2265 p.add(p1); 2266 } 2267 2268 @Override 2269 public void valueChanged(ListSelectionEvent e) { 2270 super.valueChanged(e); 2271 bSpin.setEnabled(addIconIsEnabled()); 2272 bBox.setEnabled(addIconIsEnabled()); 2273 } 2274 }; 2275 ActionListener addIconAction = a -> putGlobalVariable(); 2276 JFrameItem frame = makeAddIconFrame("GlobalVariable", true, true, editor); 2277 _iconEditorFrame.put("GlobalVariable", frame); 2278 editor.setPickList(PickListModel.globalVariablePickModelInstance()); 2279 editor.makeIconPanel(true); 2280 editor.complete(addIconAction, false, false, false); 2281 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2282 } 2283 2284 protected void addLogixNGTableEditor() { 2285 IconAdder editor = new IconAdder("LogixNGTable"); 2286 ActionListener addIconAction = a -> addLogixNGTable(); 2287 JFrameItem frame = makeAddIconFrame("LogixNGTable", true, true, editor); 2288 _iconEditorFrame.put("LogixNGTable", frame); 2289 editor.setPickList(PickListModel.namedTablePickModelInstance()); 2290 editor.makeIconPanel(true); 2291 editor.complete(addIconAction, false, false, false); 2292 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2293 } 2294 2295 protected void addBlockContentsEditor() { 2296 IconAdder editor = new IconAdder("Block Contents"); 2297 ActionListener addIconAction = a -> putBlockContents(); 2298 JFrameItem frame = makeAddIconFrame("BlockLabel", true, true, editor); 2299 _iconEditorFrame.put("BlockLabel", frame); 2300 editor.setPickList(PickListModel.blockPickModelInstance()); 2301 editor.makeIconPanel(true); 2302 editor.complete(addIconAction, false, true, false); 2303 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2304 } 2305 2306 protected void addReporterEditor() { 2307 IconAdder editor = new IconAdder("Reporter"); 2308 ActionListener addIconAction = a -> addReporter(); 2309 JFrameItem frame = makeAddIconFrame("Reporter", true, true, editor); 2310 _iconEditorFrame.put("Reporter", frame); 2311 editor.setPickList(PickListModel.reporterPickModelInstance()); 2312 editor.makeIconPanel(true); 2313 editor.complete(addIconAction, false, true, false); 2314 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2315 } 2316 2317 protected void addLightEditor() { 2318 IconAdder editor = new IconAdder("Light"); 2319 editor.setIcon(3, "StateOff", 2320 "resources/icons/smallschematics/lights/cross-on.png"); 2321 editor.setIcon(2, "StateOn", 2322 "resources/icons/smallschematics/lights/cross-off.png"); 2323 editor.setIcon(0, "BeanStateInconsistent", 2324 "resources/icons/smallschematics/lights/cross-inconsistent.png"); 2325 editor.setIcon(1, "BeanStateUnknown", 2326 "resources/icons/smallschematics/lights/cross-unknown.png"); 2327 2328 JFrameItem frame = makeAddIconFrame("Light", true, true, editor); 2329 _iconEditorFrame.put("Light", frame); 2330 editor.setPickList(PickListModel.lightPickModelInstance()); 2331 2332 ActionListener addIconAction = a -> addLight(); 2333 editor.makeIconPanel(true); 2334 editor.complete(addIconAction, true, true, false); 2335 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2336 } 2337 2338 protected void addBackgroundEditor() { 2339 IconAdder editor = new IconAdder("Background"); 2340 editor.setIcon(0, "background", "resources/PanelPro.gif"); 2341 2342 JFrameItem frame = makeAddIconFrame("Background", true, false, editor); 2343 _iconEditorFrame.put("Background", frame); 2344 2345 ActionListener addIconAction = a -> putBackground(); 2346 editor.makeIconPanel(true); 2347 editor.complete(addIconAction, true, false, false); 2348 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2349 } 2350 2351 protected JFrameItem addMultiSensorEditor() { 2352 MultiSensorIconAdder editor = new MultiSensorIconAdder("MultiSensor"); 2353 editor.setIcon(0, "BeanStateInconsistent", 2354 "resources/icons/USS/plate/levers/l-inconsistent.gif"); 2355 editor.setIcon(1, "BeanStateUnknown", 2356 "resources/icons/USS/plate/levers/l-unknown.gif"); 2357 editor.setIcon(2, "SensorStateInactive", 2358 "resources/icons/USS/plate/levers/l-inactive.gif"); 2359 editor.setIcon(3, "MultiSensorPosition 0", 2360 "resources/icons/USS/plate/levers/l-left.gif"); 2361 editor.setIcon(4, "MultiSensorPosition 1", 2362 "resources/icons/USS/plate/levers/l-vertical.gif"); 2363 editor.setIcon(5, "MultiSensorPosition 2", 2364 "resources/icons/USS/plate/levers/l-right.gif"); 2365 2366 JFrameItem frame = makeAddIconFrame("MultiSensor", true, false, editor); 2367 _iconEditorFrame.put("MultiSensor", frame); 2368 frame.addHelpMenu("package.jmri.jmrit.display.MultiSensorIconAdder", true); 2369 2370 editor.setPickList(PickListModel.sensorPickModelInstance()); 2371 2372 ActionListener addIconAction = a -> addMultiSensor(); 2373 editor.makeIconPanel(true); 2374 editor.complete(addIconAction, true, true, false); 2375 return frame; 2376 } 2377 2378 protected void addIconEditor() { 2379 IconAdder editor = new IconAdder("Icon"); 2380 editor.setIcon(0, "plainIcon", "resources/icons/smallschematics/tracksegments/block.gif"); 2381 JFrameItem frame = makeAddIconFrame("Icon", true, false, editor); 2382 _iconEditorFrame.put("Icon", frame); 2383 2384 ActionListener addIconAction = a -> putIcon(); 2385 editor.makeIconPanel(true); 2386 editor.complete(addIconAction, true, false, false); 2387 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2388 } 2389 2390 protected void addAudioEditor() { 2391 IconAdder editor = new IconAdder("Audio"); 2392 editor.setIcon(0, "plainIcon", "resources/icons/audio_icon.gif"); 2393 JFrameItem frame = makeAddIconFrame("Audio", true, false, editor); 2394 _iconEditorFrame.put("Audio", frame); 2395 editor.setPickList(PickListModel.audioPickModelInstance()); 2396 2397 ActionListener addIconAction = a -> putAudio(); 2398 editor.makeIconPanel(true); 2399 editor.complete(addIconAction, true, false, false); 2400 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2401 } 2402 2403 protected void addLogixNGEditor() { 2404 IconAdder editor = new IconAdder("LogixNG"); 2405 editor.setIcon(0, "plainIcon", "resources/icons/logixng/logixng_icon.gif"); 2406 JFrameItem frame = makeAddIconFrame("LogixNG", true, false, editor); 2407 _iconEditorFrame.put("LogixNG", frame); 2408 2409 ActionListener addIconAction = a -> putLogixNG(); 2410 editor.makeIconPanel(true); 2411 editor.complete(addIconAction, true, false, false); 2412 frame.addHelpMenu("package.jmri.jmrit.display.IconAdder", true); 2413 } 2414 2415 /* 2416 * ************** add content items from Icon Editors ******************* 2417 */ 2418 /** 2419 * Add a sensor indicator to the target. 2420 * 2421 * @return The sensor that was added to the panel. 2422 */ 2423 protected SensorIcon putSensor() { 2424 SensorIcon result = new SensorIcon(new NamedIcon("resources/icons/smallschematics/tracksegments/circuit-error.gif", 2425 "resources/icons/smallschematics/tracksegments/circuit-error.gif"), this); 2426 IconAdder editor = getIconEditor("Sensor"); 2427 Hashtable<String, NamedIcon> map = editor.getIconMap(); 2428 Enumeration<String> e = map.keys(); 2429 while (e.hasMoreElements()) { 2430 String key = e.nextElement(); 2431 result.setIcon(key, map.get(key)); 2432 } 2433// l.setActiveIcon(editor.getIcon("SensorStateActive")); 2434// l.setInactiveIcon(editor.getIcon("SensorStateInactive")); 2435// l.setInconsistentIcon(editor.getIcon("BeanStateInconsistent")); 2436// l.setUnknownIcon(editor.getIcon("BeanStateUnknown")); 2437 NamedBean b = editor.getTableSelection(); 2438 if (b != null) { 2439 result.setSensor(b.getDisplayName()); 2440 } 2441 result.setDisplayLevel(SENSORS); 2442 setNextLocation(result); 2443 try { 2444 putItem(result); 2445 } catch (Positionable.DuplicateIdException ex) { 2446 // This should never happen 2447 log.error("Editor.putItem() with null id has thrown DuplicateIdException", ex); 2448 } 2449 return result; 2450 } 2451 2452 /** 2453 * Add a turnout indicator to the target 2454 */ 2455 void addTurnoutR() { 2456 IconAdder editor = getIconEditor("RightTurnout"); 2457 addTurnout(editor); 2458 } 2459 2460 void addTurnoutL() { 2461 IconAdder editor = getIconEditor("LeftTurnout"); 2462 addTurnout(editor); 2463 } 2464 2465 protected TurnoutIcon addTurnout(IconAdder editor) { 2466 TurnoutIcon result = new TurnoutIcon(this); 2467 result.setTurnout(editor.getTableSelection().getDisplayName()); 2468 Hashtable<String, NamedIcon> map = editor.getIconMap(); 2469 Enumeration<String> e = map.keys(); 2470 while (e.hasMoreElements()) { 2471 String key = e.nextElement(); 2472 result.setIcon(key, map.get(key)); 2473 } 2474 result.setDisplayLevel(TURNOUTS); 2475 setNextLocation(result); 2476 try { 2477 putItem(result); 2478 } catch (Positionable.DuplicateIdException ex) { 2479 // This should never happen 2480 log.error("Editor.putItem() with null id has thrown DuplicateIdException", ex); 2481 } 2482 return result; 2483 } 2484 2485 @SuppressFBWarnings(value="BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification="iconEditor requested as exact type") 2486 SlipTurnoutIcon addSlip() { 2487 SlipTurnoutIcon result = new SlipTurnoutIcon(this); 2488 SlipIconAdder editor = (SlipIconAdder) getIconEditor("SlipTOEditor"); 2489 result.setSingleSlipRoute(editor.getSingleSlipRoute()); 2490 2491 switch (editor.getTurnoutType()) { 2492 case SlipTurnoutIcon.DOUBLESLIP: 2493 result.setLowerWestToUpperEastIcon(editor.getIcon("LowerWestToUpperEast")); 2494 result.setUpperWestToLowerEastIcon(editor.getIcon("UpperWestToLowerEast")); 2495 result.setLowerWestToLowerEastIcon(editor.getIcon("LowerWestToLowerEast")); 2496 result.setUpperWestToUpperEastIcon(editor.getIcon("UpperWestToUpperEast")); 2497 break; 2498 case SlipTurnoutIcon.SINGLESLIP: 2499 result.setLowerWestToUpperEastIcon(editor.getIcon("LowerWestToUpperEast")); 2500 result.setUpperWestToLowerEastIcon(editor.getIcon("UpperWestToLowerEast")); 2501 result.setLowerWestToLowerEastIcon(editor.getIcon("Slip")); 2502 result.setSingleSlipRoute(editor.getSingleSlipRoute()); 2503 break; 2504 case SlipTurnoutIcon.THREEWAY: 2505 result.setLowerWestToUpperEastIcon(editor.getIcon("Upper")); 2506 result.setUpperWestToLowerEastIcon(editor.getIcon("Middle")); 2507 result.setLowerWestToLowerEastIcon(editor.getIcon("Lower")); 2508 result.setSingleSlipRoute(editor.getSingleSlipRoute()); 2509 break; 2510 case SlipTurnoutIcon.SCISSOR: //Scissor is the same as a Double for icon storing. 2511 result.setLowerWestToUpperEastIcon(editor.getIcon("LowerWestToUpperEast")); 2512 result.setUpperWestToLowerEastIcon(editor.getIcon("UpperWestToLowerEast")); 2513 result.setLowerWestToLowerEastIcon(editor.getIcon("LowerWestToLowerEast")); 2514 //l.setUpperWestToUpperEastIcon(editor.getIcon("UpperWestToUpperEast")); 2515 break; 2516 default: 2517 log.warn("Unexpected addSlip editor.getTurnoutType() of {}", editor.getTurnoutType()); 2518 break; 2519 } 2520 2521 if ((editor.getTurnoutType() == SlipTurnoutIcon.SCISSOR) && (!editor.getSingleSlipRoute())) { 2522 result.setTurnout(editor.getTurnout("lowerwest").getName(), SlipTurnoutIcon.LOWERWEST); 2523 result.setTurnout(editor.getTurnout("lowereast").getName(), SlipTurnoutIcon.LOWEREAST); 2524 } 2525 result.setInconsistentIcon(editor.getIcon("BeanStateInconsistent")); 2526 result.setUnknownIcon(editor.getIcon("BeanStateUnknown")); 2527 result.setTurnoutType(editor.getTurnoutType()); 2528 result.setTurnout(editor.getTurnout("west").getName(), SlipTurnoutIcon.WEST); 2529 result.setTurnout(editor.getTurnout("east").getName(), SlipTurnoutIcon.EAST); 2530 result.setDisplayLevel(TURNOUTS); 2531 setNextLocation(result); 2532 try { 2533 putItem(result); 2534 } catch (Positionable.DuplicateIdException e) { 2535 // This should never happen 2536 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2537 } 2538 return result; 2539 } 2540 2541 /** 2542 * Add a signal head to the target. 2543 * 2544 * @return The signal head that was added to the target. 2545 */ 2546 protected SignalHeadIcon putSignalHead() { 2547 SignalHeadIcon result = new SignalHeadIcon(this); 2548 IconAdder editor = getIconEditor("SignalHead"); 2549 result.setSignalHead(editor.getTableSelection().getDisplayName()); 2550 Hashtable<String, NamedIcon> map = editor.getIconMap(); 2551 Enumeration<String> e = map.keys(); 2552 while (e.hasMoreElements()) { 2553 String key = e.nextElement(); 2554 result.setIcon(key, map.get(key)); 2555 } 2556 result.setDisplayLevel(SIGNALS); 2557 setNextLocation(result); 2558 try { 2559 putItem(result); 2560 } catch (Positionable.DuplicateIdException ex) { 2561 // This should never happen 2562 log.error("Editor.putItem() with null id has thrown DuplicateIdException", ex); 2563 } 2564 return result; 2565 } 2566 2567 /** 2568 * Add a signal mast to the target. 2569 * 2570 * @return The signal mast that was added to the target. 2571 */ 2572 protected SignalMastIcon putSignalMast() { 2573 SignalMastIcon result = new SignalMastIcon(this); 2574 IconAdder editor = _iconEditorFrame.get("SignalMast").getEditor(); 2575 result.setSignalMast(editor.getTableSelection().getDisplayName()); 2576 result.setDisplayLevel(SIGNALS); 2577 setNextLocation(result); 2578 try { 2579 putItem(result); 2580 } catch (Positionable.DuplicateIdException e) { 2581 // This should never happen 2582 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2583 } 2584 return result; 2585 } 2586 2587 protected MemoryIcon putMemory() { 2588 MemoryIcon result = new MemoryIcon(new NamedIcon("resources/icons/misc/X-red.gif", 2589 "resources/icons/misc/X-red.gif"), this); 2590 IconAdder memoryIconEditor = getIconEditor("Memory"); 2591 result.setMemory(memoryIconEditor.getTableSelection().getDisplayName()); 2592 result.setSize(result.getPreferredSize().width, result.getPreferredSize().height); 2593 result.setDisplayLevel(MEMORIES); 2594 setNextLocation(result); 2595 try { 2596 putItem(result); 2597 } catch (Positionable.DuplicateIdException e) { 2598 // This should never happen 2599 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2600 } 2601 return result; 2602 } 2603 2604 protected MemorySpinnerIcon addMemorySpinner() { 2605 MemorySpinnerIcon result = new MemorySpinnerIcon(this); 2606 IconAdder memoryIconEditor = getIconEditor("Memory"); 2607 result.setMemory(memoryIconEditor.getTableSelection().getDisplayName()); 2608 result.setSize(result.getPreferredSize().width, result.getPreferredSize().height); 2609 result.setDisplayLevel(MEMORIES); 2610 setNextLocation(result); 2611 try { 2612 putItem(result); 2613 } catch (Positionable.DuplicateIdException e) { 2614 // This should never happen 2615 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2616 } 2617 return result; 2618 } 2619 2620 protected MemoryInputIcon addMemoryInputBox() { 2621 MemoryInputIcon result = new MemoryInputIcon(_spinCols.getNumber().intValue(), this); 2622 IconAdder memoryIconEditor = getIconEditor("Memory"); 2623 result.setMemory(memoryIconEditor.getTableSelection().getDisplayName()); 2624 result.setSize(result.getPreferredSize().width, result.getPreferredSize().height); 2625 result.setDisplayLevel(MEMORIES); 2626 setNextLocation(result); 2627 try { 2628 putItem(result); 2629 } catch (Positionable.DuplicateIdException e) { 2630 // This should never happen 2631 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2632 } 2633 return result; 2634 } 2635 2636 protected GlobalVariableIcon putGlobalVariable() { 2637 GlobalVariableIcon result = new GlobalVariableIcon(new NamedIcon("resources/icons/misc/X-red.gif", 2638 "resources/icons/misc/X-red.gif"), this); 2639 IconAdder globalVariableIconEditor = getIconEditor("GlobalVariable"); 2640 result.setGlobalVariable(globalVariableIconEditor.getTableSelection().getDisplayName()); 2641 result.setSize(result.getPreferredSize().width, result.getPreferredSize().height); 2642 result.setDisplayLevel(MEMORIES); 2643 setNextLocation(result); 2644 try { 2645 putItem(result); 2646 } catch (Positionable.DuplicateIdException e) { 2647 // This should never happen 2648 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2649 } 2650 return result; 2651 } 2652 2653 protected GlobalVariableSpinnerIcon addGlobalVariableSpinner() { 2654 GlobalVariableSpinnerIcon result = new GlobalVariableSpinnerIcon(this); 2655 IconAdder globalVariableIconEditor = getIconEditor("GlobalVariable"); 2656 result.setGlobalVariable(globalVariableIconEditor.getTableSelection().getDisplayName()); 2657 result.setSize(result.getPreferredSize().width, result.getPreferredSize().height); 2658 result.setDisplayLevel(MEMORIES); 2659 setNextLocation(result); 2660 try { 2661 putItem(result); 2662 } catch (Positionable.DuplicateIdException e) { 2663 // This should never happen 2664 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2665 } 2666 return result; 2667 } 2668 2669 protected GlobalVariableInputIcon addGlobalVariableInputBox() { 2670 GlobalVariableInputIcon result = new GlobalVariableInputIcon(_spinCols.getNumber().intValue(), this); 2671 IconAdder globalVariableIconEditor = getIconEditor("GlobalVariable"); 2672 result.setGlobalVariable(globalVariableIconEditor.getTableSelection().getDisplayName()); 2673 result.setSize(result.getPreferredSize().width, result.getPreferredSize().height); 2674 result.setDisplayLevel(MEMORIES); 2675 setNextLocation(result); 2676 try { 2677 putItem(result); 2678 } catch (Positionable.DuplicateIdException e) { 2679 // This should never happen 2680 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2681 } 2682 return result; 2683 } 2684 2685 protected LogixNGTableIcon addLogixNGTable() { 2686 IconAdder logixNGTableIconEditor = getIconEditor("LogixNGTable"); 2687 LogixNGTableIcon result = new LogixNGTableIcon(logixNGTableIconEditor.getTableSelection().getDisplayName(), this); 2688 result.setSize(result.getPreferredSize().width, result.getPreferredSize().height); 2689 result.setDisplayLevel(MEMORIES); 2690 setNextLocation(result); 2691 try { 2692 putItem(result); 2693 } catch (Positionable.DuplicateIdException e) { 2694 // This should never happen 2695 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2696 } 2697 return result; 2698 } 2699 2700 protected BlockContentsIcon putBlockContents() { 2701 BlockContentsIcon result = new BlockContentsIcon(new NamedIcon("resources/icons/misc/X-red.gif", 2702 "resources/icons/misc/X-red.gif"), this); 2703 IconAdder blockIconEditor = getIconEditor("BlockLabel"); 2704 result.setBlock(blockIconEditor.getTableSelection().getDisplayName()); 2705 result.setSize(result.getPreferredSize().width, result.getPreferredSize().height); 2706 result.setDisplayLevel(MEMORIES); 2707 setNextLocation(result); 2708 try { 2709 putItem(result); 2710 } catch (Positionable.DuplicateIdException e) { 2711 // This should never happen 2712 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2713 } 2714 return result; 2715 } 2716 2717 /** 2718 * Add a Light indicator to the target 2719 * 2720 * @return The light indicator that was added to the target. 2721 */ 2722 protected LightIcon addLight() { 2723 LightIcon result = new LightIcon(this); 2724 IconAdder editor = getIconEditor("Light"); 2725 result.setOffIcon(editor.getIcon("StateOff")); 2726 result.setOnIcon(editor.getIcon("StateOn")); 2727 result.setInconsistentIcon(editor.getIcon("BeanStateInconsistent")); 2728 result.setUnknownIcon(editor.getIcon("BeanStateUnknown")); 2729 result.setLight((Light) editor.getTableSelection()); 2730 result.setDisplayLevel(LIGHTS); 2731 setNextLocation(result); 2732 try { 2733 putItem(result); 2734 } catch (Positionable.DuplicateIdException e) { 2735 // This should never happen 2736 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2737 } 2738 return result; 2739 } 2740 2741 protected ReporterIcon addReporter() { 2742 ReporterIcon result = new ReporterIcon(this); 2743 IconAdder reporterIconEditor = getIconEditor("Reporter"); 2744 result.setReporter((Reporter) reporterIconEditor.getTableSelection()); 2745 result.setSize(result.getPreferredSize().width, result.getPreferredSize().height); 2746 result.setDisplayLevel(REPORTERS); 2747 setNextLocation(result); 2748 try { 2749 putItem(result); 2750 } catch (Positionable.DuplicateIdException e) { 2751 // This should never happen 2752 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2753 } 2754 return result; 2755 } 2756 2757 /** 2758 * Button pushed, add a background image. Note that a background image 2759 * differs from a regular icon only in the level at which it's presented. 2760 */ 2761 void putBackground() { 2762 // most likely the image is scaled. get full size from URL 2763 IconAdder bkgrndEditor = getIconEditor("Background"); 2764 String url = bkgrndEditor.getIcon("background").getURL(); 2765 setUpBackground(url); 2766 } 2767 2768 /** 2769 * Add an icon to the target. 2770 * 2771 * @return The icon that was added to the target. 2772 */ 2773 protected Positionable putIcon() { 2774 IconAdder iconEditor = getIconEditor("Icon"); 2775 String url = iconEditor.getIcon("plainIcon").getURL(); 2776 NamedIcon icon = NamedIcon.getIconByName(url); 2777 if (log.isDebugEnabled()) { 2778 log.debug("putIcon: {} url= {}", (icon == null ? "null" : "icon"), url); 2779 } 2780 PositionableLabel result = new PositionableLabel(icon, this); 2781// l.setPopupUtility(null); // no text 2782 result.setDisplayLevel(ICONS); 2783 setNextLocation(result); 2784 try { 2785 putItem(result); 2786 } catch (Positionable.DuplicateIdException e) { 2787 // This should never happen 2788 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2789 } 2790 result.updateSize(); 2791 return result; 2792 } 2793 2794 /** 2795 * Add a LogixNG icon to the target. 2796 * 2797 * @return The LogixNG icon that was added to the target. 2798 */ 2799 protected Positionable putAudio() { 2800 IconAdder iconEditor = getIconEditor("Audio"); 2801 String url = iconEditor.getIcon("plainIcon").getURL(); 2802 NamedIcon icon = NamedIcon.getIconByName(url); 2803 if (log.isDebugEnabled()) { 2804 log.debug("putAudio: {} url= {}", (icon == null ? "null" : "icon"), url); 2805 } 2806 AudioIcon result = new AudioIcon(icon, this); 2807 NamedBean b = iconEditor.getTableSelection(); 2808 if (b != null) { 2809 result.setAudio(b.getDisplayName()); 2810 } 2811// l.setPopupUtility(null); // no text 2812 result.setDisplayLevel(ICONS); 2813 setNextLocation(result); 2814 try { 2815 putItem(result); 2816 } catch (Positionable.DuplicateIdException e) { 2817 // This should never happen 2818 log.error("Editor.putAudio() with null id has thrown DuplicateIdException", e); 2819 } 2820 result.updateSize(); 2821 return result; 2822 } 2823 2824 /** 2825 * Add a LogixNG icon to the target. 2826 * 2827 * @return The LogixNG icon that was added to the target. 2828 */ 2829 protected Positionable putLogixNG() { 2830 IconAdder iconEditor = getIconEditor("LogixNG"); 2831 String url = iconEditor.getIcon("plainIcon").getURL(); 2832 NamedIcon icon = NamedIcon.getIconByName(url); 2833 if (log.isDebugEnabled()) { 2834 log.debug("putLogixNG: {} url= {}", (icon == null ? "null" : "icon"), url); 2835 } 2836 LogixNGIcon result = new LogixNGIcon(icon, this); 2837// l.setPopupUtility(null); // no text 2838 result.setDisplayLevel(ICONS); 2839 setNextLocation(result); 2840 try { 2841 putItem(result); 2842 } catch (Positionable.DuplicateIdException e) { 2843 // This should never happen 2844 log.error("Editor.putLogixNG() with null id has thrown DuplicateIdException", e); 2845 } 2846 result.updateSize(); 2847 return result; 2848 } 2849 2850 @SuppressFBWarnings(value="BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification="iconEditor requested as exact type") 2851 public MultiSensorIcon addMultiSensor() { 2852 MultiSensorIcon result = new MultiSensorIcon(this); 2853 MultiSensorIconAdder editor = (MultiSensorIconAdder) getIconEditor("MultiSensor"); 2854 result.setUnknownIcon(editor.getIcon("BeanStateUnknown")); 2855 result.setInconsistentIcon(editor.getIcon("BeanStateInconsistent")); 2856 result.setInactiveIcon(editor.getIcon("SensorStateInactive")); 2857 int numPositions = editor.getNumIcons(); 2858 for (int i = 3; i < numPositions; i++) { 2859 NamedIcon icon = editor.getIcon(i); 2860 String sensor = editor.getSensor(i).getName(); 2861 result.addEntry(sensor, icon); 2862 } 2863 result.setUpDown(editor.getUpDown()); 2864 result.setDisplayLevel(SENSORS); 2865 setNextLocation(result); 2866 try { 2867 putItem(result); 2868 } catch (Positionable.DuplicateIdException e) { 2869 // This should never happen 2870 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2871 } 2872 return result; 2873 } 2874 2875 protected AnalogClock2Display addClock() { 2876 AnalogClock2Display result = new AnalogClock2Display(this); 2877 result.setOpaque(false); 2878 result.update(); 2879 result.setDisplayLevel(CLOCK); 2880 setNextLocation(result); 2881 try { 2882 putItem(result); 2883 } catch (Positionable.DuplicateIdException e) { 2884 // This should never happen 2885 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2886 } 2887 return result; 2888 } 2889 2890 protected RpsPositionIcon addRpsReporter() { 2891 RpsPositionIcon result = new RpsPositionIcon(this); 2892 result.setSize(result.getPreferredSize().width, result.getPreferredSize().height); 2893 result.setDisplayLevel(SENSORS); 2894 setNextLocation(result); 2895 try { 2896 putItem(result); 2897 } catch (Positionable.DuplicateIdException e) { 2898 // This should never happen 2899 log.error("Editor.putItem() with null id has thrown DuplicateIdException", e); 2900 } 2901 return result; 2902 } 2903 2904 /* 2905 * ****************** end adding content ******************** 2906 */ 2907 /* 2908 * ********************* Icon Editors utils *************************** 2909 */ 2910 public static class JFrameItem extends JmriJFrame { 2911 2912 private final IconAdder _editor; 2913 2914 JFrameItem(String name, IconAdder editor) { 2915 super(name); 2916 _editor = editor; 2917 setName(name); 2918 } 2919 2920 public IconAdder getEditor() { 2921 return _editor; 2922 } 2923 2924 @Override 2925 public String toString() { 2926 return this.getName(); 2927 } 2928 } 2929 2930 public void setTitle() { 2931 String name = _targetFrame.getTitle(); 2932 if (name == null || name.equals("")) { 2933 super.setTitle(Bundle.getMessage("LabelEditor")); 2934 } else { 2935 super.setTitle(name + " " + Bundle.getMessage("LabelEditor")); 2936 } 2937 for (JFrameItem frame : _iconEditorFrame.values()) { 2938 frame.setTitle(frame.getName() + " (" + name + ")"); 2939 } 2940 setName(name); 2941 } 2942 2943 /** 2944 * Create a frame showing all images in the set used for an icon. 2945 * Opened when editItemInPanel button is clicked in the Edit Icon Panel, 2946 * shown after icon's context menu Edit Icon... item is selected. 2947 * 2948 * @param name bean type name 2949 * @param add true when used to add a new item on panel, false when used to edit an item already on the panel 2950 * @param table true for bean types presented as table instead of icons 2951 * @param editor parent frame of the image frame 2952 * @return JFrame connected to the editor, to be filled with icons 2953 */ 2954 public JFrameItem makeAddIconFrame(String name, boolean add, boolean table, IconAdder editor) { 2955 log.debug("makeAddIconFrame for {}, add= {}, table= {}", name, add, table); 2956 String txt; 2957 String bundleName; 2958 JFrameItem frame = new JFrameItem(name, editor); 2959 // use NamedBeanBundle property for basic beans like "Turnout" I18N 2960 if ("Sensor".equals(name)) { 2961 bundleName = "BeanNameSensor"; 2962 } else if ("SignalHead".equals(name)) { 2963 bundleName = "BeanNameSignalHead"; 2964 } else if ("SignalMast".equals(name)) { 2965 bundleName = "BeanNameSignalMast"; 2966 } else if ("Memory".equals(name)) { 2967 bundleName = "BeanNameMemory"; 2968 } else if ("Reporter".equals(name)) { 2969 bundleName = "BeanNameReporter"; 2970 } else if ("Light".equals(name)) { 2971 bundleName = "BeanNameLight"; 2972 } else if ("Turnout".equals(name)) { 2973 bundleName = "BeanNameTurnout"; // called by RightTurnout and LeftTurnout objects in TurnoutIcon.java edit() method 2974 } else if ("Block".equals(name)) { 2975 bundleName = "BeanNameBlock"; 2976 } else if ("GlobalVariable".equals(name)) { 2977 bundleName = "BeanNameGlobalVariable"; 2978 } else if ("LogixNGTable".equals(name)) { 2979 bundleName = "BeanNameLogixNGTable"; 2980 } else if ("Audio".equals(name)) { 2981 bundleName = "BeanNameAudio"; 2982 } else { 2983 bundleName = name; 2984 } 2985 if (editor != null) { 2986 JPanel p = new JPanel(); 2987 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); 2988 if (add) { 2989 txt = MessageFormat.format(Bundle.getMessage("addItemToPanel"), Bundle.getMessage(bundleName)); 2990 } else { 2991 txt = MessageFormat.format(Bundle.getMessage("editItemInPanel"), Bundle.getMessage(bundleName)); 2992 } 2993 p.add(new JLabel(txt)); 2994 if (table) { 2995 txt = MessageFormat.format(Bundle.getMessage("TableSelect"), Bundle.getMessage(bundleName), 2996 (add ? Bundle.getMessage("ButtonAddIcon") : Bundle.getMessage("ButtonUpdateIcon"))); 2997 } else { 2998 if ("MultiSensor".equals(name)) { 2999 txt = MessageFormat.format(Bundle.getMessage("SelectMultiSensor", Bundle.getMessage("ButtonAddIcon")), 3000 (add ? Bundle.getMessage("ButtonAddIcon") : Bundle.getMessage("ButtonUpdateIcon"))); 3001 } else { 3002 txt = MessageFormat.format(Bundle.getMessage("IconSelect"), Bundle.getMessage(bundleName), 3003 (add ? Bundle.getMessage("ButtonAddIcon") : Bundle.getMessage("ButtonUpdateIcon"))); 3004 } 3005 } 3006 p.add(new JLabel(txt)); 3007 p.add(new JLabel(" ")); // add a bit of space on pane above icons 3008 frame.getContentPane().add(p, BorderLayout.NORTH); 3009 frame.getContentPane().add(editor); 3010 3011 JMenuBar menuBar = new JMenuBar(); 3012 JMenu findIcon = new JMenu(Bundle.getMessage("findIconMenu")); 3013 menuBar.add(findIcon); 3014 3015 JMenuItem editItem = new JMenuItem(Bundle.getMessage("editIndexMenu")); 3016 editItem.addActionListener(e -> { 3017 ImageIndexEditor ii = InstanceManager.getDefault(ImageIndexEditor.class); 3018 ii.pack(); 3019 ii.setVisible(true); 3020 }); 3021 findIcon.add(editItem); 3022 findIcon.addSeparator(); 3023 3024 JMenuItem searchItem = new JMenuItem(Bundle.getMessage("searchFSMenu")); 3025 searchItem.addActionListener(new ActionListener() { 3026 private IconAdder ea; 3027 3028 @Override 3029 public void actionPerformed(ActionEvent e) { 3030 InstanceManager.getDefault(DirectorySearcher.class).searchFS(); 3031 ea.addDirectoryToCatalog(); 3032 } 3033 3034 ActionListener init(IconAdder ed) { 3035 ea = ed; 3036 return this; 3037 } 3038 }.init(editor)); 3039 3040 findIcon.add(searchItem); 3041 frame.setJMenuBar(menuBar); 3042 editor.setParent(frame); 3043 // when this window closes, check for saving 3044 if (add) { 3045 frame.addWindowListener(new WindowAdapter() { 3046 @Override 3047 public void windowClosing(WindowEvent e) { 3048 setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); 3049 if (log.isDebugEnabled()) { 3050 log.debug("windowClosing: HIDE {}", toString()); 3051 } 3052 } 3053 }); 3054 } 3055 } else { 3056 log.error("No icon editor specified for {}", name); // NOI18N 3057 } 3058 if (add) { 3059 txt = MessageFormat.format(Bundle.getMessage("AddItem"), Bundle.getMessage(bundleName)); 3060 _iconEditorFrame.put(name, frame); 3061 } else { 3062 txt = MessageFormat.format(Bundle.getMessage("EditItem"), Bundle.getMessage(bundleName)); 3063 } 3064 frame.setTitle(txt + " (" + getTitle() + ")"); 3065 frame.pack(); 3066 return frame; 3067 } 3068 3069 /* 3070 * ******************* cleanup ************************ 3071 */ 3072 protected void removeFromTarget(@Nonnull Positionable l) { 3073 Point p = l.getLocation(); 3074 _targetPanel.remove((Component) l); 3075 _highlightcomponent = null; 3076 int w = Math.max( l.maxWidth(), l.getWidth()); 3077 int h = Math.max( l.maxHeight(), l.getHeight()); 3078 _targetPanel.revalidate(); 3079 _targetPanel.repaint(p.x, p.y, w, h); 3080 } 3081 3082 public boolean removeFromContents(@Nonnull Positionable l) { 3083 removeFromTarget(l); 3084 //todo check that parent == _targetPanel 3085 //Container parent = this.getParent(); 3086 // force redisplay 3087 if (l.getId() != null) { 3088 _idContents.remove(l.getId()); 3089 } 3090 for (String className : l.getClasses()) { 3091 _classContents.get(className).remove(l); 3092 } 3093 return _contents.remove(l); 3094 } 3095 3096 /** 3097 * Ask user the user to decide what to do with LogixNGs, whether to delete them 3098 * or convert them to normal LogixNGs. Then respond to user's choice. 3099 */ 3100 private void dispositionLogixNGs() { 3101 ArrayList<LogixNG> logixNGArrayList = new ArrayList<>(); 3102 for (Positionable _content : _contents) { 3103 if (_content.getLogixNG() != null) { 3104 LogixNG logixNG = _content.getLogixNG(); 3105 logixNGArrayList.add(logixNG); 3106 } 3107 } 3108 if (!logixNGArrayList.isEmpty()) { 3109 LogixNGDeleteDialog logixNGDeleteDialog = new LogixNGDeleteDialog(this, getTitle(), logixNGArrayList); 3110 logixNGDeleteDialog.setVisible(true); 3111 List<LogixNG> selectedItems = logixNGDeleteDialog.getSelectedItems(); 3112 for (LogixNG logixNG : selectedItems) { 3113 deleteLogixNG_Internal(logixNG); 3114 logixNGArrayList.remove(logixNG); 3115 } 3116 for (LogixNG logixNG : logixNGArrayList) { 3117 logixNG.setInline(false); 3118 logixNG.setEnabled(!logixNGDeleteDialog.isDisableLogixNG()); 3119 } 3120 } 3121 } 3122 3123 /** 3124 * Ask user if panel should be deleted. The caller should dispose the panel 3125 * to delete it. 3126 * 3127 * @return true if panel should be deleted. 3128 */ 3129 public boolean deletePanel() { 3130 log.debug("deletePanel"); 3131 // verify deletion 3132 int selectedValue = JmriJOptionPane.showOptionDialog(_targetPanel, 3133 Bundle.getMessage("QuestionA") + "\n" + Bundle.getMessage("QuestionA2", 3134 Bundle.getMessage("FileMenuItemStore")), 3135 Bundle.getMessage("DeleteVerifyTitle"), JmriJOptionPane.DEFAULT_OPTION, 3136 JmriJOptionPane.QUESTION_MESSAGE, null, 3137 new Object[]{Bundle.getMessage("ButtonYesDelete"), Bundle.getMessage("ButtonCancel")}, 3138 Bundle.getMessage("ButtonCancel")); 3139 // return without deleting if "Cancel" or Cancel Dialog response 3140 if (selectedValue == 0) { 3141 dispositionLogixNGs(); 3142 } 3143 return (selectedValue == 0 ); // array position 0 = Yes, Delete. 3144 } 3145 3146 /** 3147 * Dispose of the editor. 3148 */ 3149 @Override 3150 public void dispose() { 3151 for (JFrameItem frame : _iconEditorFrame.values()) { 3152 frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 3153 frame.dispose(); 3154 } 3155 // delete panel - deregister the panel for saving 3156 ConfigureManager cm = InstanceManager.getNullableDefault(ConfigureManager.class); 3157 if (cm != null) { 3158 cm.deregister(this); 3159 } 3160 InstanceManager.getDefault(EditorManager.class).remove(this); 3161 setVisible(false); 3162 _contents.clear(); 3163 _idContents.clear(); 3164 for (var list : _classContents.values()) { 3165 list.clear(); 3166 } 3167 _classContents.clear(); 3168 removeAll(); 3169 super.dispose(); 3170 } 3171 3172 /* 3173 * **************** Mouse Methods ********************** 3174 */ 3175 public void showToolTip(Positionable selection, JmriMouseEvent event) { 3176 ToolTip tip = selection.getToolTip(); 3177 tip.setLocation(selection.getX() + selection.getWidth() / 2, selection.getY() + selection.getHeight()); 3178 setToolTip(tip); 3179 } 3180 3181 protected int getItemX(Positionable p, int deltaX) { 3182 if ((p instanceof MemoryOrGVIcon) && (p.getPopupUtility().getFixedWidth() == 0)) { 3183 MemoryOrGVIcon pm = (MemoryOrGVIcon) p; 3184 return pm.getOriginalX() + (int) Math.round(deltaX / getPaintScale()); 3185 } else { 3186 return p.getX() + (int) Math.round(deltaX / getPaintScale()); 3187 } 3188 } 3189 3190 protected int getItemY(Positionable p, int deltaY) { 3191 if ((p instanceof MemoryOrGVIcon) && (p.getPopupUtility().getFixedWidth() == 0)) { 3192 MemoryOrGVIcon pm = (MemoryOrGVIcon) p; 3193 return pm.getOriginalY() + (int) Math.round(deltaY / getPaintScale()); 3194 } else { 3195 return p.getY() + (int) Math.round(deltaY / getPaintScale()); 3196 } 3197 } 3198 3199 /** 3200 * Provide a method for external code to add items to context menus. 3201 * 3202 * @param nb The namedBean associated with the postionable item. 3203 * @param item The entry to add to the menu. 3204 * @param menu The menu to add the entry to. 3205 */ 3206 public void addToPopUpMenu(NamedBean nb, JMenuItem item, int menu) { 3207 if (nb == null || item == null) { 3208 return; 3209 } 3210 for (Positionable pos : _contents) { 3211 if (pos.getNamedBean() == nb && pos.getPopupUtility() != null) { 3212 addToPopUpMenu( pos, item, menu); 3213 return; 3214 } else if (pos instanceof SlipTurnoutIcon) { 3215 if (pos.getPopupUtility() != null) { 3216 SlipTurnoutIcon sti = (SlipTurnoutIcon) pos; 3217 if ( sti.getTurnout(SlipTurnoutIcon.EAST) == nb || sti.getTurnout(SlipTurnoutIcon.WEST) == nb 3218 || sti.getTurnout(SlipTurnoutIcon.LOWEREAST) == nb 3219 || sti.getTurnout(SlipTurnoutIcon.LOWERWEST) == nb) { 3220 addToPopUpMenu( pos, item, menu); 3221 return; 3222 } 3223 } 3224 } else if ( pos instanceof MultiSensorIcon && pos.getPopupUtility() != null) { 3225 MultiSensorIcon msi = (MultiSensorIcon) pos; 3226 for (int i = 0; i < msi.getNumEntries(); i++) { 3227 if ( msi.getSensorName(i).equals(nb.getUserName()) 3228 || msi.getSensorName(i).equals(nb.getSystemName())) { 3229 addToPopUpMenu( pos, item, menu); 3230 return; 3231 } 3232 } 3233 } 3234 } 3235 } 3236 3237 private void addToPopUpMenu( Positionable pos, JMenuItem item, int menu ) { 3238 switch (menu) { 3239 case VIEWPOPUPONLY: 3240 pos.getPopupUtility().addViewPopUpMenu(item); 3241 break; 3242 case EDITPOPUPONLY: 3243 pos.getPopupUtility().addEditPopUpMenu(item); 3244 break; 3245 default: 3246 pos.getPopupUtility().addEditPopUpMenu(item); 3247 pos.getPopupUtility().addViewPopUpMenu(item); 3248 } 3249 } 3250 3251 public static final int VIEWPOPUPONLY = 0x00; 3252 public static final int EDITPOPUPONLY = 0x01; 3253 public static final int BOTHPOPUPS = 0x02; 3254 3255 /** 3256 * Relocate item. 3257 * <p> 3258 * Note that items can not be moved past the left or top edges of the panel. 3259 * 3260 * @param p The item to move. 3261 * @param deltaX The horizontal displacement. 3262 * @param deltaY The vertical displacement. 3263 */ 3264 public void moveItem(Positionable p, int deltaX, int deltaY) { 3265 //log.debug("moveItem at ({},{}) delta ({},{})", p.getX(), p.getY(), deltaX, deltaY); 3266 if (getFlag(OPTION_POSITION, p.isPositionable())) { 3267 int xObj = getItemX(p, deltaX); 3268 int yObj = getItemY(p, deltaY); 3269 // don't allow negative placement, icon can become unreachable 3270 if (xObj < 0) { 3271 xObj = 0; 3272 } 3273 if (yObj < 0) { 3274 yObj = 0; 3275 } 3276 p.setLocation(xObj, yObj); 3277 // and show! 3278 p.repaint(); 3279 } 3280 } 3281 3282 /** 3283 * Return a List of all items whose bounding rectangle contain the mouse 3284 * position. ordered from top level to bottom 3285 * 3286 * @param event contains the mouse position. 3287 * @return a list of positionable items or an empty list. 3288 */ 3289 protected List<Positionable> getSelectedItems(JmriMouseEvent event) { 3290 Rectangle rect = new Rectangle(); 3291 ArrayList<Positionable> selections = new ArrayList<>(); 3292 for (Positionable p : _contents) { 3293 double x = event.getX(); 3294 double y = event.getY(); 3295 rect = p.getBounds(rect); 3296 if (p instanceof jmri.jmrit.display.controlPanelEditor.shape.PositionableShape 3297 && p.getDegrees() != 0) { 3298 double rad = p.getDegrees() * Math.PI / 180.0; 3299 java.awt.geom.AffineTransform t = java.awt.geom.AffineTransform.getRotateInstance(-rad); 3300 double[] pt = new double[2]; 3301 // bit shift to avoid SpotBugs paranoia 3302 pt[0] = x - rect.x - (rect.width >>> 1); 3303 pt[1] = y - rect.y - (rect.height >>> 1); 3304 t.transform(pt, 0, pt, 0, 1); 3305 x = pt[0] + rect.x + (rect.width >>> 1); 3306 y = pt[1] + rect.y + (rect.height >>> 1); 3307 } 3308 Rectangle2D.Double rect2D = new Rectangle2D.Double(rect.x * _paintScale, 3309 rect.y * _paintScale, 3310 rect.width * _paintScale, 3311 rect.height * _paintScale); 3312 if (rect2D.contains(x, y) && (p.getDisplayLevel() > BKG || event.isControlDown())) { 3313 boolean added = false; 3314 int level = p.getDisplayLevel(); 3315 for (int k = 0; k < selections.size(); k++) { 3316 if (level >= selections.get(k).getDisplayLevel()) { 3317 selections.add(k, p); 3318 added = true; // OK to lie in the case of background icon 3319 break; 3320 } 3321 } 3322 if (!added) { 3323 selections.add(p); 3324 } 3325 } 3326 } 3327 //log.debug("getSelectedItems at ({},{}) {} found,", x, y, selections.size()); 3328 return selections; 3329 } 3330 3331 /* 3332 * Gather all items inside _selectRect 3333 * Keep old group if Control key is down 3334 */ 3335 protected void makeSelectionGroup(JmriMouseEvent event) { 3336 if (!event.isControlDown() || _selectionGroup == null) { 3337 _selectionGroup = new ArrayList<>(); 3338 } 3339 Rectangle test = new Rectangle(); 3340 List<Positionable> list = getContents(); 3341 if (event.isShiftDown()) { 3342 for (Positionable comp : list) { 3343 if (_selectRect.intersects(comp.getBounds(test)) 3344 && (event.isControlDown() || comp.getDisplayLevel() > BKG)) { 3345 _selectionGroup.add(comp); 3346 //log.debug("makeSelectionGroup: selection: {}, class= {}", comp.getNameString(), comp.getClass().getName()); 3347 } 3348 } 3349 } else { 3350 for (Positionable comp : list) { 3351 if (_selectRect.contains(comp.getBounds(test)) 3352 && (event.isControlDown() || comp.getDisplayLevel() > BKG)) { 3353 _selectionGroup.add(comp); 3354 //log.debug("makeSelectionGroup: selection: {}, class= {}", comp.getNameString(), comp.getClass().getName()); 3355 } 3356 } 3357 } 3358 log.debug("makeSelectionGroup: {} selected.", _selectionGroup.size()); 3359 if (_selectionGroup.size() < 1) { 3360 _selectRect = null; 3361 deselectSelectionGroup(); 3362 } 3363 } 3364 3365 /* 3366 * For the param, selection, Add to or delete from _selectionGroup. 3367 * If not there, add. 3368 * If there, delete. 3369 * make new group if Cntl key is not held down 3370 */ 3371 protected void modifySelectionGroup(Positionable selection, JmriMouseEvent event) { 3372 if (!event.isControlDown() || _selectionGroup == null) { 3373 _selectionGroup = new ArrayList<>(); 3374 } 3375 boolean removed = false; 3376 if (event.isControlDown()) { 3377 if (selection.getDisplayLevel() > BKG) { 3378 if (_selectionGroup.contains(selection)) { 3379 removed = _selectionGroup.remove(selection); 3380 } else { 3381 _selectionGroup.add(selection); 3382 } 3383 } else if (event.isShiftDown()) { 3384 if (_selectionGroup.contains(selection)) { 3385 removed = _selectionGroup.remove(selection); 3386 } else { 3387 _selectionGroup.add(selection); 3388 } 3389 } 3390 } 3391 log.debug("modifySelectionGroup: size= {}, selection {}", 3392 _selectionGroup.size(), (removed ? "removed" : "added")); 3393 } 3394 3395 /** 3396 * Set attributes of a Positionable. 3397 * 3398 * @param newUtil helper from which to get attributes 3399 * @param p the item to set attributes of 3400 * 3401 */ 3402 public void setAttributes(PositionablePopupUtil newUtil, Positionable p) { 3403 p.setPopupUtility(newUtil.clone(p, p.getTextComponent())); 3404 int mar = newUtil.getMargin(); 3405 int bor = newUtil.getBorderSize(); 3406 Border outlineBorder; 3407 if (bor == 0) { 3408 outlineBorder = BorderFactory.createEmptyBorder(0, 0, 0, 0); 3409 } else { 3410 outlineBorder = new LineBorder(newUtil.getBorderColor(), bor); 3411 } 3412 Border borderMargin; 3413 if (newUtil.hasBackground()) { 3414 borderMargin = new LineBorder(p.getBackground(), mar); 3415 } else { 3416 borderMargin = BorderFactory.createEmptyBorder(mar, mar, mar, mar); 3417 } 3418 p.setBorder(new CompoundBorder(outlineBorder, borderMargin)); 3419 3420 if (p instanceof PositionableLabel) { 3421 PositionableLabel pos = (PositionableLabel) p; 3422 if (pos.isText()) { 3423 int deg = pos.getDegrees(); 3424 pos.rotate(0); 3425 if (deg == 0) { 3426 p.setOpaque(newUtil.hasBackground()); 3427 } else { 3428 pos.rotate(deg); 3429 } 3430 } 3431 } else if (p instanceof PositionableJPanel) { 3432 p.setOpaque(newUtil.hasBackground()); 3433 p.getTextComponent().setOpaque(newUtil.hasBackground()); 3434 } 3435 p.updateSize(); 3436 p.repaint(); 3437 if (p instanceof PositionableIcon) { 3438 NamedBean bean = p.getNamedBean(); 3439 if (bean != null) { 3440 ((PositionableIcon) p).displayState(bean.getState()); 3441 } 3442 } 3443 } 3444 3445 protected void setSelectionsAttributes(PositionablePopupUtil util, Positionable pos) { 3446 if (_selectionGroup != null && _selectionGroup.contains(pos)) { 3447 for (Positionable p : _selectionGroup) { 3448 if (p instanceof PositionableLabel) { 3449 setAttributes(util, p); 3450 } 3451 } 3452 } 3453 } 3454 3455 protected void setSelectionsHidden(boolean enabled, Positionable p) { 3456 if (_selectionGroup != null && _selectionGroup.contains(p)) { 3457 for (Positionable comp : _selectionGroup) { 3458 comp.setHidden(enabled); 3459 } 3460 } 3461 } 3462 3463 protected boolean setSelectionsPositionable(boolean enabled, Positionable p) { 3464 if (_selectionGroup != null && _selectionGroup.contains(p)) { 3465 for (Positionable comp : _selectionGroup) { 3466 comp.setPositionable(enabled); 3467 } 3468 return true; 3469 } else { 3470 return false; 3471 } 3472 } 3473 3474 protected void removeSelections(Positionable p) { 3475 if (_selectionGroup != null && _selectionGroup.contains(p)) { 3476 for (Positionable comp : _selectionGroup) { 3477 comp.remove(); 3478 } 3479 deselectSelectionGroup(); 3480 } 3481 } 3482 3483 protected void setSelectionsScale(double s, Positionable p) { 3484 if (_selectionGroup != null && _selectionGroup.contains(p)) { 3485 for (Positionable comp : _selectionGroup) { 3486 comp.setScale(s); 3487 } 3488 } else { 3489 p.setScale(s); 3490 } 3491 } 3492 3493 protected void setSelectionsRotation(int k, Positionable p) { 3494 if (_selectionGroup != null && _selectionGroup.contains(p)) { 3495 for (Positionable comp : _selectionGroup) { 3496 comp.rotate(k); 3497 } 3498 } else { 3499 p.rotate(k); 3500 } 3501 } 3502 3503 protected void setSelectionsDisplayLevel(int k, Positionable p) { 3504 if (_selectionGroup != null && _selectionGroup.contains(p)) { 3505 for (Positionable comp : _selectionGroup) { 3506 comp.setDisplayLevel(k); 3507 } 3508 } else { 3509 p.setDisplayLevel(k); 3510 } 3511 } 3512 3513 protected void setSelectionsDockingLocation(Positionable p) { 3514 if (_selectionGroup != null && _selectionGroup.contains(p)) { 3515 for (Positionable pos : _selectionGroup) { 3516 if (pos instanceof LocoIcon) { 3517 ((LocoIcon) pos).setDockingLocation(pos.getX(), pos.getY()); 3518 } 3519 } 3520 } else if (p instanceof LocoIcon) { 3521 ((LocoIcon) p).setDockingLocation(p.getX(), p.getY()); 3522 } 3523 } 3524 3525 protected void dockSelections(Positionable p) { 3526 if (_selectionGroup != null && _selectionGroup.contains(p)) { 3527 for (Positionable pos : _selectionGroup) { 3528 if (pos instanceof LocoIcon) { 3529 ((LocoIcon) pos).dock(); 3530 } 3531 } 3532 } else if (p instanceof LocoIcon) { 3533 ((LocoIcon) p).dock(); 3534 } 3535 } 3536 3537 protected boolean showAlignPopup(Positionable p) { 3538 return _selectionGroup != null && _selectionGroup.contains(p); 3539 } 3540 3541 public Rectangle getSelectRect() { 3542 return _selectRect; 3543 } 3544 3545 public void drawSelectRect(int x, int y) { 3546 int aX = getAnchorX(); 3547 int aY = getAnchorY(); 3548 int w = x - aX; 3549 int h = y - aY; 3550 if (x < aX) { 3551 aX = x; 3552 w = -w; 3553 } 3554 if (y < aY) { 3555 aY = y; 3556 h = -h; 3557 } 3558 _selectRect = new Rectangle((int) Math.round(aX / _paintScale), (int) Math.round(aY / _paintScale), 3559 (int) Math.round(w / _paintScale), (int) Math.round(h / _paintScale)); 3560 } 3561 3562 public final int getAnchorX() { 3563 return _anchorX; 3564 } 3565 3566 public final int getAnchorY() { 3567 return _anchorY; 3568 } 3569 3570 public final int getLastX() { 3571 return _lastX; 3572 } 3573 3574 public final int getLastY() { 3575 return _lastY; 3576 } 3577 3578 @Override 3579 public void keyTyped(KeyEvent e) { 3580 } 3581 3582 @Override 3583 public void keyPressed(KeyEvent e) { 3584 if (_selectionGroup == null) { 3585 return; 3586 } 3587 int x = 0; 3588 int y = 0; 3589 switch (e.getKeyCode()) { 3590 case KeyEvent.VK_UP: 3591 y = -1; 3592 break; 3593 case KeyEvent.VK_DOWN: 3594 y = 1; 3595 break; 3596 case KeyEvent.VK_LEFT: 3597 x = -1; 3598 break; 3599 case KeyEvent.VK_RIGHT: 3600 x = 1; 3601 break; 3602 default: 3603 log.debug("Unexpected e.getKeyCode() of {}", e.getKeyCode()); 3604 break; 3605 } 3606 //A cheat if the shift key isn't pressed then we move 5 pixels at a time. 3607 if (!e.isShiftDown()) { 3608 y *= 5; 3609 x *= 5; 3610 } 3611 for (Positionable comp : _selectionGroup) { 3612 moveItem(comp, x, y); 3613 } 3614 _targetPanel.repaint(); 3615 } 3616 3617 @Override 3618 public void keyReleased(KeyEvent e) { 3619 } 3620 3621 @Override 3622 public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { 3623 NamedBean nb = (NamedBean) evt.getOldValue(); 3624 if ("CanDelete".equals(evt.getPropertyName())) { // NOI18N 3625 StringBuilder message = new StringBuilder(); 3626 message.append(Bundle.getMessage("VetoInUseEditorHeader", getName())); // NOI18N 3627 message.append("<br>"); 3628 boolean found = false; 3629 int count = 0; 3630 for (Positionable p : _contents) { 3631 if (nb.equals(p.getNamedBean())) { 3632 found = true; 3633 count++; 3634 } 3635 } 3636 if (found) { 3637 message.append(Bundle.getMessage("VetoFoundInPanel", count)); 3638 message.append("<br>"); 3639 message.append(Bundle.getMessage("VetoReferencesWillBeRemoved")); // NOI18N 3640 message.append("<br>"); 3641 throw new PropertyVetoException(message.toString(), evt); 3642 } 3643 } else if ("DoDelete".equals(evt.getPropertyName())) { // NOI18N 3644 ArrayList<Positionable> toDelete = new ArrayList<>(); 3645 for (Positionable p : _contents) { 3646 if (nb.equals(p.getNamedBean())) { 3647 toDelete.add(p); 3648 } 3649 } 3650 for (Positionable p : toDelete) { 3651 removeFromContents(p); 3652 _targetPanel.repaint(); 3653 } 3654 } 3655 } 3656 3657 /* 3658 * ********************* Abstract Methods *********************** 3659 */ 3660 @Override 3661 public abstract void mousePressed(JmriMouseEvent event); 3662 3663 @Override 3664 public abstract void mouseReleased(JmriMouseEvent event); 3665 3666 @Override 3667 public abstract void mouseClicked(JmriMouseEvent event); 3668 3669 @Override 3670 public abstract void mouseDragged(JmriMouseEvent event); 3671 3672 @Override 3673 public abstract void mouseMoved(JmriMouseEvent event); 3674 3675 @Override 3676 public abstract void mouseEntered(JmriMouseEvent event); 3677 3678 @Override 3679 public abstract void mouseExited(JmriMouseEvent event); 3680 3681 /* 3682 * set up target panel, frame etc. 3683 */ 3684 protected abstract void init(String name); 3685 3686 /* 3687 * Closing of Target frame window. 3688 */ 3689 protected abstract void targetWindowClosingEvent(WindowEvent e); 3690 3691 /** 3692 * Called from TargetPanel's paint method for additional drawing by editor 3693 * view. 3694 * 3695 * @param g the context to paint within 3696 */ 3697 protected abstract void paintTargetPanel(Graphics g); 3698 3699 /** 3700 * Set an object's location when it is created. 3701 * 3702 * @param obj the object to locate 3703 */ 3704 public abstract void setNextLocation(Positionable obj); 3705 3706 /** 3707 * After construction, initialize all the widgets to their saved config 3708 * settings. 3709 */ 3710 protected abstract void initView(); 3711 3712 /** 3713 * Set up item(s) to be copied by paste. 3714 * 3715 * @param p the item to copy 3716 */ 3717 protected abstract void copyItem(Positionable p); 3718 3719 @CheckForNull 3720 public Rectangle2D resizePanelBounds(boolean forceFlag) { 3721 // Do nothing. This method is overridden by LayoutEditor. 3722 return null; 3723 } 3724 3725 public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) { 3726 List<NamedBeanUsageReport> report = new ArrayList<>(); 3727 if (bean != null) { 3728 getContents().forEach( pos -> { 3729 String data = getUsageData(pos); 3730 if (pos instanceof MultiSensorIcon) { 3731 MultiSensorIcon multi = (MultiSensorIcon) pos; 3732 multi.getSensors().forEach( sensor -> { 3733 if (bean.equals(sensor)) { 3734 report.add(new NamedBeanUsageReport("PositionalIcon", data)); 3735 } 3736 }); 3737 3738 } else if (pos instanceof SlipTurnoutIcon) { 3739 SlipTurnoutIcon slip3Scissor = (SlipTurnoutIcon) pos; 3740 if (bean.equals(slip3Scissor.getTurnout(SlipTurnoutIcon.EAST))) { 3741 report.add(new NamedBeanUsageReport("PositionalIcon", data)); 3742 } 3743 if (bean.equals(slip3Scissor.getTurnout(SlipTurnoutIcon.WEST))) { 3744 report.add(new NamedBeanUsageReport("PositionalIcon", data)); 3745 } 3746 if ( slip3Scissor.getNamedTurnout(SlipTurnoutIcon.LOWEREAST) != null 3747 && bean.equals(slip3Scissor.getTurnout(SlipTurnoutIcon.LOWEREAST))) { 3748 report.add(new NamedBeanUsageReport("PositionalIcon", data)); 3749 } 3750 if ( slip3Scissor.getNamedTurnout(SlipTurnoutIcon.LOWERWEST) != null 3751 && bean.equals(slip3Scissor.getTurnout(SlipTurnoutIcon.LOWERWEST))) { 3752 report.add(new NamedBeanUsageReport("PositionalIcon", data)); 3753 } 3754 3755 } else if (pos instanceof LightIcon) { 3756 LightIcon icon = (LightIcon) pos; 3757 if (bean.equals(icon.getLight())) { 3758 report.add(new NamedBeanUsageReport("PositionalIcon", data)); 3759 } 3760 3761 } else if (pos instanceof ReporterIcon) { 3762 ReporterIcon icon = (ReporterIcon) pos; 3763 if (bean.equals(icon.getReporter())) { 3764 report.add(new NamedBeanUsageReport("PositionalIcon", data)); 3765 } 3766 3767 } else if (pos instanceof AudioIcon) { 3768 AudioIcon icon = (AudioIcon) pos; 3769 if (bean.equals(icon.getAudio())) { 3770 report.add(new NamedBeanUsageReport("PositionalIcon", data)); 3771 } 3772 3773 } else { 3774 if ( bean.equals(pos.getNamedBean())) { 3775 report.add(new NamedBeanUsageReport("PositionalIcon", data)); 3776 } 3777 } 3778 }); 3779 } 3780 return report; 3781 } 3782 3783 String getUsageData(Positionable pos) { 3784 Point point = pos.getLocation(); 3785 return String.format("%s :: x=%d, y=%d", 3786 pos.getClass().getSimpleName(), 3787 Math.round(point.getX()), 3788 Math.round(point.getY())); 3789 } 3790 3791 // initialize logging 3792 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Editor.class); 3793 3794}