001package jmri.jmrit.display; 002 003import java.awt.*; 004import java.awt.datatransfer.DataFlavor; 005import java.awt.datatransfer.Transferable; 006import java.awt.datatransfer.UnsupportedFlavorException; 007import java.awt.dnd.DnDConstants; 008import java.awt.dnd.DropTarget; 009import java.awt.dnd.DropTargetDragEvent; 010import java.awt.dnd.DropTargetDropEvent; 011import java.awt.dnd.DropTargetEvent; 012import java.awt.dnd.DropTargetListener; 013import java.awt.event.ActionEvent; 014import java.awt.event.ActionListener; 015import java.awt.event.KeyAdapter; 016import java.awt.event.KeyEvent; 017import java.io.IOException; 018import java.util.ArrayList; 019import java.util.Enumeration; 020import java.util.HashMap; 021import java.util.Hashtable; 022import java.util.Iterator; 023import java.util.Map; 024import javax.swing.*; 025import javax.swing.event.ListSelectionEvent; 026import javax.swing.event.ListSelectionListener; 027import javax.swing.table.TableColumn; 028import javax.swing.table.TableColumnModel; 029import javax.swing.tree.TreeNode; 030 031import jmri.CatalogTree; 032import jmri.CatalogTreeManager; 033import jmri.InstanceManager; 034import jmri.NamedBean; 035import jmri.SignalHead; 036import jmri.jmrit.catalog.CatalogPanel; 037import jmri.CatalogTreeLeaf; 038import jmri.CatalogTreeNode; 039import jmri.jmrit.catalog.ImageIndexEditor; 040import jmri.jmrit.catalog.NamedIcon; 041import jmri.jmrit.picker.PickListModel; 042import jmri.util.swing.JmriJOptionPane; 043 044/** 045 * Provides a simple editor for selecting N NamedIcons. Class for Icon Editors 046 * implements "Drag n Drop". Allows drops from icons dragged from a Catalog 047 * preview pane. 048 * <p> 049 * See {@link SensorIcon} for an item that might want to have that type of 050 * information, and {@link jmri.jmrit.display.panelEditor.PanelEditor} for an 051 * example of how to use this. 052 * 053 * @author Pete Cressman Copyright (c) 2009, 2010 054 */ 055public class IconAdder extends JPanel implements ListSelectionListener { 056 057 private int ROW_HEIGHT; 058 059 HashMap<String, JToggleButton> _iconMap; 060 ArrayList<String> _iconOrderList; 061 private JScrollPane _pickTablePane; 062 063 private PickListModel<NamedBean> _pickListModel; 064 065 CatalogTreeNode _defaultIcons; // current set of icons user has selected 066 JPanel _iconPanel; 067 private JPanel _buttonPanel; 068 private String _type; 069 private boolean _userDefaults; 070 protected JTextField _sysNameText; // is set in IconAdderTest 071 JTable _table; 072 JButton _addButton; 073 private JButton _addTableButton; 074 private JButton _changeButton; 075 private JButton _closeButton; 076 private CatalogPanel _catalog; 077 private JFrame _parent; 078 private boolean _allowDeletes; 079 boolean _update; // updating existing icon from popup 080 081 public IconAdder() { 082 _userDefaults = false; 083 _iconMap = new HashMap<>(10); 084 _iconOrderList = new ArrayList<>(); 085 IconAdder.this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 086 } 087 088 public IconAdder(boolean allowDeletes) { 089 this(); 090 _allowDeletes = allowDeletes; 091 } 092 093 public IconAdder(String type) { 094 this(); 095 _type = type; 096 IconAdder.this.initDefaultIcons(); 097 } 098 099 public void reset() { 100 if (_table != null) { 101 _table.clearSelection(); 102 } 103 closeCatalog(); 104 if (_defaultIcons != null) { 105 makeIconPanel(true); 106 log.debug("IconPanel ready"); 107 } 108 this.revalidate(); 109 } 110 111 public void initDefaultIcons() { 112 CatalogTreeManager manager = InstanceManager.getDefault(jmri.CatalogTreeManager.class); 113 // unfiltered, xml-stored, default icon tree 114 CatalogTree tree = manager.getBySystemName("NXDI"); 115 if (tree != null) { 116 CatalogTreeNode node = tree.getRoot(); 117 118 Enumeration<TreeNode> e = node.children(); 119 120 while (e.hasMoreElements()) { 121 CatalogTreeNode nChild = (CatalogTreeNode) e.nextElement(); 122 if (_type.equals(nChild.toString())) { 123 _defaultIcons = nChild; // consists of set of a NOI18N appearance name elements, 124 // each containing an icon URL path 125 _userDefaults = true; 126 break; 127 } 128 } 129 } 130 log.debug("initDefaultIcons: type= {}, defaultIcons= {}", _type, _defaultIcons); 131 } 132 133 /** 134 * Replace the existing _defaultIcons TreeSet with a new set, 135 * created from the current _iconMap set of icons. Note these might have I18N labels as their keys. 136 * <p> 137 * The new _defaultIcons might be a null Node. 138 */ 139 private void createDefaultIconNodeFromMap() { 140 log.debug("createDefaultIconNodeFromMap for node= {}, _iconOrderList.size()= {}", _type, _iconOrderList.size()); 141 _defaultIcons = new CatalogTreeNode(_type); 142 for (Map.Entry<String, JToggleButton> entry : _iconMap.entrySet()) { 143 NamedIcon icon = (NamedIcon) entry.getValue().getIcon(); 144 _defaultIcons.addLeaf(new CatalogTreeLeaf(entry.getKey(), icon.getURL(), _iconOrderList.indexOf(entry.getKey()))); 145 } 146 } 147 148 public CatalogTreeNode getDefaultIconNode() { 149 log.debug("getDefaultIconNode for node= {}", _type); 150 CatalogTreeNode defaultIcons = new CatalogTreeNode(_type); 151 ArrayList<CatalogTreeLeaf> leafList = _defaultIcons.getLeaves(); 152 for (int i = 0; i < leafList.size(); i++) { 153 CatalogTreeLeaf leaf = leafList.get(i); 154 defaultIcons.addLeaf(new CatalogTreeLeaf(leaf.getName(), leaf.getPath(), i)); 155 } 156 return defaultIcons; 157 } 158 159 /** 160 * Build iconMap and orderArray from user's choice of defaults. 161 * 162 * @param n the root in a catalog from which icons are made 163 */ 164 protected void makeIcons(CatalogTreeNode n) { 165 if (log.isDebugEnabled()) { 166 log.debug("makeIcons from node= {}, numChildren= {}, NumLeaves= {}", 167 n.toString(), n.getChildCount(), n.getNumLeaves()); 168 } 169 _iconMap = new HashMap<>(10); 170 _iconOrderList = new ArrayList<>(); 171 ArrayList<CatalogTreeLeaf> leafList = n.getLeaves(); 172 // adjust order of icons 173 int k = leafList.size() - 1; 174 for (int i = leafList.size() - 1; i >= 0; i--) { 175 CatalogTreeLeaf leaf = leafList.get(i); 176 String name = leaf.getName(); 177 String path = leaf.getPath(); 178 switch (name) { 179 case "BeanStateInconsistent": 180 this.setIcon(0, name, new NamedIcon(path, path)); 181 break; 182 case "BeanStateUnknown": 183 this.setIcon(1, name, new NamedIcon(path, path)); 184 break; 185 default: 186 this.setIcon(k, name, new NamedIcon(path, path)); 187 k--; 188 break; 189 } 190 } 191 } 192 193 /** 194 * @param order the index to icon's name and the inverse order that icons 195 * are drawn in doIconPanel() 196 * @param label the icon name displayed in the icon panel and the key 197 * to the icon button in _iconMap, supplied as I18N string 198 * @param icon the icon displayed in the icon button 199 */ 200 protected void setIcon(int order, String label, NamedIcon icon) { 201 // make a button to change that icon 202 log.debug("setIcon at order= {}, key= {}", order, label); 203 JToggleButton button = new IconButton(label, icon); 204 if (icon == null || icon.getIconWidth() < 1 || icon.getIconHeight() < 1) { 205 button.setText(Bundle.getMessage("invisibleIcon")); 206 button.setForeground(Color.lightGray); 207 } else { 208 icon.reduceTo(CatalogPanel.ICON_WIDTH, CatalogPanel.ICON_HEIGHT, CatalogPanel.ICON_SCALE); 209 button.setToolTipText(icon.getName()); 210 } 211 212 if (_allowDeletes) { 213 String fileName = "resources/icons/misc/X-red.gif"; 214 button.setSelectedIcon(new jmri.jmrit.catalog.NamedIcon(fileName, fileName)); 215 } 216 if (icon != null) { 217 icon.reduceTo(CatalogPanel.ICON_WIDTH, CatalogPanel.ICON_HEIGHT, CatalogPanel.ICON_SCALE); 218 } 219 220 _iconMap.put(label, button); 221 // calls may not be in ascending order, so pad array 222 if (order > _iconOrderList.size()) { 223 for (int i = _iconOrderList.size(); i < order; i++) { 224 _iconOrderList.add(i, "placeHolder"); 225 } 226 } else { 227 if (order < _iconOrderList.size()) { 228 _iconOrderList.remove(order); 229 } 230 } 231 _iconOrderList.add(order, label); 232 } 233 234 /** 235 * Install the icons used to represent all the states of the entity being 236 * edited. 237 * 238 * @param order (reverse) order of display, (0 last, to N first) 239 * @param label the state name to display. Must be unique from all other 240 * calls to this method 241 * @param name the resource name of the icon image to display 242 */ 243 public void setIcon(int order, String label, String name) { 244 log.debug("setIcon: order= {}, label= {}, name= {}", order, label, name); 245 this.setIcon(order, label, new NamedIcon(name, name)); 246 } 247 248 public void setParent(JFrame parent) { 249 _parent = parent; 250 } 251 252 void pack() { 253 _parent.pack(); 254 } 255 256 public int getNumIcons() { 257 return _iconMap.size(); 258 } 259 260 static int STRUT_SIZE = 3; 261 262 /** 263 * After all the calls to setIcon(...) are made, make the icon display. Two 264 * columns to save space for subsequent panels. 265 * 266 * @param useDefaults true to use user-specified defaults; false otherwise 267 */ 268 public void makeIconPanel(boolean useDefaults) { 269 if (useDefaults && _userDefaults) { 270 makeIcons(_defaultIcons); 271 } 272 log.debug("makeIconPanel updating"); 273 clearIconPanel(); 274 doIconPanel(); 275 } 276 277 private void clearIconPanel() { 278 if (_iconPanel != null) { 279 this.remove(_iconPanel); 280 } 281 _iconPanel = new JPanel(); 282 _iconPanel.setLayout(new GridLayout(0,2)); 283 } 284 285 protected void doIconPanel() { 286 JPanel panel; 287 for (int i = _iconOrderList.size() - 1; i >= 0; i--) { 288 log.debug("adding icon #{}", i); 289 panel = new JPanel(); 290 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); 291 panel.add(Box.createHorizontalStrut(STRUT_SIZE)); 292 String key = _iconOrderList.get(i); // NOI18N 293 // TODO BUG edit icon context usage in signal head; turnout etc work OK 294 JPanel p = new JPanel(); 295 p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); 296 String labelName = key; 297 try { 298 labelName = Bundle.getMessage(key); // I18N 299 } catch (java.util.MissingResourceException mre) { 300 log.warn("doIconPanel() property key {} missing", key); 301 } 302 JLabel name = new JLabel(labelName); 303 name.setAlignmentX(Component.CENTER_ALIGNMENT); 304 p.add(name); 305 JToggleButton button = _iconMap.get(key); 306 button.setAlignmentX(Component.CENTER_ALIGNMENT); 307 p.add(button); 308 panel.add(p); 309 // TODO align button centered in GridLayout 310 _iconPanel.add(panel); 311 } 312 this.add(_iconPanel, 0); 313 } 314 315 /** 316 * After the calls to makeIconPanel(), optionally make a pick list table for 317 * managed elements. (Not all Icon Editors use pick lists). 318 * 319 * @param tableModel the model from which the table is created 320 */ 321 @SuppressWarnings("unchecked") // cast PickListModel<? extends NamedBean> to PickListModel<NamedBean> 322 public void setPickList(PickListModel<? extends NamedBean> tableModel) { 323 _pickListModel = (PickListModel<NamedBean>) tableModel; 324 _table = new JTable(tableModel); 325 _pickListModel.makeSorter(_table); 326 327 _table.setRowSelectionAllowed(true); 328 _table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 329 ROW_HEIGHT = _table.getRowHeight(); 330 _table.setPreferredScrollableViewportSize(new java.awt.Dimension(200, 7 * ROW_HEIGHT)); 331 _table.setDragEnabled(true); 332 TableColumnModel columnModel = _table.getColumnModel(); 333 334 TableColumn sNameColumnT = columnModel.getColumn(PickListModel.SNAME_COLUMN); 335 sNameColumnT.setResizable(true); 336 sNameColumnT.setMinWidth(50); 337 sNameColumnT.setMaxWidth(200); 338 339 TableColumn uNameColumnT = columnModel.getColumn(PickListModel.UNAME_COLUMN); 340 uNameColumnT.setResizable(true); 341 uNameColumnT.setMinWidth(100); 342 uNameColumnT.setMaxWidth(300); 343 344 _pickTablePane = new JScrollPane(_table); 345 this.add(_pickTablePane); 346 this.add(Box.createVerticalStrut(STRUT_SIZE)); 347 pack(); 348 } 349 350 public void setSelection(NamedBean bean) { 351 int row = _pickListModel.getIndexOf(bean); 352 row = _table.convertRowIndexToView(row); 353 _table.addRowSelectionInterval(row, row); 354 _pickTablePane.getVerticalScrollBar().setValue(row * ROW_HEIGHT); 355 } 356 357 /** 358 * When a Pick list is installed, table selection controls the Add button. 359 */ 360 @Override 361 public void valueChanged(ListSelectionEvent e) { 362 if (_table == null) { 363 return; 364 } 365 int row = _table.getSelectedRow(); 366 log.debug("Table valueChanged: row= {}", row); 367 if (row >= 0) { 368 _addButton.setEnabled(true); 369 _addButton.setToolTipText(null); 370 if (_type != null && _type.equals("SignalHead")) { 371 // update Add Icon panel to match icons displayed to the selected signal head appearances 372 makeIconMap(_pickListModel.getBeanAt(row)); // NOI18N 373 clearIconPanel(); 374 doIconPanel(); 375 } 376 } else { 377 _addButton.setEnabled(false); 378 _addButton.setToolTipText(Bundle.getMessage("ToolTipPickFromTable")); 379 } 380 validate(); 381 } 382 383 /** 384 * Update/Recreate the iconMap for this bean, only called for SignalHeads. 385 * 386 * @param bean the object to create the map for 387 */ 388 private void makeIconMap(NamedBean bean) { 389 if (bean != null && _type != null && _type.equals("SignalHead")) { 390 _iconMap = new HashMap<>(12); 391 _iconOrderList = new ArrayList<>(); 392 ArrayList<CatalogTreeLeaf> leafList = _defaultIcons.getLeaves(); 393 int k = 0; 394 String[] stateKeys = ((SignalHead) bean).getValidStateKeys(); // states contains non-localized appearances 395 for (CatalogTreeLeaf leaf : leafList) { 396 String name = leaf.getName(); // NOI18N 397 log.debug("SignalHead Appearance leaf name= {}", name); 398 for (String state : stateKeys) { 399 if (name.equals(state) || name.equals("SignalHeadStateDark") 400 || name.equals("SignalHeadStateHeld")) { 401 String path = leaf.getPath(); 402 this.setIcon(k++, name, new NamedIcon(path, path)); 403 break; 404 } 405 } 406 } 407 } else { // no selection, revert to default signal head appearances 408 makeIcons(_defaultIcons); 409 } 410 log.debug("makeIconMap: _iconMap.size()= {}", _iconMap.size()); 411 } 412 413 private void checkIconSizes() { 414 if (!_addButton.isEnabled()) { 415 return; 416 } 417 Iterator<JToggleButton> iter = _iconMap.values().iterator(); 418 int lastWidth = 0; 419 int lastHeight = 0; 420 boolean first = true; 421 while (iter.hasNext()) { 422 JToggleButton but = iter.next(); 423 if (first) { 424 lastWidth = but.getIcon().getIconWidth(); 425 lastHeight = but.getIcon().getIconHeight(); 426 first = false; 427 continue; 428 } 429 int nextWidth = but.getIcon().getIconWidth(); 430 int nextHeight = but.getIcon().getIconHeight(); 431 if ((Math.abs(lastWidth - nextWidth) > 3 || Math.abs(lastHeight - nextHeight) > 3)) { 432 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("IconSizeDiff"), 433 Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 434 return; 435 } 436 lastWidth = nextWidth; 437 lastHeight = nextHeight; 438 } 439 log.debug("Size: width= {}, height= {}", lastWidth, lastHeight); 440 } 441 442 /** 443 * Used by Panel Editor to make the final installation of the icon(s) into 444 * the user's Panel. 445 * <p> 446 * Note! the selection is cleared. When two successive calls are made, the 447 * 2nd will always return null, regardless of the 1st return. 448 * 449 * @return the selected item 450 */ 451 public NamedBean getTableSelection() { 452 if (InstanceManager.getDefault(CatalogTreeManager.class).isIndexChanged()) { 453 checkIconSizes(); 454 } 455 int row = _table.getSelectedRow(); 456 row = _table.convertRowIndexToModel(row); 457 if (row >= 0) { 458 NamedBean b = _pickListModel.getBeanAt(row); 459 _table.clearSelection(); 460 _addButton.setEnabled(false); 461 _addButton.setToolTipText(null); 462 this.revalidate(); 463 if (b != null) { 464 log.debug("getTableSelection: row = {}, bean = {}", row, b.getDisplayName()); 465 } 466 return b; 467 } else { 468 log.debug("getTableSelection: row = 0"); 469 } 470 return null; 471 } 472 473 /** 474 * Get a new NamedIcon object for your own use. 475 * 476 * @param key Name of key (label) 477 * @return Unique object 478 */ 479 public NamedIcon getIcon(String key) { 480 log.debug("getIcon for key= {}", key); 481 return new NamedIcon((NamedIcon) _iconMap.get(key).getIcon()); 482 } 483 484 /** 485 * Get a new Hashtable of only the icons selected for display. 486 * 487 * @return a map of icons using the icon labels as keys 488 */ 489 public Hashtable<String, NamedIcon> getIconMap() { 490 log.debug("getIconMap: _allowDeletes= {}", _allowDeletes); 491 Hashtable<String, NamedIcon> iconMap = new Hashtable<>(); 492 for (Map.Entry<String, JToggleButton> entry : _iconMap.entrySet()) { 493 JToggleButton button = entry.getValue(); 494 log.debug("getIconMap: key= {}, button.isSelected()= {}", entry.getKey(), button.isSelected()); 495 if (!_allowDeletes || !button.isSelected()) { 496 iconMap.put(entry.getKey(), new NamedIcon((NamedIcon) button.getIcon())); 497 } 498 } 499 return iconMap; 500 } 501 502 /* 503 * Support selection of NamedBean from a pick list table. 504 * 505 * @param addIconAction ActionListener that adds an icon to the panel - 506 * representing either an entity as pick list selection, an 507 * arbitrary image, or a value, such as a memory value 508 * @param changeIconAction ActionListener that displays sources from 509 * which to select an image file 510 */ 511 public void complete(ActionListener addIconAction, boolean changeIcon, 512 boolean addToTable, boolean update) { 513 _update = update; 514 if (_buttonPanel != null) { 515 this.remove(_buttonPanel); 516 } 517 _buttonPanel = new JPanel(); 518 _buttonPanel.setLayout(new BoxLayout(_buttonPanel, BoxLayout.Y_AXIS)); 519 JPanel p = new JPanel(); 520 p.setLayout(new FlowLayout()); 521 if (addToTable) { 522 JPanel pInner = new JPanel(); 523 pInner.setLayout(new BoxLayout(pInner, BoxLayout.X_AXIS)); 524 _sysNameText = new JTextField(); 525 _sysNameText.setPreferredSize( 526 new Dimension(150, _sysNameText.getPreferredSize().height + 2)); 527 528 String tooltip = _pickListModel.getManager().getEntryToolTip(); 529 if (tooltip!=null) { 530 StringBuilder sb = new StringBuilder(); 531 sb.append("<br>"); 532 sb.append(_pickListModel.getManager().getMemo().getUserName()); 533 sb.append(" "); 534 sb.append(_pickListModel.getManager().getBeanTypeHandled(true)); 535 sb.append(":<br>"); 536 sb.append(_pickListModel.getManager().getEntryToolTip()); 537 tooltip = sb.toString(); 538 } 539 540 _sysNameText.setToolTipText(Bundle.getMessage("newBeanBySysNameTip", 541 _pickListModel.getManager().getBeanTypeHandled(false), 542 _pickListModel.getManager().getMemo().getUserName(), 543 InstanceManager.getDefault(jmri.jmrix.internal.InternalSystemConnectionMemo.class) 544 .getSystemPrefix()+_pickListModel.getManager().typeLetter(), 545 (tooltip==null ? "" : tooltip) 546 )); 547 _addTableButton = new JButton(Bundle.getMessage("addToTable",_pickListModel.getManager().getBeanTypeHandled())); 548 _addTableButton.addActionListener((ActionEvent a) -> addToTable()); 549 _addTableButton.setEnabled(false); 550 _addTableButton.setToolTipText(Bundle.getMessage("ToolTipWillActivate")); 551 pInner.add(_sysNameText); 552 _sysNameText.addKeyListener(new KeyAdapter() { 553 @Override 554 public void keyReleased(KeyEvent a) { 555 if (_sysNameText.getText().length() > 0) { 556 _addTableButton.setEnabled(true); 557 _addTableButton.setToolTipText(null); 558 _table.clearSelection(); 559 } 560 } 561 }); 562 563 pInner.add(_addTableButton); 564 p.add(pInner); 565 _buttonPanel.add(p); 566 p = new JPanel(); 567 p.setLayout(new FlowLayout()); //new BoxLayout(p, BoxLayout.Y_AXIS) 568 } 569 if (update) { 570 _addButton = new JButton(Bundle.getMessage("ButtonUpdateIcon")); 571 } else { 572 _addButton = new JButton(Bundle.getMessage("ButtonAddIcon")); 573 } 574 _addButton.addActionListener(addIconAction); 575 _addButton.setEnabled(true); 576 if (changeIcon) { 577 _changeButton = new JButton(Bundle.getMessage("ButtonChangeIcon")); 578 _changeButton.addActionListener((ActionEvent a) -> addCatalog()); 579 p.add(_changeButton); 580 _closeButton = new JButton(Bundle.getMessage("ButtonCloseCatalog")); 581 _closeButton.addActionListener((ActionEvent a) -> closeCatalog()); 582 _closeButton.setVisible(false); 583 p.add(_closeButton); 584 } 585 _buttonPanel.add(p); 586 if (_table != null) { 587 _addButton.setEnabled(false); 588 _addButton.setToolTipText(Bundle.getMessage("ToolTipPickFromTable")); 589 } 590 addAdditionalButtons(_buttonPanel); 591 p = new JPanel(); 592 p.add(_addButton); 593 _buttonPanel.add(p); 594 595 _buttonPanel.add(Box.createVerticalStrut(STRUT_SIZE)); 596 _buttonPanel.add(new JSeparator()); 597 this.add(_buttonPanel); 598 599 if (changeIcon) { 600 _catalog = CatalogPanel.makeDefaultCatalog(); 601 _catalog.setVisible(false); 602 _catalog.setToolTipText(Bundle.getMessage("ToolTipDragIcon")); 603 this.add(_catalog); 604 } 605 if (_type != null) { 606 createDefaultIconNodeFromMap(); 607 } 608 // Allow initial row to be set without getting callback to valueChanged 609 if (_table != null) { 610 _table.getSelectionModel().addListSelectionListener(this); 611 } 612 pack(); 613 } 614 615 protected void addAdditionalButtons(JPanel p) { 616 } 617 618 public boolean addIconIsEnabled() { 619 return _addButton.isEnabled(); 620 } 621 622 @SuppressWarnings("unchecked") // PickList is a parameterized class, but we don't use that here 623 void addToTable() { 624 String name = _sysNameText.getText(); 625 if (name != null && name.length() > 0) { 626 try { 627 NamedBean bean = _pickListModel.addBean(name); 628 if (bean != null) { 629 int setRow = _pickListModel.getIndexOf(bean); 630 _table.setRowSelectionInterval(setRow, setRow); 631 _pickTablePane.getVerticalScrollBar().setValue(setRow * ROW_HEIGHT); 632 } 633 } catch (IllegalArgumentException ex) { 634 JmriJOptionPane.showMessageDialog(this.getParent(), 635 ex.getLocalizedMessage(), 636 Bundle.getMessage("WarningTitle"), // NOI18N 637 JmriJOptionPane.WARNING_MESSAGE); 638 } 639 } 640 _sysNameText.setText(""); 641 _addTableButton.setEnabled(false); 642 _addTableButton.setToolTipText(Bundle.getMessage("ToolTipWillActivate")); 643 } 644 645 /* 646 * Add panel to change icons. 647 */ 648 public void addCatalog() { 649 log.debug("addCatalog() called"); 650 // add and display the catalog, so icons can be selected 651 if (_catalog == null) { 652 _catalog = CatalogPanel.makeDefaultCatalog(); 653 _catalog.setToolTipText(Bundle.getMessage("ToolTipDragIcon")); 654 } 655 _catalog.setVisible(true); // display the tree view 656 657 if (_changeButton != null) { 658 _changeButton.setVisible(false); 659 _closeButton.setVisible(true); 660 } 661 if (_pickTablePane != null) { 662 _pickTablePane.setVisible(false); // hide the bean table during icon edit 663 } 664 pack(); 665 } 666 667 void closeCatalog() { 668 if (_changeButton != null) { 669 _catalog.setVisible(false); // hide the tree view 670 _changeButton.setVisible(true); 671 _closeButton.setVisible(false); 672 } 673 if (_pickTablePane != null) { 674 _pickTablePane.setVisible(true); 675 } 676 pack(); 677 } 678 679 public void addDirectoryToCatalog() { 680 if (_catalog == null) { 681 _catalog = CatalogPanel.makeDefaultCatalog(); 682 } 683 if (_changeButton != null) { 684 _changeButton.setVisible(false); 685 _closeButton.setVisible(true); 686 } 687 this.add(_catalog); 688 this.pack(); 689 } 690 691 /** 692 * If icons are changed, update global tree. 693 */ 694 private void updateCatalogTree() { 695 CatalogTreeManager manager = InstanceManager.getDefault(jmri.CatalogTreeManager.class); 696 // unfiltered, xml-stored, default icon tree 697 CatalogTree tree = manager.getBySystemName("NXDI"); 698 if (tree == null) { // build a new Default Icons tree 699 tree = manager.newCatalogTree("NXDI", "Default Icons"); 700 } 701 CatalogTreeNode root = tree.getRoot(); 702 703 Enumeration<TreeNode> e = root.children(); 704 705 String name = _defaultIcons.toString(); 706 while (e.hasMoreElements()) { 707 CatalogTreeNode nChild = (CatalogTreeNode)e.nextElement(); 708 if (name.equals(nChild.toString())) { 709 log.debug("Remove node {}", nChild); 710 root.remove(nChild); 711 break; 712 } 713 } 714 root.add(_defaultIcons); 715 InstanceManager.getDefault(CatalogTreeManager.class).indexChanged(true); 716 } 717 718 private class IconButton extends DropButton { 719 720 String key; // NOI18N 721 722 IconButton(String label, Icon icon) { // init icon passed to avoid ref before ctor complete 723 super(icon); 724 key = label; 725 } 726 } 727 728 /** 729 * Clean up when its time to make it all go away 730 */ 731 public void dispose() { 732 // clean up GUI aspects 733 this.removeAll(); 734 _iconMap = null; 735 _iconOrderList = null; 736 _catalog = null; 737 } 738 739 class DropButton extends JToggleButton implements DropTargetListener { 740 741 DataFlavor dataFlavor; 742 743 DropButton(Icon icon) { 744 super(icon); 745 try { 746 dataFlavor = new DataFlavor(ImageIndexEditor.IconDataFlavorMime); 747 } catch (ClassNotFoundException cnfe) { 748 log.error("Unable to create drag and drop target.", cnfe); 749 } 750 // is the item created in this next line ever used? 751 new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, this); 752 // log.debug("DropJLabel ctor"); 753 } 754 755 @Override 756 public void dragExit(DropTargetEvent dte) { 757 // log.debug("DropJLabel.dragExit "); 758 } 759 760 @Override 761 public void dragEnter(DropTargetDragEvent dtde) { 762 // log.debug("DropJLabel.dragEnter "); 763 } 764 765 @Override 766 public void dragOver(DropTargetDragEvent dtde) { 767 // log.debug("DropJLabel.dragOver "); 768 } 769 770 @Override 771 public void dropActionChanged(DropTargetDragEvent dtde) { 772 // log.debug("DropJLabel.dropActionChanged "); 773 } 774 775 @Override 776 public void drop(DropTargetDropEvent e) { 777 try { 778 Transferable tr = e.getTransferable(); 779 if (e.isDataFlavorSupported(dataFlavor)) { 780 NamedIcon newIcon = (NamedIcon) tr.getTransferData(dataFlavor); 781 if (newIcon != null) { // newIcon never null according to contract 782 e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); 783 DropTarget target = (DropTarget) e.getSource(); 784 IconButton iconButton = (IconButton) target.getComponent(); 785 String key = iconButton.key; 786 JToggleButton button = _iconMap.get(key); 787 NamedIcon oldIcon = (NamedIcon) button.getIcon(); 788 button.setIcon(newIcon); 789 if (newIcon.getIconWidth() < 1 || newIcon.getIconHeight() < 1) { 790 button.setText(Bundle.getMessage("invisibleIcon")); 791 button.setForeground(Color.lightGray); 792 } else { 793 button.setText(null); 794 } 795 _iconMap.put(key, button); 796 if (!_update) { 797 _defaultIcons.deleteLeaf(key, oldIcon.getURL()); 798 _defaultIcons.addLeaf(key, newIcon.getURL()); 799 updateCatalogTree(); 800 } 801 e.dropComplete(true); 802 log.debug("DropJLabel.drop COMPLETED for {}, {}", key, newIcon.getURL()); 803 } else { 804 log.debug("DropJLabel.drop REJECTED!"); 805 e.rejectDrop(); 806 } 807 } 808 } catch (IOException ioe) { 809 log.debug("DropPanel.drop REJECTED!"); 810 e.rejectDrop(); 811 } catch (UnsupportedFlavorException ufe) { 812 log.debug("DropJLabel.drop REJECTED!"); 813 e.rejectDrop(); 814 } 815 } 816 } 817 818 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(IconAdder.class); 819 820}