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