001package jmri.jmrit.display.palette; 002 003import java.awt.Color; 004import java.awt.Component; 005import java.awt.Dimension; 006import java.awt.FlowLayout; 007import java.awt.GridBagConstraints; 008import java.awt.GridBagLayout; 009import java.awt.datatransfer.DataFlavor; 010import java.awt.event.ActionEvent; 011import java.awt.event.ActionListener; 012import java.util.Enumeration; 013import java.util.HashMap; 014import java.util.Map.Entry; 015 016import javax.swing.AbstractAction; 017import javax.swing.AbstractButton; 018import javax.swing.Action; 019import javax.swing.BorderFactory; 020import javax.swing.Box; 021import javax.swing.BoxLayout; 022import javax.swing.ButtonGroup; 023import javax.swing.JButton; 024import javax.swing.JComponent; 025import javax.swing.JLabel; 026import javax.swing.JPanel; 027import javax.swing.JRadioButton; 028import javax.swing.KeyStroke; 029 030import jmri.jmrit.catalog.CatalogPanel; 031import jmri.jmrit.catalog.NamedIcon; 032import jmri.jmrit.display.DisplayFrame; 033import jmri.jmrit.display.Editor; 034import jmri.util.swing.ImagePanel; 035import jmri.util.swing.JmriJOptionPane; 036 037/** 038 * ItemPanel general implementation for placement of CPE items having sets of 039 * icons (families). The "family" is the set of icons that represent the various 040 * states and/or status of the item. 041 * 042 * @see ItemPanel palette class diagram 043 * @author Pete Cressman Copyright (c) 2010, 2011, 2018 044 * @author Egbert Broerse 2017 045 */ 046public abstract class FamilyItemPanel extends ItemPanel { 047 048 protected String _family; 049 // _iconPanel (from ItemPanel) contains all the images of the icons for a 050 // selected family. 051 // _previewPanel (from ItemPanel) contains _iconPanel and optionally 052 // _dragIconPanel. 053 //protected JPanel _iconFamilyPanel; // Holds _previewPanel, _familyButtonPanel. 054 protected ImagePanel _dragIconPanel; // panel to drag to the icons to the 055 // control panel, hidden upon [Show Icons] 056 protected JPanel _familyButtonPanel; // panel of radioButtons to select icon family 057 protected JButton _showIconsButton; 058 protected JButton _updateButton; 059 protected HashMap<String, NamedIcon> _unstoredMap; 060 protected IconDialog _dialog; 061 protected ButtonGroup _familyButtonGroup; 062 063 protected boolean _isUnstoredMap; 064 protected boolean _cntlDown; // when true, edit dialog will add default sets 065 066 /** 067 * Constructor types with multiple families and multiple icon families. 068 * 069 * @param parentFrame enclosing parentFrame 070 * @param type bean type 071 * @param family icon family 072 */ 073 public FamilyItemPanel(DisplayFrame parentFrame, String type, String family) { 074 super(parentFrame, type); 075 _family = family; 076 } 077 078 @Override 079 public void init() { 080 if (!_initialized) { 081 makeShowIconsButton(); 082 super.init(); 083 } 084 hideIcons(); 085 } 086 087 /** 088 * Init for update of existing palette item type. 089 * 090 * @param doneAction doneAction 091 * @param iconMap iconMap 092 */ 093 public void init(ActionListener doneAction, HashMap<String, NamedIcon> iconMap) { 094 _update = true; 095 _doneAction = doneAction; 096 _suppressDragging = true; // no dragging when updating 097 if (iconMap != null) { 098 checkCurrentMap(iconMap); // is map in catalog? 099 } 100 if (_family == null || _family.isEmpty()) { 101 _family = Bundle.getMessage("unNamed"); 102 } 103 initIconFamiliesPanel(); 104 _initialized = true; 105 } 106 107 /** 108 * Initialization for conversion of plain track to indicator track by 109 * CircuitBuilder. 110 * 111 * @param bottomPanel button panel 112 */ 113 public void init(JPanel bottomPanel) { 114 _update = false; 115 _suppressDragging = true; // no dragging in circuitBuilder 116 initIconFamiliesPanel(); 117 remove(_bottomPanel); 118 bottomPanel.add(makeShowIconsButton(), 0); 119 add(bottomPanel); 120 _initialized = true; 121 hideIcons(); 122 } 123 124 /** 125 * Needed by CPE ConvertDialog.java 126 * 127 * @return JPanel 128 */ 129 public JPanel getBottomPanel() { 130 return _bottomPanel; 131 } 132 133 public JButton getUpdateButton() { 134 return _updateButton; 135 } 136 137 /** 138 * Add [Update] button to _bottomPanel. 139 * @param doneAction Action for button 140 */ 141 @Override 142 protected JButton makeUpdateButton(ActionListener doneAction) { 143 _updateButton = new JButton(Bundle.getMessage("updateButton")); 144 _updateButton.addActionListener(doneAction); 145 _updateButton.setToolTipText(Bundle.getMessage("ToolTipPickFromTable")); 146 return _updateButton; 147 } 148 149 @Override 150 protected JPanel makeItemButtonPanel() { 151 JPanel panel = new JPanel(); 152 panel.add(makeShowIconsButton()); 153 panel.add(makeEditButton()); 154 if (!_update) { 155 addCreateDeleteFamilyButtons(panel); 156 } 157 return panel; 158 } 159 160 protected JButton makeShowIconsButton() { 161 if (_showIconsButton == null) { 162 _showIconsButton = new JButton(Bundle.getMessage("ShowIcons")); 163 _showIconsButton.addActionListener(a -> { 164 if (_iconPanel.isVisible()) { 165 hideIcons(); 166 } else { 167 showIcons(); 168 } 169 }); 170 _showIconsButton.setToolTipText(Bundle.getMessage("ToolTipShowIcons")); 171 } 172 return _showIconsButton; 173 } 174 175 private JButton makeEditButton() { 176 JButton editButton = new JButton(Bundle.getMessage("ButtonEditIcons")); 177 editButton.addActionListener(a -> openDialog(_itemType, _family)); 178 editButton.setToolTipText(Bundle.getMessage("ToolTipEditIcons")); 179 makeControlKeyBinder(editButton); 180 return editButton; 181 } 182 183 private JButton makeNewFamilyButton() { 184 JButton button = new JButton(Bundle.getMessage("createNewFamily")); 185 button.addActionListener(a -> newFamilyDialog()); 186 button.setToolTipText(Bundle.getMessage("ToolTipAddFamily")); 187 makeControlKeyBinder(button); 188 return button; 189 } 190 191 /** 192 * Replacement panel for _bottomPanel when no icon families exist for 193 * _itemType. 194 */ 195 @Override 196 protected JPanel makeSpecialBottomPanel(boolean update) { 197 JPanel _bottom2Panel = new JPanel(); 198 if (update) { 199 _bottom2Panel.add(makeEditButton()); 200 } else { 201 _bottom2Panel.add(makeNewFamilyButton()); 202 } 203 JButton button = new JButton(Bundle.getMessage("RestoreDefault")); 204 button.addActionListener(a -> loadDefaultType()); 205 _bottom2Panel.add(button); 206 return _bottom2Panel; 207 } 208 209 protected void addCreateDeleteFamilyButtons(JPanel panel) { 210 panel.add(makeNewFamilyButton()); 211 JButton deleteButton = new JButton(Bundle.getMessage("deleteFamily")); 212 deleteButton.addActionListener(a -> deleteFamilySet()); 213 deleteButton.setToolTipText(Bundle.getMessage("ToolTipDeleteFamily")); 214 panel.add(deleteButton); 215 } 216 217 /** 218 * Check whether map is one of the families. If so, return. If not, does 219 * user want to add it to families? If so, add. If not, save for return when 220 * updated. update ctor has entered a name for _family. 221 * 222 * @param iconMap existing map of the icon 223 */ 224 private void checkCurrentMap(HashMap<String, NamedIcon> iconMap) { 225 if (_itemType.equals("SignalMast")) { 226 return; 227 } 228 String family = getValidFamilyName(_family, iconMap); 229 230 if (_isUnstoredMap) { 231 _unstoredMap = iconMap; 232 int result = JmriJOptionPane.showConfirmDialog(_frame.getEditor(), Bundle.getMessage("UnkownFamilyName", family), 233 Bundle.getMessage("QuestionTitle"), JmriJOptionPane.YES_NO_OPTION, 234 JmriJOptionPane.QUESTION_MESSAGE); 235 if (result == JmriJOptionPane.YES_OPTION) { 236 ItemPalette.addFamily(_itemType, family, iconMap); 237 } 238 _family = family; 239 } else { 240 if (family != null) { // icons same as a known family, maybe with 241 // another name 242 if (!family.equals(_family)) { 243 log.info( 244 "{} icon's family \"{}\" found but is called \"{}\" in the Catalog. Name changed to Catalog name.", 245 _itemType, _family, family); 246 _family = family; 247 } 248 } 249 } 250 } 251 252 /** 253 * Check that family name proposed by user for an icon family 1. name is not 254 * a duplicate key 2. icon family is already stored. (Sets "_isUnstoredMap" 255 * flag.) 256 * 257 * @param family name for icon set 258 * @param iconMap map the family name refers to. 259 * @return valid family name or null if user declines to provide a valid 260 * name. 261 */ 262 protected String getValidFamilyName(String family, HashMap<String, NamedIcon> iconMap) { 263 HashMap<String, HashMap<String, NamedIcon>> families = ItemPalette.getFamilyMaps(_itemType); 264 String mapFamily; 265 if (iconMap != null) { 266 mapFamily = findFamilyOfMap(null, iconMap, families); 267 if (mapFamily == null) { 268 _isUnstoredMap = true; 269 } else { 270 log.debug("getValidFamilyName: findFamilyOfMap {} found stored family \"{}\" for family \"{}\".", 271 _itemType, mapFamily, family); 272 _isUnstoredMap = false; 273 if (family != null) { 274 return mapFamily; 275 } 276 } 277 } 278 mapFamily = family; 279 // check that name is not duplicate. 280 boolean nameOK = false; 281 while (!nameOK) { 282 if (mapFamily == null || mapFamily.isEmpty()) { 283 Component fr; 284 if (_dialog != null) { 285 fr = _dialog; 286 } else { 287 fr = this; 288 } 289 mapFamily = JmriJOptionPane.showInputDialog(fr, Bundle.getMessage("EnterFamilyName"), 290 Bundle.getMessage("createNewFamily"), JmriJOptionPane.QUESTION_MESSAGE ); 291 if (mapFamily == null) { // user quit 292 return null; 293 } 294 } 295 if (families.isEmpty()) { 296 break; 297 } 298 for (String fam : families.keySet()) { 299 if (mapFamily.equals(fam)) { 300 if (_update) { 301 String thisType = NAME_MAP.get(_itemType); 302 JmriJOptionPane.showMessageDialog(_frame, 303 Bundle.getMessage("DuplicateFamilyName", mapFamily, Bundle.getMessage(thisType), 304 Bundle.getMessage("UseAnotherName")), Bundle.getMessage("WarningTitle"), JmriJOptionPane.WARNING_MESSAGE); 305 mapFamily = null; 306 nameOK = false; 307 break; 308 } else { 309 return mapFamily; 310 } 311 } 312 nameOK = true; 313 } 314 if (!nameOK && _update) { 315 break; 316 } 317 } 318 return mapFamily; 319 } 320 321 /** 322 * Find the family name of the map in a families HashMap. 323 * 324 * @param exemptFamily exclude from matching 325 * @param newMap iconMap 326 * @param families families of itemType 327 * @return null if map is not in the family 328 */ 329 protected String findFamilyOfMap(String exemptFamily, HashMap<String, NamedIcon> newMap, 330 HashMap<String, HashMap<String, NamedIcon>> families) { 331 for (Entry<String, HashMap<String, NamedIcon>> entry : families.entrySet()) { 332 String family = entry.getKey(); 333 // log.debug("FamilyKey = {}", entry.getKey()); 334 if (!family.equals(exemptFamily)) { 335 if (mapsAreEqual(entry.getValue(), newMap)) { 336 // log.debug("findFamilyOfMap: Map found with name \"{}\"", 337 // entry.getKey()); 338 return entry.getKey(); 339 } 340 } 341 } 342 return null; 343 } 344 345 protected boolean namesStoredMap(String family) { 346 HashMap<String, HashMap<String, NamedIcon>> families = ItemPalette.getFamilyMaps(_itemType); 347 return families.containsKey(family); 348 } 349 350 /* 351 * Entry point when returning from result of familiesMissing() call 352 */ 353 @Override 354 protected void makeFamiliesPanel() { 355 HashMap<String, HashMap<String, NamedIcon>> families = ItemPalette.getFamilyMaps(_itemType); 356 boolean isEmpty = families.values().isEmpty(); 357 if (_bottomPanel == null) { 358 makeBottomPanel(isEmpty); 359 } else { 360 if (isEmpty ^ _wasEmpty) { 361 remove(_bottomPanel); 362 makeBottomPanel(isEmpty); 363 log.debug("REMAKE BOTTOM PANEL {}", _itemType); 364 } 365 } 366 if (!isEmpty) { 367 makeFamilyButtons(families.keySet()); // makes _familyButtonPanel 368 if (_currentIconMap == null || _currentIconMap.isEmpty()) { 369 _currentIconMap = families.get(_family); 370 } 371 } 372 373 if (_currentIconMap == null) { 374 if (_isUnstoredMap) { 375 _currentIconMap = _unstoredMap; 376 } else { 377 _currentIconMap = new HashMap<>(); 378 } 379 } 380 _wasEmpty = isEmpty; 381 382 if (!_suppressDragging) { 383 makeDragIconPanel(); 384 makeDndIcon(_currentIconMap); 385 } 386 387 addIconsToPanel(_currentIconMap, _iconPanel, false); 388 addFamilyPanels(!isEmpty); 389 } 390 391 @Override 392 protected JPanel instructions() { 393 JPanel blurb = new JPanel(); 394 blurb.setLayout(new BoxLayout(blurb, BoxLayout.Y_AXIS)); 395 String thisType = NAME_MAP.get(_itemType); 396 blurb.add(new JLabel(Bundle.getMessage("PickRowBean", Bundle.getMessage(thisType)))); 397 blurb.add(new JLabel(Bundle.getMessage("DragBean"))); 398 JPanel panel = new JPanel(); 399 panel.add(blurb); 400 return panel; 401 } 402 403 protected void addFamilyPanels(boolean hasMaps) { 404 makePreviewPanel(hasMaps, _dragIconPanel); 405 406 if (_familyButtonPanel != null) { 407 _iconFamilyPanel.add(_familyButtonPanel); 408 } 409 _iconPanel.setVisible(false); 410 } 411 412 // the null checks are needed for several rare cases where nulls can occur 413 protected void updateFamiliesPanel() { 414 log.debug("updateFamiliesPanel for {}", _itemType); 415 if (_iconPanel != null) { 416 _iconPanel.removeAll(); 417 } 418 if (_dragIconPanel != null) { 419 _dragIconPanel.removeAll(); 420 } 421 if (_previewPanel != null) { 422 _previewPanel.setVisible(false); 423 } 424 if (_familyButtonPanel != null) { 425 _familyButtonPanel.removeAll(); 426 } 427 makeFamiliesPanel(); 428 _iconFamilyPanel.invalidate(); 429 } 430 431 /** 432 * Make the _familyButtonPanel panel of buttons to select a family. Create 433 * and set actions of radioButtons to change family on pane. 434 * 435 * @param keySet of icon family names 436 */ 437 protected void makeFamilyButtons(java.util.Set<String> keySet) { 438 if (_familyButtonPanel == null) { 439 _familyButtonPanel = new JPanel(); // this is only a local object 440 _familyButtonPanel.setLayout(new BoxLayout(_familyButtonPanel, BoxLayout.Y_AXIS)); 441 } else { 442 _familyButtonPanel.removeAll(); 443 } 444 log.debug("makeFamilyButtons for {} family= {}", _itemType, _family); 445 String thisType = NAME_MAP.get(_itemType); 446 String txt = Bundle.getMessage("IconFamiliesLabel", Bundle.getMessage(thisType)); 447 448 JPanel p = new JPanel(new FlowLayout()); 449 p.add(new JLabel(txt)); 450 p.setOpaque(false); 451 _familyButtonPanel.add(p); 452 _familyButtonGroup = new ButtonGroup(); 453 454 GridBagLayout gridbag = new GridBagLayout(); 455 GridBagConstraints c = ItemPanel.itemGridBagConstraint(); 456 457 int numCol = 4; 458 JPanel buttonPanel = new JPanel(); 459 buttonPanel.setLayout(gridbag); 460 String family = ""; 461 int length = 0; 462 JRadioButton button = null; 463 464 for (String s : keySet) { 465 family = s; 466 length += family.length(); 467 button = new JRadioButton(family); 468 addFamilyButtonListener(button, family); 469 if (family.equals(_family)) { 470 button.setSelected(true); 471 } 472 log.debug("{} ActionListener and button for family \"{}\" at gridx= {} gridy= {}", _itemType, family, c.gridx, c.gridy); 473 gridbag.setConstraints(button, c); 474 buttonPanel.add(button, c); 475 if (c.gridx >= numCol || length > 50) { // start next row 476 c.gridy++; 477 c.gridx = 0; 478 length = 0; 479 } 480 c.gridx++; 481 } 482 if (button != null && _family == null) { 483 button.setSelected(true); 484 _family = family; 485 } else if (_family != null && !keySet.contains(_family)) { 486 button = new JRadioButton(_family); 487 addFamilyButtonListener(button, _family); 488 log.debug("\"{}\" ActionListener and button for family \"{}\" at gridx= {} gridy= {}", _itemType, _family, 489 c.gridx, c.gridy); 490 gridbag.setConstraints(button, c); 491 buttonPanel.add(button, c); 492 button.setSelected(true); 493 } 494 _familyButtonPanel.add(buttonPanel); 495 } 496 497 private void addFamilyButtonListener(JRadioButton button, String family) { 498 button.addActionListener(new ActionListener() { 499 String fam; 500 501 @Override 502 public void actionPerformed(ActionEvent e) { 503 setFamily(fam); 504 } 505 506 ActionListener init(String f) { 507 fam = f; 508 return this; 509 } 510 }.init(family)); 511 _familyButtonGroup.add(button); 512 } 513 514 /** 515 * Position initial Preview component on _iconFamilyPanel. If already 516 * present, keep and clear it. 517 */ 518 protected void makeDragIconPanel() { 519 if (_dragIconPanel == null) { 520 _dragIconPanel = new ImagePanel(); 521 _dragIconPanel.setOpaque(true); // to show background color/squares 522 _dragIconPanel.setLayout(new FlowLayout()); 523 _dragIconPanel.setBorder(BorderFactory.createLineBorder(Color.black)); 524 _dragIconPanel.setToolTipText(Bundle.getMessage("ToolTipDragIcon")); 525 } else { 526 _dragIconPanel.removeAll(); 527 } 528 _dragIconPanel.setImage(_frame.getPreviewBackground()); 529 if (_iconPanel != null) { 530 _iconPanel.setImage(_frame.getPreviewBackground()); 531 } 532 _dragIconPanel.setVisible(true); 533 } 534 535 @Override 536 protected JPanel makeIconDisplayPanel(String key, HashMap<String, NamedIcon> iconMap, boolean dropIcon) { 537 NamedIcon icon = iconMap.get(key); 538 JPanel panel = new JPanel(); 539 JLabel image; 540 if (dropIcon) { 541 image = new DropJLabel(icon, iconMap); 542 } else { 543 image = new JLabel(icon); 544 } 545 wrapIconImage(icon, image, panel, key); 546 return panel; 547 } 548 549 protected JLabel getDragger(DataFlavor flavor, HashMap<String, NamedIcon> map, NamedIcon icon) { 550 return null; 551 } 552 553 protected void makeDndIcon(HashMap<String, NamedIcon> iconMap) { 554 if (iconMap == null) { 555 return; 556 } 557 JLabel label; 558 NamedIcon icon; 559 String scaleText; 560 if (!iconMap.isEmpty()) { 561 String displayKey = getDisplayKey(); 562 if (iconMap.get(displayKey) == null) { 563 displayKey = (String) iconMap.keySet().toArray()[0]; 564 } 565 icon = iconMap.get(displayKey); 566 if (log.isDebugEnabled()) { 567 log.debug("makeDndIcon for {}, {}. displayKey \"{}\" has icon {}", 568 _itemType, _family, displayKey, (icon != null)); 569 } 570 if (icon != null) { 571 icon = new NamedIcon(icon); 572 double scale = icon.reduceTo(CatalogPanel.ICON_WIDTH, 573 CatalogPanel.ICON_HEIGHT, CatalogPanel.ICON_SCALE); 574 scaleText = java.text.MessageFormat.format(Bundle.getMessage("scale"), 575 CatalogPanel.printDbl(scale, 2)); 576 } else { 577 scaleText = Bundle.getMessage("noIcon"); 578 } 579 try { 580 label = getDragger(new DataFlavor(Editor.POSITIONABLE_FLAVOR), iconMap, icon); 581 } catch (java.lang.ClassNotFoundException cnfe) { 582 log.warn("no DndIconPanel for {}, {} created", _itemType, displayKey, cnfe); 583 label = new JLabel(scaleText); 584 } 585 } else { 586 label = new JLabel("- - - - - -"); 587 scaleText = Bundle.getMessage("noIcon"); 588 } 589 JPanel panel = makeDragIconPanel(label, scaleText); 590 _dragIconPanel.add(panel); 591 } 592 593 /** 594 * Get the key to display the icon to be used for dragging to the panel 595 * 596 * @return key for desired icon 597 */ 598 abstract protected String getDisplayKey(); 599 600 private JPanel makeDragIconPanel(JLabel label, String scaleText) { 601 JPanel panel = new JPanel(); 602 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 603 String borderName = Bundle.getMessage("dragToPanel"); 604 panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black), 605 borderName)); 606 panel.setToolTipText(Bundle.getMessage("ToolTipDragIcon")); 607 panel.setOpaque(false); 608 panel.add(Box.createVerticalGlue()); 609 if (label != null) { 610 label.setToolTipText(Bundle.getMessage("ToolTipDragIcon")); 611 // label.setIcon(icon); 612 label.setName(borderName); 613 label.setOpaque(false); 614 JPanel p = new JPanel(); 615 p.add(label); 616 p.setOpaque(false); 617 panel.add(p); 618 } 619 JPanel p = new JPanel(); 620 p.setOpaque(false); 621 p.add(new JLabel(scaleText)); 622 panel.add(p); 623 Dimension dim = panel.getPreferredSize(); 624 dim.width = Math.max(CatalogPanel.ICON_WIDTH, dim.width) + 10; 625 panel.setPreferredSize(dim); 626 return panel; 627 } 628 629 @Override 630 protected void hideIcons() { 631 boolean isPalette = (_frame instanceof ItemPalette); 632 Dimension totalDim = _frame.getSize(); 633 Dimension oldDim = getSize(); 634 if (_iconPanel != null) { 635 _iconPanel.setVisible(false); 636 _iconPanel.invalidate(); // force redraw 637 if (_update) { 638 _previewPanel.setVisible(false); 639 } 640 if (!_suppressDragging) { 641 _dragIconPanel.setVisible(true); 642 _dragIconPanel.invalidate(); 643 _previewPanel.setVisible(true); 644 _instructions.setVisible(true); 645 } else { 646 _previewPanel.setVisible(false); 647 } 648 _previewPanel.invalidate(); // force redraw 649 } 650 reSizeDisplay(isPalette, oldDim, totalDim); 651 _showIconsButton.setText(Bundle.getMessage("ShowIcons")); 652 closeDialogs(); 653 } 654 655 protected void showIcons() { 656 boolean isPalette = (_frame instanceof ItemPalette); 657 Dimension totalDim = _frame.getSize(); 658 Dimension oldDim = getSize(); 659 if (_iconPanel != null) { 660 _iconPanel.setVisible(true); 661 _iconPanel.invalidate(); // force redraw 662 if (_update) { 663 _previewPanel.setVisible(true); 664 } 665 if (!_suppressDragging) { 666 _dragIconPanel.setVisible(false); 667 _dragIconPanel.invalidate(); 668 _instructions.setVisible(false); 669 } else { 670 _previewPanel.setVisible(true); 671 } 672 _previewPanel.invalidate(); // force redraw 673 } 674 reSizeDisplay(isPalette, oldDim, totalDim); 675 _showIconsButton.setText(Bundle.getMessage("HideIcons")); 676 closeDialogs(); 677 } 678 679 /** 680 * Action item for deletion of an icon family. 681 */ 682 protected void deleteFamilySet() { 683 if (JmriJOptionPane.showConfirmDialog(_frame, Bundle.getMessage("confirmDelete", _family), 684 Bundle.getMessage("QuestionTitle"), JmriJOptionPane.YES_NO_OPTION, 685 JmriJOptionPane.QUESTION_MESSAGE) == JmriJOptionPane.YES_OPTION) { 686 ItemPalette.removeIconMap(_itemType, _family); 687 _family = null; 688 _currentIconMap = null; 689 updateFamiliesPanel(); 690 } 691 } 692 693 protected void setControlDown(boolean b) { 694 _cntlDown = b; 695 } 696 Action pressed = new AbstractAction() { 697 @Override 698 public void actionPerformed(ActionEvent e) { 699 setControlDown(true); 700 } 701 }; 702 Action released = new AbstractAction() { 703 @Override 704 public void actionPerformed(ActionEvent e) { 705 setControlDown(false); 706 } 707 }; 708 709 private void makeControlKeyBinder(JComponent comp) { 710 comp.getInputMap().put(KeyStroke.getKeyStroke("control A"), "pressed"); 711 comp.getActionMap().put("pressed", pressed); 712 comp.getInputMap().put(KeyStroke.getKeyStroke("control released A"), "released"); 713 comp.getActionMap().put("released", released); 714 } 715 716 private boolean newFamilyDialog() { 717 if (_cntlDown) { 718 loadDefaultType(); 719 _cntlDown = false; 720 return true; 721 } 722 String family = JmriJOptionPane.showInputDialog(_frame, Bundle.getMessage("EnterFamilyName"), 723 Bundle.getMessage("createNewFamily"), JmriJOptionPane.QUESTION_MESSAGE ); 724 if (family == null) { 725 return false; 726 } 727 _family = null; // don't delete current family when adding new 728 openDialog(_itemType, family); 729 return true; 730 } 731 732 protected void openDialog(String type, String family) { 733 closeDialogs(); 734 hideIcons(); 735 _dialog = new IconDialog(type, family, this); 736 if (_family == null) { 737 _dialog.setMap(null); 738 } else { 739 _dialog.setMap(_currentIconMap); 740 } 741 } 742 743 /** 744 * IconDialog calls this method to make any changes 'permanent'. It is 745 * responsible for testing that the changes are valid. 746 * 747 * @param family family name, possibly changed 748 * @param iconMap family map, possibly changed 749 */ 750 protected void dialogDoneAction(String family, HashMap<String, NamedIcon> iconMap) { 751 if (!_update && !(family.equals(_family) && mapsAreEqual(iconMap, _currentIconMap))) { 752 ItemPalette.removeIconMap(_itemType, _family); 753 ItemPalette.addFamily(_itemType, family, iconMap); 754 } else { 755 _currentIconMap = iconMap; 756 if (!namesStoredMap(family)) { 757 _isUnstoredMap = true; 758 } 759 if (_isUnstoredMap) { 760 _unstoredMap = iconMap; 761 } 762 } 763 _family = family; 764 makeFamiliesPanel(); 765 setFamily(family); 766 _cntlDown = false; 767 hideIcons(); 768 if (log.isDebugEnabled()) { 769 log.debug("dialogDoneAction done for {} {} update={}. unStored={}", 770 _itemType, _family, _update, _isUnstoredMap); 771 } 772 } 773 774 protected boolean isUpdate() { 775 return _update; 776 } 777 778 @Override 779 public void closeDialogs() { 780 if (_dialog != null) { 781 _dialog.closeDialogs(); 782 _dialog.dispose(); 783 _dialog = null; 784 } 785 } 786 787 public void dispose() { 788 closeDialogs(); 789 } 790 791 /** 792 * Recover from cancelled Add Family dialog 793 */ 794 protected void setFamily() { 795 if (_familyButtonGroup == null) { 796 return; 797 } 798 Enumeration<AbstractButton> en = _familyButtonGroup.getElements(); 799 while (en.hasMoreElements()) { 800 AbstractButton button = en.nextElement(); 801 if (button.isSelected()) { 802 _family = button.getText(); 803 break; 804 } 805 } 806 } 807 /** 808 * Action of family radio button. MultiSensorItemPanel and 809 * IndicatorTOItemPanel must override. 810 * 811 * @param family icon family name 812 */ 813 protected void setFamily(String family) { 814 _family = family; 815 setFamilyMaps(); 816 _iconFamilyPanel.invalidate(); // force redraw 817 hideIcons(); 818 setFamilyButton(); 819 } 820 821 protected void setFamilyMaps() { 822 _currentIconMap = ItemPalette.getIconMap(_itemType, _family); 823 if (_currentIconMap == null) { 824 _isUnstoredMap = true; 825 _currentIconMap = _unstoredMap; 826 } 827 if (!_suppressDragging) { 828 makeDragIconPanel(); 829 makeDndIcon(_currentIconMap); 830 } 831 addIconsToPanel(_currentIconMap, _iconPanel, false); 832 } 833 834 protected void setFamilyButton() { 835 if (_familyButtonGroup == null) { 836 return; 837 } 838 Enumeration<AbstractButton> en = _familyButtonGroup.getElements(); 839 while (en.hasMoreElements()) { 840 AbstractButton button = en.nextElement(); 841 if (_family != null && _family.equals(button.getText())) { 842 button.setSelected(true); 843 break; 844 } 845 } 846 } 847 848 @Override 849 protected void previewColorChange() { 850 if (_dialog != null) { 851 ImagePanel iconPanel = _dialog.getIconEditPanel(); 852 if (iconPanel != null) { 853 iconPanel.setImage(_frame.getPreviewBackground()); 854 } 855 iconPanel = _dialog.getCatalogPreviewPanel(); 856 if (iconPanel != null) { 857 iconPanel.setImage(_frame.getPreviewBackground()); 858 } 859 } 860 log.debug("FamilyItemPanel.super stores previewColorChange"); 861 super.previewColorChange(); 862 } 863 864 /** 865 * Create icon set to panel icon display class. 866 * 867 * @return updated icon map 868 */ 869 public HashMap<String, NamedIcon> getIconMap() { 870 if (_currentIconMap != null) { 871 return _currentIconMap; 872 } 873 HashMap<String, NamedIcon> map = ItemPalette.getIconMap(_itemType, _family); 874 if (map == null) { 875 map = _unstoredMap; 876 } 877 if (map == null) { 878 log.warn("Family \"{}\" for type \"{}\" not found.", _family, _itemType); 879 map = makeNewIconMap(_itemType); 880 } 881 return map; 882 } 883 884 public String getFamilyName() { 885 return _family; 886 } 887 888 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FamilyItemPanel.class); 889 890}