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