001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs; 003 004import org.openstreetmap.josm.Main; 005import org.openstreetmap.josm.data.osm.PrimitiveId; 006import org.openstreetmap.josm.gui.ExtendedDialog; 007import org.openstreetmap.josm.gui.widgets.HistoryComboBox; 008import org.openstreetmap.josm.gui.widgets.HtmlPanel; 009import org.openstreetmap.josm.gui.widgets.JosmTextField; 010import org.openstreetmap.josm.gui.widgets.OsmIdTextField; 011import org.openstreetmap.josm.gui.widgets.OsmPrimitiveTypesComboBox; 012import org.openstreetmap.josm.tools.Utils; 013 014import javax.swing.BorderFactory; 015import javax.swing.GroupLayout; 016import javax.swing.JLabel; 017import javax.swing.JOptionPane; 018import javax.swing.JPanel; 019import javax.swing.KeyStroke; 020import javax.swing.border.EtchedBorder; 021import javax.swing.plaf.basic.BasicComboBoxEditor; 022import java.awt.Component; 023import java.awt.Dimension; 024import java.awt.event.ItemEvent; 025import java.awt.event.ItemListener; 026import java.awt.event.KeyEvent; 027import java.awt.event.WindowEvent; 028import java.awt.event.WindowListener; 029import java.util.Collection; 030import java.util.Collections; 031import java.util.LinkedList; 032import java.util.List; 033 034import static org.openstreetmap.josm.tools.I18n.tr; 035import static org.openstreetmap.josm.tools.I18n.trc; 036 037/** 038 * Dialog prompt to user to let him choose OSM primitives by specifying their type and IDs. 039 * @since 6448, split from DownloadObjectDialog 040 */ 041public class OsmIdSelectionDialog extends ExtendedDialog implements WindowListener { 042 043 protected final JPanel panel = new JPanel(); 044 protected final OsmPrimitiveTypesComboBox cbType = new OsmPrimitiveTypesComboBox(); 045 protected final OsmIdTextField tfId = new OsmIdTextField(); 046 protected final HistoryComboBox cbId = new HistoryComboBox(); 047 protected final GroupLayout layout = new GroupLayout(panel); 048 049 public OsmIdSelectionDialog(Component parent, String title, String[] buttonTexts) { 050 super(parent, title, buttonTexts); 051 } 052 053 public OsmIdSelectionDialog(Component parent, String title, String[] buttonTexts, boolean modal) { 054 super(parent, title, buttonTexts, modal); 055 } 056 057 public OsmIdSelectionDialog(Component parent, String title, String[] buttonTexts, boolean modal, boolean disposeOnClose) { 058 super(parent, title, buttonTexts, modal, disposeOnClose); 059 } 060 061 protected void init() { 062 panel.setLayout(layout); 063 layout.setAutoCreateGaps(true); 064 layout.setAutoCreateContainerGaps(true); 065 066 JLabel lbl1 = new JLabel(tr("Object type:")); 067 068 cbType.addItem(trc("osm object types", "mixed")); 069 cbType.setToolTipText(tr("Choose the OSM object type")); 070 JLabel lbl2 = new JLabel(tr("Object ID:")); 071 072 cbId.setEditor(new BasicComboBoxEditor() { 073 @Override 074 protected JosmTextField createEditorComponent() { 075 return tfId; 076 } 077 }); 078 cbId.setToolTipText(tr("Enter the ID of the object that should be downloaded")); 079 restorePrimitivesHistory(cbId); 080 081 // forward the enter key stroke to the download button 082 tfId.getKeymap().removeKeyStrokeBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false)); 083 tfId.setPreferredSize(new Dimension(400, tfId.getPreferredSize().height)); 084 085 HtmlPanel help = new HtmlPanel(tr("Object IDs can be separated by comma or space.<br/>" 086 + " Examples: <b><ul><li>1 2 5</li><li>1,2,5</li></ul><br/></b>" 087 + " In mixed mode, specify objects like this: <b>w123, n110, w12, r15</b><br/>")); 088 help.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED)); 089 090 cbType.addItemListener(new ItemListener() { 091 @Override 092 public void itemStateChanged(ItemEvent e) { 093 tfId.setType(cbType.getType()); 094 tfId.performValidation(); 095 } 096 }); 097 098 final GroupLayout.SequentialGroup sequentialGroup = layout.createSequentialGroup() 099 .addGroup(layout.createParallelGroup() 100 .addComponent(lbl1) 101 .addComponent(cbType, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)) 102 .addGroup(layout.createParallelGroup() 103 .addComponent(lbl2) 104 .addComponent(cbId, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)); 105 106 final GroupLayout.ParallelGroup parallelGroup = layout.createParallelGroup() 107 .addGroup(layout.createSequentialGroup() 108 .addGroup(layout.createParallelGroup() 109 .addComponent(lbl1) 110 .addComponent(lbl2) 111 ) 112 .addGroup(layout.createParallelGroup() 113 .addComponent(cbType) 114 .addComponent(cbId)) 115 ); 116 117 for (Component i : getComponentsBeforeHelp()) { 118 sequentialGroup.addComponent(i); 119 parallelGroup.addComponent(i); 120 } 121 122 layout.setVerticalGroup(sequentialGroup.addComponent(help)); 123 layout.setHorizontalGroup(parallelGroup.addComponent(help)); 124 } 125 126 /** 127 * Let subclasses add custom components between the id input field and the help text 128 * @return the collections to add 129 */ 130 protected Collection<Component> getComponentsBeforeHelp() { 131 return Collections.emptySet(); 132 } 133 134 /** 135 * Allows subclasses to specify a different continue button index. If this button is pressed, the history is updated. 136 * @return the button index 137 */ 138 public int getContinueButtonIndex() { 139 return 1; 140 } 141 142 /** 143 * Restore the current history from the preferences 144 * 145 * @param cbHistory the {@link HistoryComboBox} to which the history is restored to 146 */ 147 protected void restorePrimitivesHistory(HistoryComboBox cbHistory) { 148 java.util.List<String> cmtHistory = new LinkedList<String>(Main.pref.getCollection(getClass().getName() + ".primitivesHistory", new LinkedList<String>())); 149 // we have to reverse the history, because ComboBoxHistory will reverse it again in addElement() 150 Collections.reverse(cmtHistory); 151 cbHistory.setPossibleItems(cmtHistory); 152 } 153 154 /** 155 * Remind the current history in the preferences 156 * 157 * @param cbHistory the {@link HistoryComboBox} of which to restore the history 158 */ 159 protected void remindPrimitivesHistory(HistoryComboBox cbHistory) { 160 cbHistory.addCurrentItemToHistory(); 161 Main.pref.putCollection(getClass().getName() + ".primitivesHistory", cbHistory.getHistory()); 162 } 163 164 /** 165 * Gets the requested OSM object IDs. 166 * 167 * @return The list of requested OSM object IDs 168 */ 169 public final List<PrimitiveId> getOsmIds() { 170 return tfId.getIds(); 171 } 172 173 @Override 174 public void setupDialog() { 175 setContent(panel, false); 176 cbType.setSelectedIndex(Main.pref.getInteger("downloadprimitive.lasttype", 0)); 177 tfId.setType(cbType.getType()); 178 if (Main.pref.getBoolean("downloadprimitive.autopaste", true)) { 179 tryToPasteFromClipboard(tfId, cbType); 180 } 181 setDefaultButton(getContinueButtonIndex()); 182 addWindowListener(this); 183 super.setupDialog(); 184 } 185 186 protected void tryToPasteFromClipboard(OsmIdTextField tfId, OsmPrimitiveTypesComboBox cbType) { 187 String buf = Utils.getClipboardContent(); 188 if (buf != null) { 189 if (buf.contains("node")) cbType.setSelectedIndex(0); 190 if (buf.contains("way")) cbType.setSelectedIndex(1); 191 if (buf.contains("relation")) cbType.setSelectedIndex(2); 192 String[] res = buf.split("/"); 193 String txt; 194 if (res.length > 0) { 195 txt = res[res.length - 1]; 196 if (txt.isEmpty() && txt.length() > 1) txt = res[res.length - 2]; 197 } else { 198 txt = buf; 199 } 200 if (buf.length() <= Main.pref.getInteger("downloadprimitive.max-autopaste-length", 2000)) { 201 tfId.tryToPasteFrom(txt); 202 } 203 } 204 } 205 206 @Override public void windowClosed(WindowEvent e) { 207 if (e != null && e.getComponent() == this && getValue() == getContinueButtonIndex()) { 208 Main.pref.putInteger("downloadprimitive.lasttype", cbType.getSelectedIndex()); 209 210 if (!tfId.readIds()) { 211 JOptionPane.showMessageDialog(getParent(), 212 tr("Invalid ID list specified\n" 213 + "Cannot continue."), 214 tr("Information"), 215 JOptionPane.INFORMATION_MESSAGE 216 ); 217 return; 218 } 219 220 remindPrimitivesHistory(cbId); 221 } 222 } 223 224 @Override public void windowOpened(WindowEvent e) {} 225 @Override public void windowClosing(WindowEvent e) {} 226 @Override public void windowIconified(WindowEvent e) {} 227 @Override public void windowDeiconified(WindowEvent e) {} 228 @Override public void windowActivated(WindowEvent e) {} 229 @Override public void windowDeactivated(WindowEvent e) {} 230}