001package jmri.jmrit.display.panelEditor; 002 003import java.awt.Color; 004import java.awt.Component; 005import java.awt.Dimension; 006import java.awt.FlowLayout; 007import java.awt.Font; 008import java.awt.Graphics; 009import java.awt.Rectangle; 010import java.awt.event.ActionEvent; 011import java.awt.event.ActionListener; 012import java.awt.event.ItemEvent; 013import java.awt.event.ItemListener; 014import java.awt.event.KeyAdapter; 015import java.awt.event.KeyEvent; 016import java.awt.event.WindowAdapter; 017import java.lang.reflect.InvocationTargetException; 018import java.util.ArrayList; 019import java.util.Collections; 020import java.util.HashMap; 021import java.util.List; 022 023import javax.swing.AbstractAction; 024import javax.swing.BoxLayout; 025import javax.swing.JButton; 026import javax.swing.JCheckBox; 027import javax.swing.JCheckBoxMenuItem; 028import javax.swing.JComboBox; 029import javax.swing.JComponent; 030import javax.swing.JDialog; 031import javax.swing.JFrame; 032import javax.swing.JLabel; 033import javax.swing.JMenu; 034import javax.swing.JMenuBar; 035import javax.swing.JMenuItem; 036import javax.swing.JPanel; 037import javax.swing.JPopupMenu; 038import javax.swing.JTextField; 039 040import jmri.CatalogTreeManager; 041import jmri.ConfigureManager; 042import jmri.InstanceManager; 043import jmri.configurexml.ConfigXmlManager; 044import jmri.configurexml.XmlAdapter; 045import jmri.jmrit.catalog.ImageIndexEditor; 046import jmri.jmrit.display.Editor; 047import jmri.jmrit.display.EditorManager; 048import jmri.jmrit.display.Positionable; 049import jmri.jmrit.display.PositionablePopupUtil; 050import jmri.jmrit.display.ToolTip; 051import jmri.util.JmriJFrame; 052import jmri.util.gui.GuiLafPreferencesManager; 053import jmri.util.swing.JmriColorChooser; 054import jmri.util.swing.JmriJOptionPane; 055import jmri.util.swing.JmriMouseEvent; 056 057import org.jdom2.Element; 058 059/** 060 * Provides a simple editor for adding jmri.jmrit.display items to a captive 061 * JFrame. 062 * <p> 063 * GUI is structured as a band of common parameters across the top, then a 064 * series of things you can add. 065 * <p> 066 * All created objects are put specific levels depending on their type (higher 067 * levels are in front): 068 * <ul> 069 * <li>BKG background 070 * <li>ICONS icons and other drawing symbols 071 * <li>LABELS text labels 072 * <li>TURNOUTS turnouts and other variable track items 073 * <li>SENSORS sensors and other independently modified objects 074 * </ul> 075 * <p> 076 * The "contents" List keeps track of all the objects added to the target frame 077 * for later manipulation. 078 * <p> 079 * If you close the Editor window, the target is left alone and the editor 080 * window is just hidden, not disposed. If you close the target, the editor and 081 * target are removed, and dispose is run. To make this logic work, the 082 * PanelEditor is descended from a JFrame, not a JPanel. That way it can control 083 * its own visibility. 084 * <p> 085 * The title of the target and the editor panel are kept consistent via the 086 * {#setTitle} method. 087 * 088 * @author Bob Jacobsen Copyright (c) 2002, 2003, 2007 089 * @author Dennis Miller 2004 090 * @author Howard G. Penny Copyright (c) 2005 091 * @author Matthew Harris Copyright (c) 2009 092 * @author Pete Cressman Copyright (c) 2009, 2010 093 */ 094public class PanelEditor extends Editor implements ItemListener { 095 096 private static final String SENSOR = "Sensor"; 097 private static final String SIGNAL_HEAD = "SignalHead"; 098 private static final String SIGNAL_MAST = "SignalMast"; 099 private static final String MEMORY = "Memory"; 100 private static final String RIGHT_TURNOUT = "RightTurnout"; 101 private static final String LEFT_TURNOUT = "LeftTurnout"; 102 private static final String SLIP_TO_EDITOR = "SlipTOEditor"; 103 private static final String BLOCK_LABEL = "BlockLabel"; 104 private static final String REPORTER = "Reporter"; 105 private static final String LIGHT = "Light"; 106 private static final String BACKGROUND = "Background"; 107 private static final String MULTI_SENSOR = "MultiSensor"; 108 private static final String RPSREPORTER = "RPSreporter"; 109 private static final String FAST_CLOCK = "FastClock"; 110 private static final String GLOBAL_VARIABLE = "GlobalVariable"; 111 private static final String ICON = "Icon"; 112 private static final String AUDIO = "Audio"; 113 private static final String LOGIXNG = "LogixNG"; 114 private final JTextField nextX = new JTextField("0", 4); 115 private final JTextField nextY = new JTextField("0", 4); 116 117 private final JCheckBox editableBox = new JCheckBox(Bundle.getMessage("CheckBoxEditable")); 118 private final JCheckBox positionableBox = new JCheckBox(Bundle.getMessage("CheckBoxPositionable")); 119 private final JCheckBox controllingBox = new JCheckBox(Bundle.getMessage("CheckBoxControlling")); 120 //private JCheckBox showCoordinatesBox = new JCheckBox(Bundle.getMessage("CheckBoxShowCoordinates")); 121 private final JCheckBox showTooltipBox = new JCheckBox(Bundle.getMessage("CheckBoxShowTooltips")); 122 private final JCheckBox hiddenBox = new JCheckBox(Bundle.getMessage("CheckBoxHidden")); 123 private final JCheckBox menuBox = new JCheckBox(Bundle.getMessage("CheckBoxMenuBar")); 124 private final JLabel scrollableLabel = new JLabel(Bundle.getMessage("ComboBoxScrollable")); 125 private final JComboBox<String> scrollableComboBox = new JComboBox<>(); 126 127 private final JButton labelAdd = new JButton(Bundle.getMessage("ButtonAddText")); 128 private final JTextField nextLabel = new JTextField(10); 129 130 private JComboBox<ComboBoxItem> _addIconBox; 131 132 public PanelEditor() { 133 } 134 135 public PanelEditor(String name) { 136 super(name, false, true); 137 init(name); 138 } 139 140 @Override 141 protected void init(String name) { 142 java.awt.Container contentPane = this.getContentPane(); 143 contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 144 // common items 145 JPanel common = new JPanel(); 146 common.setLayout(new FlowLayout()); 147 common.add(new JLabel(" x:")); 148 common.add(nextX); 149 common.add(new JLabel(" y:")); 150 common.add(nextY); 151 contentPane.add(common); 152 setAllEditable(true); 153 setShowHidden(true); 154 super.setTargetPanel(null, makeFrame(name)); 155 super.setTargetPanelSize(400, 300); 156 super.setDefaultToolTip(new ToolTip(null, 0, 0, new Font("SansSerif", Font.PLAIN, 12), 157 Color.black, new Color(215, 225, 255), Color.black, null)); 158 // set scrollbar initial state 159 setScroll(SCROLL_BOTH); 160 161 // add menu - not using PanelMenu, because it now 162 // has other stuff in it? 163 JMenuBar menuBar = new JMenuBar(); 164 JMenu fileMenu = new JMenu(Bundle.getMessage("MenuFile")); 165 menuBar.add(fileMenu); 166 fileMenu.add(new jmri.jmrit.display.NewPanelAction(Bundle.getMessage("MenuItemNew"))); 167 fileMenu.add(new jmri.configurexml.StoreXmlUserAction(Bundle.getMessage("FileMenuItemStore"))); 168 JMenuItem storeIndexItem = new JMenuItem(Bundle.getMessage("MIStoreImageIndex")); 169 fileMenu.add(storeIndexItem); 170 storeIndexItem.addActionListener(event -> InstanceManager.getDefault(CatalogTreeManager.class).storeImageIndex()); 171 JMenuItem editItem = new JMenuItem(Bundle.getMessage("editIndexMenu")); 172 editItem.addActionListener(e -> { 173 ImageIndexEditor ii = InstanceManager.getDefault(ImageIndexEditor.class); 174 ii.pack(); 175 ii.setVisible(true); 176 }); 177 fileMenu.add(editItem); 178 179 editItem = new JMenuItem(Bundle.getMessage("CPEView")); 180 fileMenu.add(editItem); 181 editItem.addActionListener(event -> changeView("jmri.jmrit.display.controlPanelEditor.ControlPanelEditor")); 182 183 fileMenu.addSeparator(); 184 JMenuItem deleteItem = new JMenuItem(Bundle.getMessage("DeletePanel")); 185 fileMenu.add(deleteItem); 186 deleteItem.addActionListener(event -> { 187 if (deletePanel()) { 188 getTargetFrame().dispose(); 189 dispose(); 190 } 191 }); 192 193 setJMenuBar(menuBar); 194 addHelpMenu("package.jmri.jmrit.display.PanelEditor", true); 195 196 // allow renaming the panel 197 { 198 JPanel namep = new JPanel(); 199 namep.setLayout(new FlowLayout()); 200 JButton b = new JButton(Bundle.getMessage("renamePanelMenu", "...")); 201 b.addActionListener(new ActionListener() { 202 PanelEditor editor; 203 204 @Override 205 public void actionPerformed(ActionEvent e) { 206 Component ancestor = getTargetPanel().getTopLevelAncestor(); // could be null 207 String oldName = ""; 208 if (ancestor instanceof JFrame) { 209 oldName = ((JFrame) ancestor).getTitle(); 210 } 211 // prompt for name 212 String newName = JmriJOptionPane.showInputDialog(null, Bundle.getMessage("PromptNewName"), oldName); 213 if ((newName == null) || (oldName.equals(newName))) { 214 return; // cancelled 215 } 216 if (InstanceManager.getDefault(EditorManager.class).contains(newName)) { 217 JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("CanNotRename"), Bundle.getMessage("PanelExist"), 218 JmriJOptionPane.ERROR_MESSAGE); 219 return; 220 } 221 if (ancestor instanceof JFrame) { 222 ((JFrame) ancestor).setTitle(newName); 223 } 224 editor.setTitle(); 225 } 226 227 ActionListener init(PanelEditor e) { 228 editor = e; 229 return this; 230 } 231 }.init(this)); 232 namep.add(b); 233 this.getContentPane().add(namep); 234 } 235 // add a text label 236 { 237 JPanel panel = new JPanel(); 238 panel.setLayout(new FlowLayout()); 239 panel.add(labelAdd); 240 labelAdd.setEnabled(false); 241 labelAdd.setToolTipText(Bundle.getMessage("ToolTipWillActivate")); 242 panel.add(nextLabel); 243 labelAdd.addActionListener(new ActionListener() { 244 PanelEditor editor; 245 246 @Override 247 public void actionPerformed(ActionEvent a) { 248 editor.addLabel(nextLabel.getText()); 249 } 250 251 ActionListener init(PanelEditor e) { 252 editor = e; 253 return this; 254 } 255 }.init(this)); 256 nextLabel.addKeyListener(new KeyAdapter() { 257 @Override 258 public void keyReleased(KeyEvent a) { 259 if (nextLabel.getText().equals("")) { 260 labelAdd.setEnabled(false); 261 labelAdd.setToolTipText(Bundle.getMessage("ToolTipWillActivate")); 262 } else { 263 labelAdd.setEnabled(true); 264 labelAdd.setToolTipText(null); 265 } 266 } 267 }); 268 this.getContentPane().add(panel); 269 } 270 271 // Selection of the type of entity for the icon to represent is done from a combobox 272 _addIconBox = new JComboBox<>(); 273 _addIconBox.setMinimumSize(new Dimension(75, 75)); 274 _addIconBox.setMaximumSize(new Dimension(200, 200)); 275 _addIconBox.addItem(new ComboBoxItem(RIGHT_TURNOUT)); 276 _addIconBox.addItem(new ComboBoxItem(LEFT_TURNOUT)); 277 _addIconBox.addItem(new ComboBoxItem(SLIP_TO_EDITOR)); 278 _addIconBox.addItem(new ComboBoxItem(SENSOR)); // NOI18N 279 _addIconBox.addItem(new ComboBoxItem(SIGNAL_HEAD)); 280 _addIconBox.addItem(new ComboBoxItem(SIGNAL_MAST)); 281 _addIconBox.addItem(new ComboBoxItem(MEMORY)); 282 _addIconBox.addItem(new ComboBoxItem(BLOCK_LABEL)); 283 _addIconBox.addItem(new ComboBoxItem(REPORTER)); 284 _addIconBox.addItem(new ComboBoxItem(LIGHT)); 285 _addIconBox.addItem(new ComboBoxItem(BACKGROUND)); 286 _addIconBox.addItem(new ComboBoxItem(MULTI_SENSOR)); 287 _addIconBox.addItem(new ComboBoxItem(RPSREPORTER)); 288 _addIconBox.addItem(new ComboBoxItem(FAST_CLOCK)); 289 _addIconBox.addItem(new ComboBoxItem(GLOBAL_VARIABLE)); 290 _addIconBox.addItem(new ComboBoxItem(AUDIO)); 291 _addIconBox.addItem(new ComboBoxItem(LOGIXNG)); 292 _addIconBox.addItem(new ComboBoxItem(ICON)); 293 _addIconBox.setSelectedIndex(-1); 294 _addIconBox.addItemListener(this); // must be AFTER no selection is set 295 JPanel p1 = new JPanel(); 296 p1.setLayout(new BoxLayout(p1, BoxLayout.Y_AXIS)); 297 JPanel p2 = new JPanel(); 298 p2.setLayout(new FlowLayout()); 299 p2.add(new JLabel(Bundle.getMessage("selectTypeIcon"))); 300 p1.add(p2); 301 p1.add(_addIconBox); 302 contentPane.add(p1); 303 304 // edit, position, control controls 305 { 306 // edit mode item 307 contentPane.add(editableBox); 308 editableBox.addActionListener(event -> { 309 setAllEditable(editableBox.isSelected()); 310 hiddenCheckBoxListener(); 311 }); 312 editableBox.setSelected(isEditable()); 313 // positionable item 314 contentPane.add(positionableBox); 315 positionableBox.addActionListener(event -> setAllPositionable(positionableBox.isSelected())); 316 positionableBox.setSelected(allPositionable()); 317 // controlable item 318 contentPane.add(controllingBox); 319 controllingBox.addActionListener(event -> setAllControlling(controllingBox.isSelected())); 320 controllingBox.setSelected(allControlling()); 321 // hidden item 322 contentPane.add(hiddenBox); 323 hiddenCheckBoxListener(); 324 hiddenBox.setSelected(showHidden()); 325 326 /* 327 contentPane.add(showCoordinatesBox); 328 showCoordinatesBox.addActionListener(new ActionListener() { 329 public void actionPerformed(ActionEvent e) { 330 setShowCoordinates(showCoordinatesBox.isSelected()); 331 } 332 }); 333 showCoordinatesBox.setSelected(showCoordinates()); 334 */ 335 contentPane.add(showTooltipBox); 336 showTooltipBox.addActionListener(e -> setAllShowToolTip(showTooltipBox.isSelected())); 337 showTooltipBox.setSelected(showToolTip()); 338 339 contentPane.add(menuBox); 340 menuBox.addActionListener(e -> setPanelMenuVisible(menuBox.isSelected())); 341 menuBox.setSelected(true); 342 343 // Show/Hide Scroll Bars 344 JPanel scrollPanel = new JPanel(); 345 scrollPanel.setLayout(new FlowLayout()); 346 scrollableLabel.setLabelFor(scrollableComboBox); 347 scrollPanel.add(scrollableLabel); 348 scrollPanel.add(scrollableComboBox); 349 contentPane.add(scrollPanel); 350 scrollableComboBox.addItem(Bundle.getMessage("ScrollNone")); 351 scrollableComboBox.addItem(Bundle.getMessage("ScrollBoth")); 352 scrollableComboBox.addItem(Bundle.getMessage("ScrollHorizontal")); 353 scrollableComboBox.addItem(Bundle.getMessage("ScrollVertical")); 354 scrollableComboBox.setSelectedIndex(SCROLL_BOTH); 355 scrollableComboBox.addActionListener(e -> setScroll(scrollableComboBox.getSelectedIndex())); 356 } 357 358 // register the resulting panel for later configuration 359 ConfigureManager cm = InstanceManager.getNullableDefault(jmri.ConfigureManager.class); 360 if (cm != null) { 361 cm.registerUser(this); 362 } 363 364 // when this window closes, set contents of target uneditable 365 addWindowListener(new java.awt.event.WindowAdapter() { 366 367 HashMap<String, JFrameItem> iconAdderFrames; 368 369 @Override 370 public void windowClosing(java.awt.event.WindowEvent e) { 371 for (JFrameItem frame : iconAdderFrames.values()) { 372 frame.dispose(); 373 } 374 } 375 376 WindowAdapter init(HashMap<String, JFrameItem> f) { 377 iconAdderFrames = f; 378 return this; 379 } 380 }.init(_iconEditorFrame)); 381 382 // and don't destroy the window 383 setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); 384 // move this editor panel off the panel's position 385 getTargetFrame().setLocationRelativeTo(this); 386 getTargetFrame().pack(); 387 getTargetFrame().setVisible(true); 388 log.debug("PanelEditor ctor done."); 389 } // end ctor 390 391 /** 392 * Initializes the hiddencheckbox and its listener. This has been taken out 393 * of the init, as checkbox is enable/disabled by the editableBox. 394 */ 395 private void hiddenCheckBoxListener() { 396 setShowHidden(hiddenBox.isSelected()); 397 if (editableBox.isSelected()) { 398 hiddenBox.setEnabled(false); 399// hiddenBox.setSelected(true); 400 } else { 401 hiddenBox.setEnabled(true); 402 hiddenBox.addActionListener(event -> setShowHidden(hiddenBox.isSelected())); 403 } 404 405 } 406 407 /** 408 * After construction, initialize all the widgets to their saved config 409 * settings. 410 */ 411 @Override 412 public void initView() { 413 editableBox.setSelected(isEditable()); 414 positionableBox.setSelected(allPositionable()); 415 controllingBox.setSelected(allControlling()); 416 //showCoordinatesBox.setSelected(showCoordinates()); 417 showTooltipBox.setSelected(showToolTip()); 418 hiddenBox.setSelected(showHidden()); 419 menuBox.setSelected(getTargetFrame().getJMenuBar().isVisible()); 420 } 421 422 static class ComboBoxItem { 423 424 private final String name; 425 426 protected ComboBoxItem(String n) { 427 name = n; 428 } 429 430 protected String getName() { 431 return name; 432 } 433 434 @Override 435 public String toString() { 436 // I18N split Bundle name 437 // use NamedBeanBundle property for basic beans like "Turnout" I18N 438 String bundleName; 439 if (SENSOR.equals(name)) { 440 bundleName = "BeanNameSensor"; 441 } else if (SIGNAL_HEAD.equals(name)) { 442 bundleName = "BeanNameSignalHead"; 443 } else if (SIGNAL_MAST.equals(name)) { 444 bundleName = "BeanNameSignalMast"; 445 } else if (MEMORY.equals(name)) { 446 bundleName = "BeanNameMemory"; 447 } else if (REPORTER.equals(name)) { 448 bundleName = "BeanNameReporter"; 449 } else if (LIGHT.equals(name)) { 450 bundleName = "BeanNameLight"; 451 } else if (GLOBAL_VARIABLE.equals(name)) { 452 bundleName = "BeanNameGlobalVariable"; 453 } else if (AUDIO.equals(name)) { 454 bundleName = "BeanNameAudio"; 455 } else { 456 bundleName = name; 457 } 458 return Bundle.getMessage(bundleName); // use NamedBeanBundle property for basic beans like "Turnout" I18N 459 } 460 } 461 462 /* 463 * itemListener for JComboBox. 464 */ 465 @Override 466 public void itemStateChanged(ItemEvent e) { 467 if (e.getStateChange() == ItemEvent.SELECTED) { 468 ComboBoxItem item = (ComboBoxItem) e.getItem(); 469 String name = item.getName(); 470 JFrameItem frame = super.getIconFrame(name); 471 if (frame != null) { 472 frame.getEditor().reset(); 473 frame.setVisible(true); 474 } else { 475 if (name.equals(FAST_CLOCK)) { 476 addClock(); 477 } else if (name.equals(RPSREPORTER)) { 478 addRpsReporter(); 479 } else { 480 log.error("Unable to open Icon Editor \"{}\"", item.getName()); 481 } 482 } 483 _addIconBox.setSelectedIndex(-1); 484 } 485 } 486 487 /** 488 * Handle close of editor window. 489 * <p> 490 * Overload/override method in JmriJFrame parent, which by default is 491 * permanently closing the window. Here, we just want to make it invisible, 492 * so we don't dispose it (yet). 493 */ 494 @Override 495 public void windowClosing(java.awt.event.WindowEvent e) { 496 setVisible(false); 497 } 498 499 /** 500 * Create sequence of panels, etc, for layout: JFrame contains its 501 * ContentPane which contains a JPanel with BoxLayout (p1) which contains a 502 * JScollPane (js) which contains the targetPane. 503 * @param name the frame name. 504 * @return the frame. 505 */ 506 public JmriJFrame makeFrame(String name) { 507 JmriJFrame targetFrame = new JmriJFrame(name); 508 targetFrame.setVisible(false); 509 510 JMenuBar menuBar = new JMenuBar(); 511 JMenu editMenu = new JMenu(Bundle.getMessage("MenuEdit")); 512 menuBar.add(editMenu); 513 editMenu.add(new AbstractAction(Bundle.getMessage("OpenEditor")) { 514 @Override 515 public void actionPerformed(ActionEvent e) { 516 setVisible(true); 517 } 518 }); 519 editMenu.addSeparator(); 520 editMenu.add(new AbstractAction(Bundle.getMessage("DeletePanel")) { 521 @Override 522 public void actionPerformed(ActionEvent e) { 523 if (deletePanel()) { 524 dispose(); 525 } 526 } 527 }); 528 targetFrame.setJMenuBar(menuBar); 529 // add maker menu 530 JMenu markerMenu = new JMenu(Bundle.getMessage("MenuMarker")); 531 menuBar.add(markerMenu); 532 markerMenu.add(new AbstractAction(Bundle.getMessage("AddLoco")) { 533 @Override 534 public void actionPerformed(ActionEvent e) { 535 locoMarkerFromInput(); 536 } 537 }); 538 markerMenu.add(new AbstractAction(Bundle.getMessage("AddLocoRoster")) { 539 @Override 540 public void actionPerformed(ActionEvent e) { 541 locoMarkerFromRoster(); 542 } 543 }); 544 markerMenu.add(new AbstractAction(Bundle.getMessage("RemoveMarkers")) { 545 @Override 546 public void actionPerformed(ActionEvent e) { 547 removeMarkers(); 548 } 549 }); 550 551 JMenu warrantMenu = jmri.jmrit.logix.WarrantTableAction.getDefault().makeWarrantMenu(isEditable()); 552 if (warrantMenu != null) { 553 menuBar.add(warrantMenu); 554 } 555 556 targetFrame.addHelpMenu("package.jmri.jmrit.display.PanelTarget", true); 557 return targetFrame; 558 } 559 560 /* 561 ************* implementation of Abstract Editor methods ********** 562 */ 563 564 /** 565 * The target window has been requested to close, don't delete it at this 566 * time. Deletion must be accomplished via the Delete this panel menu item. 567 */ 568 @Override 569 protected void targetWindowClosingEvent(java.awt.event.WindowEvent e) { 570 targetWindowClosing(); 571 } 572 573 /** 574 * Called from TargetPanel's paint method for additional drawing by editor 575 * view 576 */ 577 @Override 578 protected void paintTargetPanel(Graphics g) { 579 /*Graphics2D g2 = (Graphics2D)g; 580 drawPositionableLabelBorder(g2);*/ 581 } 582 583 /** 584 * Set an object's location when it is created. 585 */ 586 @Override 587 protected void setNextLocation(Positionable obj) { 588 int x = Integer.parseInt(nextX.getText()); 589 int y = Integer.parseInt(nextY.getText()); 590 obj.setLocation(x, y); 591 } 592 593 /** 594 * Create popup for a Positionable object. Popup items common to all 595 * positionable objects are done before and after the items that pertain 596 * only to specific Positionable types. 597 * 598 * @param p the item containing or requiring the context menu 599 * @param event the event triggering the menu 600 * @param selections the list of all Positionables at this position 601 */ 602 protected void showPopUp(Positionable p, JmriMouseEvent event, List<Positionable> selections) { 603 if (!((JComponent) p).isVisible()) { 604 return; // component must be showing on the screen to determine its location 605 } 606 JPopupMenu popup = new JPopupMenu(); 607 PositionablePopupUtil util = p.getPopupUtility(); 608 if (p.isEditable()) { 609 // items for all Positionables 610 if (p.doViemMenu()) { 611 popup.add(p.getNameString()); 612 setPositionableMenu(p, popup); 613 if (p.isPositionable()) { 614 setShowCoordinatesMenu(p, popup); 615 setShowAlignmentMenu(p, popup); 616 } 617 setDisplayLevelMenu(p, popup); 618 setHiddenMenu(p, popup); 619 setEmptyHiddenMenu(p, popup); 620 setEditIdMenu(p, popup); 621 setEditClassesMenu(p, popup); 622 popup.addSeparator(); 623 setLogixNGPositionableMenu(p, popup); 624 popup.addSeparator(); 625 } 626 627 // Positionable items with defaults or using overrides 628 boolean popupSet = false; 629 popupSet = p.setRotateOrthogonalMenu(popup); 630 popupSet |= p.setRotateMenu(popup); 631 popupSet |= p.setScaleMenu(popup); 632 if (popupSet) { 633 popup.addSeparator(); 634 } 635 popupSet = p.setEditIconMenu(popup); 636 if (popupSet) { 637 popup.addSeparator(); 638 } 639 popupSet = p.setTextEditMenu(popup); 640 if (util != null) { 641 util.setFixedTextMenu(popup); 642 util.setTextMarginMenu(popup); 643 util.setTextBorderMenu(popup); 644 util.setTextFontMenu(popup); 645 util.setBackgroundMenu(popup); 646 util.setTextJustificationMenu(popup); 647 util.setTextOrientationMenu(popup); 648 util.copyItem(popup); 649 popup.addSeparator(); 650 util.propertyUtil(popup); 651 util.setAdditionalEditPopUpMenu(popup); 652 popupSet = true; 653 } 654 if (popupSet) { 655 popup.addSeparator(); 656 } 657 p.setDisableControlMenu(popup); 658 659 // for Positionables with unique item settings 660 p.showPopUp(popup); 661 662 setShowToolTipMenu(p, popup); 663 setRemoveMenu(p, popup); 664 } else { 665 p.showPopUp(popup); 666 if (util != null) { 667 util.setAdditionalViewPopUpMenu(popup); 668 } 669 } 670 671 if (selections.size() > 1) { 672 boolean found = false; 673 JMenu iconsBelowMenu = new JMenu(Bundle.getMessage("MenuItemIconsBelow")); 674 for (int i=0; i < selections.size(); i++) { 675 Positionable pos = selections.get(i); 676 if (found) { 677 iconsBelowMenu.add(new AbstractAction(Bundle.getMessage( 678 "PositionableTypeAndName", pos.getTypeString(), pos.getNameString())) { 679 @Override 680 public void actionPerformed(ActionEvent e) { 681 showPopUp(pos, event, new ArrayList<>()); 682 } 683 }); 684 } else { 685 if (p == pos) found = true; 686 } 687 } 688 popup.addSeparator(); 689 popup.add(iconsBelowMenu); 690 } 691 692 popup.show((Component) p, p.getWidth() / 2, p.getHeight() / 2); 693 } 694 695 /** 696 * *************************************************** 697 */ 698 private boolean delayedPopupTrigger; 699 700 @Override 701 public void mousePressed(JmriMouseEvent event) { 702 setToolTip(null); // ends tooltip if displayed 703 if (log.isDebugEnabled()) { 704 log.debug("mousePressed at ({},{}) _dragging= {}", event.getX(), event.getY(), _dragging); 705 } 706 _anchorX = event.getX(); 707 _anchorY = event.getY(); 708 _lastX = _anchorX; 709 _lastY = _anchorY; 710 List<Positionable> selections = getSelectedItems(event); 711 if (_dragging) { 712 return; 713 } 714 if (selections.size() > 0) { 715 if (event.isShiftDown() && selections.size() > 1) { 716 _currentSelection = selections.get(1); 717 } else { 718 _currentSelection = selections.get(0); 719 } 720 if (event.isPopupTrigger()) { 721 log.debug("mousePressed calls showPopUp"); 722 if (event.isMetaDown() || event.isAltDown()) { 723 // if requesting a popup and it might conflict with moving, delay the request to mouseReleased 724 delayedPopupTrigger = true; 725 } else { 726 // no possible conflict with moving, display the popup now 727 if (_selectionGroup != null) { 728 //Will show the copy option only 729 showMultiSelectPopUp(event, _currentSelection); 730 } else { 731 showPopUp(_currentSelection, event, selections); 732 } 733 } 734 } else if (!event.isControlDown()) { 735 _currentSelection.doMousePressed(event); 736 if (_multiItemCopyGroup != null && !_multiItemCopyGroup.contains(_currentSelection)) { 737 _multiItemCopyGroup = null; 738 } 739 // _selectionGroup = null; 740 } 741 } else { 742 if (event.isPopupTrigger()) { 743 if (event.isMetaDown() || event.isAltDown()) { 744 // if requesting a popup and it might conflict with moving, delay the request to mouseReleased 745 delayedPopupTrigger = true; 746 } else { 747 if (_multiItemCopyGroup != null) { 748 pasteItemPopUp(event); 749 } else if (_selectionGroup != null) { 750 showMultiSelectPopUp(event, _currentSelection); 751 } else { 752 backgroundPopUp(event); 753 _currentSelection = null; 754 } 755 } 756 } else { 757 _currentSelection = null; 758 } 759 } 760 // if ((event.isControlDown() || _selectionGroup!=null) && _currentSelection!=null){ 761 if ((event.isControlDown()) || event.isMetaDown() || event.isAltDown()) { 762 //Don't want to do anything, just want to catch it, so that the next two else ifs are not 763 //executed 764 } else if ((_currentSelection == null && _multiItemCopyGroup == null) 765 || (_selectRect != null && !_selectRect.contains(_anchorX, _anchorY))) { 766 _selectRect = new Rectangle(_anchorX, _anchorY, 0, 0); 767 _selectionGroup = null; 768 } else { 769 _selectRect = null; 770 _selectionGroup = null; 771 } 772 _targetPanel.repaint(); // needed for ToolTip 773 } 774 775 @Override 776 public void mouseReleased(JmriMouseEvent event) { 777 setToolTip(null); // ends tooltip if displayed 778 if (log.isDebugEnabled()) { 779 // in if statement to avoid inline conditional unless logging 780 log.debug("mouseReleased at ({},{}) dragging= {} selectRect is {}", event.getX(), event.getY(), _dragging, 781 _selectRect == null ? "null" : "not null"); 782 } 783 List<Positionable> selections = getSelectedItems(event); 784 785 if (_dragging) { 786 mouseDragged(event); 787 } 788 if (selections.size() > 0) { 789 if (event.isShiftDown() && selections.size() > 1) { 790 _currentSelection = selections.get(1); 791 } else { 792 _currentSelection = selections.get(0); 793 } 794 if (_multiItemCopyGroup != null && !_multiItemCopyGroup.contains(_currentSelection)) { 795 _multiItemCopyGroup = null; 796 } 797 } else { 798 if ((event.isPopupTrigger() || delayedPopupTrigger) && !_dragging) { 799 if (_multiItemCopyGroup != null) { 800 pasteItemPopUp(event); 801 } else { 802 backgroundPopUp(event); 803 _currentSelection = null; 804 } 805 } else { 806 _currentSelection = null; 807 808 } 809 } 810 /*if (event.isControlDown() && _currentSelection!=null && !event.isPopupTrigger()){ 811 amendSelectionGroup(_currentSelection, event);*/ 812 if ((event.isPopupTrigger() || delayedPopupTrigger) && _currentSelection != null && !_dragging) { 813 if (_selectionGroup != null) { 814 //Will show the copy option only 815 showMultiSelectPopUp(event, _currentSelection); 816 817 } else { 818 showPopUp(_currentSelection, event, selections); 819 } 820 } else { 821 if (_currentSelection != null && !_dragging && !event.isControlDown()) { 822 _currentSelection.doMouseReleased(event); 823 } 824 if (allPositionable() && _selectRect != null) { 825 if (_selectionGroup == null && _dragging) { 826 makeSelectionGroup(event); 827 } 828 } 829 } 830 delayedPopupTrigger = false; 831 _dragging = false; 832 _selectRect = null; 833 834 // if not sending MouseClicked, do it here 835 if (InstanceManager.getDefault(GuiLafPreferencesManager.class).isNonStandardMouseEvent()) { 836 mouseClicked(event); 837 } 838 _targetPanel.repaint(); // needed for ToolTip 839 } 840 841 @Override 842 public void mouseDragged(JmriMouseEvent event) { 843 setToolTip(null); // ends tooltip if displayed 844 if ((event.isPopupTrigger()) || (!event.isMetaDown() && !event.isAltDown())) { 845 if (_currentSelection != null) { 846 List<Positionable> selections = getSelectedItems(event); 847 if (selections.size() > 0) { 848 if (selections.get(0) != _currentSelection) { 849 _currentSelection.doMouseReleased(event); 850 } else { 851 _currentSelection.doMouseDragged(event); 852 } 853 } else { 854 _currentSelection.doMouseReleased(event); 855 } 856 } 857 return; 858 } 859 moveIt: 860 if (_currentSelection != null && getFlag(OPTION_POSITION, _currentSelection.isPositionable())) { 861 int deltaX = event.getX() - _lastX; 862 int deltaY = event.getY() - _lastY; 863 int minX = getItemX(_currentSelection, deltaX); 864 int minY = getItemY(_currentSelection, deltaY); 865 if (_selectionGroup != null && _selectionGroup.contains(_currentSelection)) { 866 for (Positionable comp : _selectionGroup) { 867 minX = Math.min(getItemX(comp, deltaX), minX); 868 minY = Math.min(getItemY(comp, deltaY), minY); 869 } 870 } 871 if (minX < 0 || minY < 0) { 872 break moveIt; 873 } 874 if (_selectionGroup != null && _selectionGroup.contains(_currentSelection)) { 875 for (Positionable comp : _selectionGroup) { 876 moveItem(comp, deltaX, deltaY); 877 } 878 _highlightcomponent = null; 879 } else { 880 moveItem(_currentSelection, deltaX, deltaY); 881 _highlightcomponent = new Rectangle(_currentSelection.getX(), _currentSelection.getY(), 882 _currentSelection.maxWidth(), _currentSelection.maxHeight()); 883 } 884 } else { 885 if (allPositionable() && _selectionGroup == null) { 886 drawSelectRect(event.getX(), event.getY()); 887 } 888 } 889 _dragging = true; 890 _lastX = event.getX(); 891 _lastY = event.getY(); 892 _targetPanel.repaint(); // needed for ToolTip 893 } 894 895 @Override 896 public void mouseMoved(JmriMouseEvent event) { 897 // log.debug("mouseMoved at ({},{})", event.getX(), event.getY()); 898 if (_dragging || event.isPopupTrigger()) { 899 return; 900 } 901 902 List<Positionable> selections = getSelectedItems(event); 903 Positionable selection = null; 904 if (selections.size() > 0) { 905 if (event.isShiftDown() && selections.size() > 1) { 906 selection = selections.get(1); 907 } else { 908 selection = selections.get(0); 909 } 910 } 911 if (isEditable() && selection != null && selection.getDisplayLevel() > BKG) { 912 _highlightcomponent = new Rectangle(selection.getX(), selection.getY(), selection.maxWidth(), selection.maxHeight()); 913 _targetPanel.repaint(); 914 } else { 915 _highlightcomponent = null; 916 _targetPanel.repaint(); 917 } 918 if (selection != null && selection.getDisplayLevel() > BKG && selection.showToolTip()) { 919 showToolTip(selection, event); 920 //selection.highlightlabel(true); 921 _targetPanel.repaint(); 922 } else { 923 setToolTip(null); 924 _highlightcomponent = null; 925 _targetPanel.repaint(); 926 } 927 } 928 929 @Override 930 public void mouseClicked(JmriMouseEvent event) { 931 setToolTip(null); // ends tooltip if displayed 932 if (log.isDebugEnabled()) { 933 log.debug("mouseClicked at ({},{}) dragging= {} selectRect is {}", 934 event.getX(), event.getY(), _dragging, (_selectRect == null ? "null" : "not null")); 935 } 936 List<Positionable> selections = getSelectedItems(event); 937 938 if (selections.size() > 0) { 939 if (event.isShiftDown() && selections.size() > 1) { 940 _currentSelection = selections.get(1); 941 } else { 942 _currentSelection = selections.get(0); 943 } 944 } else { 945 _currentSelection = null; 946 if (event.isPopupTrigger()) { 947 if (_multiItemCopyGroup == null) { 948 pasteItemPopUp(event); 949 } else { 950 backgroundPopUp(event); 951 } 952 } 953 } 954 if (event.isPopupTrigger() && _currentSelection != null && !_dragging) { 955 if (_selectionGroup != null) { 956 showMultiSelectPopUp(event, _currentSelection); 957 } else { 958 showPopUp(_currentSelection, event, selections); 959 } 960 // _selectionGroup = null; // Show popup only works for a single item 961 962 } else { 963 if (_currentSelection != null && !_dragging && !event.isControlDown()) { 964 _currentSelection.doMouseClicked(event); 965 } 966 } 967 _targetPanel.repaint(); // needed for ToolTip 968 if (event.isControlDown() && _currentSelection != null && !event.isPopupTrigger()) { 969 amendSelectionGroup(_currentSelection); 970 } 971 } 972 973 @Override 974 public void mouseEntered(JmriMouseEvent event) { 975 } 976 977 @Override 978 public void mouseExited(JmriMouseEvent event) { 979 setToolTip(null); 980 _targetPanel.repaint(); // needed for ToolTip 981 } 982 983 protected ArrayList<Positionable> _multiItemCopyGroup = null; // items gathered inside fence 984 985 @Override 986 protected void copyItem(Positionable p) { 987 _multiItemCopyGroup = new ArrayList<>(); 988 _multiItemCopyGroup.add(p); 989 } 990 991 protected void pasteItemPopUp(final JmriMouseEvent event) { 992 if (!isEditable()) { 993 return; 994 } 995 if (_multiItemCopyGroup == null) { 996 return; 997 } 998 JPopupMenu popup = new JPopupMenu(); 999 JMenuItem edit = new JMenuItem(Bundle.getMessage("MenuItemPaste")); 1000 edit.addActionListener(e -> pasteItem(event)); 1001 setBackgroundMenu(popup); 1002 showAddItemPopUp(event, popup); 1003 popup.add(edit); 1004 popup.show(event.getComponent(), event.getX(), event.getY()); 1005 } 1006 1007 protected void backgroundPopUp(JmriMouseEvent event) { 1008 if (!isEditable()) { 1009 return; 1010 } 1011 JPopupMenu popup = new JPopupMenu(); 1012 setBackgroundMenu(popup); 1013 showAddItemPopUp(event, popup); 1014 popup.show(event.getComponent(), event.getX(), event.getY()); 1015 } 1016 1017 protected void showMultiSelectPopUp(final JmriMouseEvent event, Positionable p) { 1018 JPopupMenu popup = new JPopupMenu(); 1019 JMenuItem copy = new JMenuItem(Bundle.getMessage("MenuItemCopy")); // changed "edit" to "copy" 1020 if (p.isPositionable()) { 1021 setShowAlignmentMenu(p, popup); 1022 } 1023 copy.addActionListener(e -> { 1024 _multiItemCopyGroup = new ArrayList<>(); 1025 // must make a copy or pasteItem() will hang 1026 if (_selectionGroup != null) { 1027 _multiItemCopyGroup.addAll(_selectionGroup); 1028 } 1029 }); 1030 1031 setMultiItemsPositionableMenu(popup); // adding Lock Position for all 1032 // selected items 1033 1034 setRemoveMenu(p, popup); 1035 //showAddItemPopUp(event, popup); // no need to Add when group selected 1036 popup.add(copy); 1037 popup.show(event.getComponent(), event.getX(), event.getY()); 1038 } 1039 1040 protected void showAddItemPopUp(final JmriMouseEvent event, JPopupMenu popup) { 1041 if (!isEditable()) { 1042 return; 1043 } 1044 JMenu _add = new JMenu(Bundle.getMessage("MenuItemAddItem")); 1045 // for items in the following list, I18N is picked up later on 1046 addItemPopUp(new ComboBoxItem(RIGHT_TURNOUT), _add); 1047 addItemPopUp(new ComboBoxItem(LEFT_TURNOUT), _add); 1048 addItemPopUp(new ComboBoxItem(SLIP_TO_EDITOR), _add); 1049 addItemPopUp(new ComboBoxItem(SENSOR), _add); 1050 addItemPopUp(new ComboBoxItem(SIGNAL_HEAD), _add); 1051 addItemPopUp(new ComboBoxItem(SIGNAL_MAST), _add); 1052 addItemPopUp(new ComboBoxItem(MEMORY), _add); 1053 addItemPopUp(new ComboBoxItem(BLOCK_LABEL), _add); 1054 addItemPopUp(new ComboBoxItem(REPORTER), _add); 1055 addItemPopUp(new ComboBoxItem(LIGHT), _add); 1056 addItemPopUp(new ComboBoxItem(BACKGROUND), _add); 1057 addItemPopUp(new ComboBoxItem(MULTI_SENSOR), _add); 1058 addItemPopUp(new ComboBoxItem(RPSREPORTER), _add); 1059 addItemPopUp(new ComboBoxItem(FAST_CLOCK), _add); 1060 addItemPopUp(new ComboBoxItem(GLOBAL_VARIABLE), _add); 1061 addItemPopUp(new ComboBoxItem(AUDIO), _add); 1062 addItemPopUp(new ComboBoxItem(LOGIXNG), _add); 1063 addItemPopUp(new ComboBoxItem(ICON), _add); 1064 addItemPopUp(new ComboBoxItem("Text"), _add); 1065 popup.add(_add); 1066 } 1067 1068 protected void addItemPopUp(final ComboBoxItem item, JMenu menu) { 1069 1070 ActionListener a = new ActionListener() { 1071 //final String desiredName = name; 1072 @Override 1073 public void actionPerformed(ActionEvent e) { 1074 addItemViaMouseClick = true; 1075 getIconFrame(item.getName()); 1076 } 1077 1078 ActionListener init(ComboBoxItem i) { 1079 return this; 1080 } 1081 }.init(item); 1082 JMenuItem addto = new JMenuItem(item.toString()); 1083 addto.addActionListener(a); 1084 menu.add(addto); 1085 } 1086 1087 protected boolean addItemViaMouseClick = false; 1088 1089 @Override 1090 public void putItem(Positionable l) throws Positionable.DuplicateIdException { 1091 super.putItem(l); 1092 /*This allows us to catch any new items that are being pasted into the panel 1093 and add them to the selection group, so that the user can instantly move them around*/ 1094 //!!! 1095 if (pasteItemFlag) { 1096 amendSelectionGroup(l); 1097 return; 1098 } 1099 if (addItemViaMouseClick) { 1100 addItemViaMouseClick = false; 1101 l.setLocation(_lastX, _lastY); 1102 } 1103 } 1104 1105 private void amendSelectionGroup(Positionable p) { 1106 if (p == null) { 1107 return; 1108 } 1109 if (_selectionGroup == null) { 1110 _selectionGroup = new ArrayList<>(); 1111 } 1112 boolean removed = false; 1113 for (int i = 0; i < _selectionGroup.size(); i++) { 1114 if (_selectionGroup.get(i) == p) { 1115 _selectionGroup.remove(i); 1116 removed = true; 1117 break; 1118 } 1119 } 1120 if (!removed) { 1121 _selectionGroup.add(p); 1122 } else if (_selectionGroup.isEmpty()) { 1123 _selectionGroup = null; 1124 } 1125 _targetPanel.repaint(); 1126 } 1127 1128 protected boolean pasteItemFlag = false; 1129 1130 protected void pasteItem(JmriMouseEvent e) { 1131 pasteItemFlag = true; 1132 XmlAdapter adapter; 1133 String className; 1134 int x; 1135 int y; 1136 int xOrig; 1137 int yOrig; 1138 if (_multiItemCopyGroup != null) { 1139 JComponent copied; 1140 int xoffset; 1141 int yoffset; 1142 x = _multiItemCopyGroup.get(0).getX(); 1143 y = _multiItemCopyGroup.get(0).getY(); 1144 xoffset = e.getX() - x; 1145 yoffset = e.getY() - y; 1146 /*We make a copy of the selected items and work off of that copy 1147 as amendments are made to the multiItemCopyGroup during this process 1148 which can result in a loop*/ 1149 ArrayList<Positionable> _copyOfMultiItemCopyGroup = new ArrayList<>(_multiItemCopyGroup); 1150 Collections.copy(_copyOfMultiItemCopyGroup, _multiItemCopyGroup); 1151 for (Positionable comp : _copyOfMultiItemCopyGroup) { 1152 copied = (JComponent) comp; 1153 xOrig = copied.getX(); 1154 yOrig = copied.getY(); 1155 x = xOrig + xoffset; 1156 y = yOrig + yoffset; 1157 if (x < 0) { 1158 x = 1; 1159 } 1160 if (y < 0) { 1161 y = 1; 1162 } 1163 className = ConfigXmlManager.adapterName(copied); 1164 copied.setLocation(x, y); 1165 try { 1166 adapter = (XmlAdapter) Class.forName(className).getDeclaredConstructor().newInstance(); 1167 Element el = adapter.store(copied); 1168 adapter.load(el, this); 1169 } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException 1170 | jmri.configurexml.JmriConfigureXmlException 1171 | RuntimeException ex) { 1172 log.debug("Could not paste.", ex); 1173 } 1174 /*We remove the original item from the list, so we end up with 1175 just the new items selected and allow the items to be moved around */ 1176 amendSelectionGroup(comp); 1177 copied.setLocation(xOrig, yOrig); 1178 } 1179 _selectionGroup = null; 1180 } 1181 pasteItemFlag = false; 1182 _targetPanel.repaint(); 1183 } 1184 1185 /** 1186 * Add an action to remove the Positionable item. 1187 */ 1188 @Override 1189 public void setRemoveMenu(Positionable p, JPopupMenu popup) { 1190 popup.add(new AbstractAction(Bundle.getMessage("Remove")) { 1191 Positionable comp; 1192 1193 @Override 1194 public void actionPerformed(ActionEvent e) { 1195 if (_selectionGroup == null) { 1196 comp.remove(); 1197 } else { 1198 removeMultiItems(); 1199 } 1200 } 1201 1202 AbstractAction init(Positionable pos) { 1203 comp = pos; 1204 return this; 1205 } 1206 }.init(p)); 1207 } 1208 1209 private void removeMultiItems() { 1210 boolean itemsInCopy = false; 1211 if (_selectionGroup == _multiItemCopyGroup) { 1212 itemsInCopy = true; 1213 } 1214 for (Positionable comp : _selectionGroup) { 1215 comp.remove(); 1216 } 1217 //As we have removed all the items from the panel we can remove the group. 1218 _selectionGroup = null; 1219 //If the items in the selection group and copy group are the same we need to 1220 //clear the copy group as the originals no longer exist. 1221 if (itemsInCopy) { 1222 _multiItemCopyGroup = null; 1223 } 1224 } 1225 1226 // This adds a single CheckBox in the PopupMenu to set or clear all the selected 1227 // items "Lock Position" or Positionable setting, when clicked, all the items in 1228 // the selection will be changed accordingly. 1229 private void setMultiItemsPositionableMenu(JPopupMenu popup) { 1230 // This would do great with a "greyed" CheckBox if the multiple items have different states. 1231 // Then selecting the true or false state would force all to change to true or false 1232 1233 JCheckBoxMenuItem lockItem = new JCheckBoxMenuItem(Bundle.getMessage("LockPosition")); 1234 boolean allSetToMove = false; // used to decide the state of the checkbox shown 1235 int trues = 0; // used to see if all items have the same setting 1236 1237 int size = _selectionGroup.size(); 1238 1239 for (Positionable comp : _selectionGroup) { 1240 if (!comp.isPositionable()) { 1241 allSetToMove = true; 1242 trues++; 1243 } 1244 1245 lockItem.setSelected(allSetToMove); 1246 1247 lockItem.addActionListener(new ActionListener() { 1248 Positionable comp; 1249 JCheckBoxMenuItem checkBox; 1250 1251 @Override 1252 public void actionPerformed(ActionEvent e) { 1253 comp.setPositionable(!checkBox.isSelected()); 1254 setSelectionsPositionable(!checkBox.isSelected(), comp); 1255 } 1256 1257 ActionListener init(Positionable pos, JCheckBoxMenuItem cb) { 1258 comp = pos; 1259 checkBox = cb; 1260 return this; 1261 } 1262 }.init(comp, lockItem)); 1263 } 1264 1265 // Add "~" to the Text when all items do not have the same setting, 1266 // until we get a "greyed" CheckBox ;) - GJM 1267 if ((trues != size) && (trues != 0)) { 1268 lockItem.setText("~ " + lockItem.getText()); 1269 // uncheck box if all not the same 1270 lockItem.setSelected(false); 1271 } 1272 popup.add(lockItem); 1273 } 1274 1275 public void setBackgroundMenu(JPopupMenu popup) { 1276 // Panel background, not text background 1277 JMenuItem edit = new JMenuItem(Bundle.getMessage("FontBackgroundColor")); 1278 edit.addActionListener((ActionEvent event) -> { 1279 Color desiredColor = JmriColorChooser.showDialog(this, 1280 Bundle.getMessage("FontBackgroundColor"), 1281 getBackgroundColor()); 1282 if (desiredColor!=null ) { 1283 setBackgroundColor(desiredColor); 1284 } 1285 }); 1286 popup.add(edit); 1287 } 1288 1289 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PanelEditor.class); 1290 1291}