001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Component; 007import java.awt.GraphicsEnvironment; 008import java.awt.GridBagLayout; 009import java.util.List; 010 011import javax.swing.DefaultListCellRenderer; 012import javax.swing.JLabel; 013import javax.swing.JList; 014import javax.swing.JOptionPane; 015import javax.swing.JPanel; 016 017import org.openstreetmap.josm.Main; 018import org.openstreetmap.josm.gui.ExtendedDialog; 019import org.openstreetmap.josm.gui.layer.Layer; 020import org.openstreetmap.josm.gui.widgets.JosmComboBox; 021import org.openstreetmap.josm.tools.GBC; 022import org.openstreetmap.josm.tools.Shortcut; 023import org.openstreetmap.josm.tools.Utils; 024 025/** 026 * Abstract superclass of different "Merge" actions. 027 * @since 1890 028 */ 029public abstract class AbstractMergeAction extends JosmAction { 030 031 /** 032 * the list cell renderer used to render layer list entries 033 */ 034 public static class LayerListCellRenderer extends DefaultListCellRenderer { 035 036 @Override 037 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 038 Layer layer = (Layer) value; 039 JLabel label = (JLabel) super.getListCellRendererComponent(list, layer.getName(), index, isSelected, cellHasFocus); 040 label.setIcon(layer.getIcon()); 041 label.setToolTipText(layer.getToolTipText()); 042 return label; 043 } 044 } 045 046 /** 047 * Constructs a new {@code AbstractMergeAction}. 048 * @param name the action's text as displayed on the menu (if it is added to a menu) 049 * @param iconName the filename of the icon to use 050 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note 051 * that html is not supported for menu actions on some platforms. 052 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always 053 * do want a shortcut, remember you can always register it with group=none, so you 054 * won't be assigned a shortcut unless the user configures one. If you pass null here, 055 * the user CANNOT configure a shortcut for your action. 056 * @param register register this action for the toolbar preferences? 057 */ 058 public AbstractMergeAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean register) { 059 super(name, iconName, tooltip, shortcut, register); 060 } 061 062 /** 063 * Constructs a new {@code AbstractMergeAction}. 064 * @param name the action's text as displayed on the menu (if it is added to a menu) 065 * @param iconName the filename of the icon to use 066 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note 067 * that html is not supported for menu actions on some platforms. 068 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always 069 * do want a shortcut, remember you can always register it with group=none, so you 070 * won't be assigned a shortcut unless the user configures one. If you pass null here, 071 * the user CANNOT configure a shortcut for your action. 072 * @param register register this action for the toolbar preferences? 073 * @param toolbar identifier for the toolbar preferences. The iconName is used, if this parameter is null 074 * @param installAdapters false, if you don't want to install layer changed and selection changed adapters 075 */ 076 public AbstractMergeAction(String name, String iconName, String tooltip, Shortcut shortcut, 077 boolean register, String toolbar, boolean installAdapters) { 078 super(name, iconName, tooltip, shortcut, register, toolbar, installAdapters); 079 } 080 081 /** 082 * Ask user to choose the target layer. 083 * @param targetLayers list of candidate target layers. 084 * @return the chosen layer 085 */ 086 protected static Layer askTargetLayer(List<Layer> targetLayers) { 087 return askTargetLayer(targetLayers.toArray(new Layer[0]), 088 tr("Please select the target layer."), 089 tr("Select target layer"), 090 tr("Merge"), "dialogs/mergedown"); 091 } 092 093 /** 094 * Asks a target layer. 095 * @param <T> type of layer 096 * @param targetLayers array of proposed target layers 097 * @param label label displayed in dialog 098 * @param title title of dialog 099 * @param buttonText text of button used to select target layer 100 * @param buttonIcon icon name of button used to select target layer 101 * @return choosen target layer 102 */ 103 @SuppressWarnings("unchecked") 104 public static <T extends Layer> T askTargetLayer(T[] targetLayers, String label, String title, String buttonText, String buttonIcon) { 105 JosmComboBox<T> layerList = new JosmComboBox<>(targetLayers); 106 layerList.setRenderer(new LayerListCellRenderer()); 107 layerList.setSelectedIndex(0); 108 109 JPanel pnl = new JPanel(new GridBagLayout()); 110 pnl.add(new JLabel(label), GBC.eol()); 111 pnl.add(layerList, GBC.eol().fill(GBC.HORIZONTAL)); 112 if (GraphicsEnvironment.isHeadless()) { 113 // return first layer in headless mode, for unit tests 114 return targetLayers[0]; 115 } 116 ExtendedDialog ed = new ExtendedDialog(Main.parent, title, buttonText, tr("Cancel")); 117 ed.setButtonIcons(buttonIcon, "cancel"); 118 ed.setContent(pnl); 119 ed.showDialog(); 120 if (ed.getValue() != 1) { 121 return null; 122 } 123 return (T) layerList.getSelectedItem(); 124 } 125 126 /** 127 * Warns user when there no layers the source layer could be merged to. 128 * @param sourceLayer source layer 129 */ 130 protected void warnNoTargetLayersForSourceLayer(Layer sourceLayer) { 131 String message = tr("<html>There are no layers the source layer<br>''{0}''<br>could be merged to.</html>", 132 Utils.escapeReservedCharactersHTML(sourceLayer.getName())); 133 if (!GraphicsEnvironment.isHeadless()) { 134 JOptionPane.showMessageDialog(Main.parent, message, tr("No target layers"), JOptionPane.WARNING_MESSAGE); 135 } 136 } 137}