source: josm/trunk/src/org/openstreetmap/josm/actions/DownloadPrimitiveAction.java@ 5299

Last change on this file since 5299 was 5211, checked in by simon04, 12 years ago

fix #7666 - Download object exception with invalid value

  • Property svn:eol-style set to native
File size: 13.5 KB
Line 
1// License: GPL. See LICENSE file for details.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trc;
7import static org.openstreetmap.josm.tools.I18n.trn;
8
9import java.awt.Font;
10import java.awt.GridBagLayout;
11import java.awt.event.ActionEvent;
12import java.awt.event.ItemEvent;
13import java.awt.event.ItemListener;
14import java.awt.event.KeyEvent;
15import java.lang.reflect.InvocationTargetException;
16import java.util.Collections;
17import java.util.LinkedList;
18import java.util.List;
19import java.util.Set;
20import java.util.TreeSet;
21import javax.swing.BorderFactory;
22import javax.swing.GroupLayout;
23
24import javax.swing.JCheckBox;
25import javax.swing.JLabel;
26import javax.swing.JOptionPane;
27import javax.swing.JPanel;
28import javax.swing.JScrollPane;
29import javax.swing.JTextArea;
30import javax.swing.JTextField;
31import javax.swing.KeyStroke;
32import javax.swing.SwingUtilities;
33import javax.swing.border.EtchedBorder;
34import javax.swing.plaf.basic.BasicComboBoxEditor;
35
36import org.openstreetmap.josm.Main;
37import org.openstreetmap.josm.actions.downloadtasks.DownloadReferrersTask;
38import org.openstreetmap.josm.data.osm.DataSet;
39import org.openstreetmap.josm.data.osm.OsmPrimitive;
40import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
41import org.openstreetmap.josm.data.osm.PrimitiveId;
42import org.openstreetmap.josm.gui.ExtendedDialog;
43import org.openstreetmap.josm.gui.io.DownloadPrimitivesTask;
44import org.openstreetmap.josm.gui.layer.OsmDataLayer;
45import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
46import org.openstreetmap.josm.gui.widgets.HtmlPanel;
47import org.openstreetmap.josm.gui.widgets.OsmIdTextField;
48import org.openstreetmap.josm.gui.widgets.OsmPrimitiveTypesComboBox;
49import org.openstreetmap.josm.tools.GBC;
50import org.openstreetmap.josm.tools.Shortcut;
51import org.openstreetmap.josm.tools.Utils;
52
53/**
54 * Download an OsmPrimitive by specifying type and ID
55 *
56 * @author Matthias Julius
57 */
58public class DownloadPrimitiveAction extends JosmAction {
59
60 public DownloadPrimitiveAction() {
61 super(tr("Download object..."), "downloadprimitive", tr("Download OSM object by ID."),
62 Shortcut.registerShortcut("system:download_primitive", tr("File: {0}", tr("Download object...")), KeyEvent.VK_O, Shortcut.CTRL_SHIFT), true);
63 putValue("help", ht("/Action/DownloadObject"));
64 }
65
66 /**
67 * Restore the current history from the preferences
68 *
69 * @param cbHistory
70 */
71 protected void restorePrimitivesHistory(HistoryComboBox cbHistory) {
72 List<String> cmtHistory = new LinkedList<String>(Main.pref.getCollection(getClass().getName() + ".primitivesHistory", new LinkedList<String>()));
73 // we have to reverse the history, because ComboBoxHistory will reverse it again
74 // in addElement()
75 //
76 Collections.reverse(cmtHistory);
77 cbHistory.setPossibleItems(cmtHistory);
78 }
79
80 /**
81 * Remind the current history in the preferences
82 * @param cbHistory
83 */
84 protected void remindPrimitivesHistory(HistoryComboBox cbHistory) {
85 cbHistory.addCurrentItemToHistory();
86 Main.pref.putCollection(getClass().getName() + ".primitivesHistory", cbHistory.getHistory());
87 }
88
89 public void actionPerformed(ActionEvent e) {
90
91 JPanel all = new JPanel();
92 GroupLayout layout = new GroupLayout(all);
93 all.setLayout(layout);
94 layout.setAutoCreateGaps(true);
95 layout.setAutoCreateContainerGaps(true);
96
97 JLabel lbl1 = new JLabel(tr("Object type:"));
98 final OsmPrimitiveTypesComboBox cbType = new OsmPrimitiveTypesComboBox();
99 cbType.addItem(trc("osm object types", "mixed"));
100 cbType.setToolTipText(tr("Choose the OSM object type"));
101 JLabel lbl2 = new JLabel(tr("Object ID:"));
102 final OsmIdTextField tfId = new OsmIdTextField();
103 HistoryComboBox cbId = new HistoryComboBox();
104 cbId.setEditor(new BasicComboBoxEditor() {
105 @Override
106 protected JTextField createEditorComponent() {
107 return tfId;
108 }
109 });
110 cbId.setToolTipText(tr("Enter the ID of the object that should be downloaded"));
111 restorePrimitivesHistory(cbId);
112 // forward the enter key stroke to the download button
113 tfId.getKeymap().removeKeyStrokeBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false));
114 JCheckBox layer = new JCheckBox(tr("Separate Layer"));
115 layer.setToolTipText(tr("Select if the data should be downloaded into a new layer"));
116 layer.setSelected(Main.pref.getBoolean("download.newlayer"));
117 final JCheckBox referrers = new JCheckBox(tr("Download referrers (parent relations)"));
118 referrers.setToolTipText(tr("Select if the referrers of the object should be downloaded as well, i.e.,"
119 + "parent relations and for nodes, additionally, parent ways"));
120 referrers.setSelected(Main.pref.getBoolean("downloadprimitive.referrers", true));
121 JCheckBox full = new JCheckBox(tr("Download relation members"));
122 full.setToolTipText(tr("Select if the members of a relation should be downloaded as well"));
123 full.setSelected(Main.pref.getBoolean("downloadprimitive.full", true));
124 HtmlPanel help = new HtmlPanel(tr("Object IDs can be separated by comma or space.<br/>"
125 + " Examples: <b><ul><li>1 2 5</li><li>1,2,5</li></ul><br/></b>"
126 + " In mixed mode, specify objects like this: <b>w123, n110, w12, r15</b><br/>"));
127 help.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
128
129 layout.setVerticalGroup(layout.createSequentialGroup()
130 .addGroup(layout.createParallelGroup()
131 .addComponent(lbl1)
132 .addComponent(cbType, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
133 .addGroup(layout.createParallelGroup()
134 .addComponent(lbl2)
135 .addComponent(cbId, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
136 .addComponent(referrers)
137 .addComponent(full)
138 .addComponent(layer)
139 .addComponent(help)
140 );
141
142 cbType.addItemListener(new ItemListener() {
143
144 @Override
145 public void itemStateChanged(ItemEvent e) {
146 tfId.setType(cbType.getType());
147 tfId.performValidation();
148 referrers.setText(cbType.getType() == OsmPrimitiveType.NODE
149 ? tr("Download referrers (parent relations and ways)")
150 : tr("Download referrers (parent relations)"));
151 }
152 });
153
154 layout.setHorizontalGroup(layout.createParallelGroup()
155 .addGroup(layout.createSequentialGroup()
156 .addGroup(layout.createParallelGroup()
157 .addComponent(lbl1)
158 .addComponent(lbl2)
159 )
160 .addGroup(layout.createParallelGroup()
161 .addComponent(cbType)
162 .addComponent(cbId))
163 )
164 .addComponent(referrers)
165 .addComponent(full)
166 .addComponent(layer)
167 .addComponent(help)
168 );
169
170 ExtendedDialog dialog = new ExtendedDialog(Main.parent,
171 tr("Download object"),
172 new String[] {tr("Download object"), tr("Cancel")}
173 );
174 dialog.setContent(all, false);
175 dialog.setButtonIcons(new String[] {"download.png", "cancel.png"});
176 dialog.setToolTipTexts(new String[] {
177 tr("Start downloading"),
178 tr("Close dialog and cancel downloading")
179 });
180 dialog.setDefaultButton(1);
181 dialog.configureContextsensitiveHelp("/Action/DownloadObject", true /* show help button */);
182 cbType.setSelectedIndex(Main.pref.getInteger("downloadprimitive.lasttype", 0));
183 dialog.showDialog();
184 if (dialog.getValue() != 1) return;
185 Main.pref.putInteger("downloadprimitive.lasttype", cbType.getSelectedIndex());
186 Main.pref.put("downloadprimitive.referrers", referrers.isSelected());
187 Main.pref.put("downloadprimitive.full", full.isSelected());
188 Main.pref.put("download.newlayer", layer.isSelected());
189
190 tfId.setType(cbType.getType());
191 if(!tfId.readOsmIds()) {
192 JOptionPane.showMessageDialog(
193 Main.parent,
194 tr("Invalid ID list specified\n"
195 + "Cannot download object."),
196 tr("Information"),
197 JOptionPane.INFORMATION_MESSAGE
198 );
199 return;
200 }
201 remindPrimitivesHistory(cbId);
202 processItems(layer.isSelected(), tfId.getIds(), referrers.isSelected(), full.isSelected());
203 }
204
205 /**
206 * @param newLayer if the data should be downloaded into a new layer
207 * @param ids
208 * @param downloadReferrers if the referrers of the object should be downloaded as well, i.e., parent relations, and for nodes, additionally, parent ways
209 * @param full if the members of a relation should be downloaded as well
210 */
211 public static void processItems(boolean newLayer, final List<PrimitiveId> ids, boolean downloadReferrers, boolean full) {
212 OsmDataLayer layer = getEditLayer();
213 if ((layer == null) || newLayer) {
214 layer = new OsmDataLayer(new DataSet(), OsmDataLayer.createNewName(), null);
215 Main.main.addLayer(layer);
216 }
217 final DownloadPrimitivesTask task = new DownloadPrimitivesTask(layer, ids, full);
218 Main.worker.submit(task);
219
220 if (downloadReferrers) {
221 for (PrimitiveId id : ids) {
222 Main.worker.submit(new DownloadReferrersTask(layer, id));
223 }
224 }
225
226 Runnable showErrorsAndWarnings = new Runnable() {
227 @Override
228 public void run() {
229 Set<PrimitiveId> errs = task.getMissingPrimitives();
230 if (errs != null && !errs.isEmpty()) {
231 final ExtendedDialog dlg = reportProblemDialog(errs,
232 trn("Object could not be downloaded", "Some objects could not be downloaded", errs.size()),
233 trn("One object could not be downloaded.<br>",
234 "{0} objects could not be downloaded.<br>",
235 errs.size(),
236 errs.size())
237 + tr("The server replied with response code 404.<br>"
238 + "This usually means, the server does not know an object with the requested id."),
239 tr("missing objects:"),
240 JOptionPane.ERROR_MESSAGE
241 );
242 try {
243 SwingUtilities.invokeAndWait(new Runnable() {
244 @Override
245 public void run() {
246 dlg.showDialog();
247 }
248 });
249 } catch (InterruptedException ex) {
250 } catch (InvocationTargetException ex) {
251 }
252 }
253
254 Set<PrimitiveId> del = new TreeSet<PrimitiveId>();
255 DataSet ds = getCurrentDataSet();
256 for (PrimitiveId id : ids) {
257 OsmPrimitive osm = ds.getPrimitiveById(id);
258 if (osm != null && osm.isDeleted()) {
259 del.add(id);
260 }
261 }
262 if (!del.isEmpty()) {
263 final ExtendedDialog dlg = reportProblemDialog(del,
264 trn("Object deleted", "Objects deleted", del.size()),
265 trn(
266 "One downloaded object is deleted.",
267 "{0} downloaded objects are deleted.",
268 del.size(),
269 del.size()),
270 null,
271 JOptionPane.WARNING_MESSAGE
272 );
273 SwingUtilities.invokeLater(new Runnable() {
274 @Override
275 public void run() {
276 dlg.showDialog();
277 }
278 });
279 }
280 }
281 };
282 Main.worker.submit(showErrorsAndWarnings);
283 }
284
285 private static ExtendedDialog reportProblemDialog(Set<PrimitiveId> errs,
286 String TITLE, String TEXT, String LIST_LABEL, int msgType) {
287 JPanel p = new JPanel(new GridBagLayout());
288 p.add(new HtmlPanel(TEXT), GBC.eop());
289 if (LIST_LABEL != null) {
290 JLabel missing = new JLabel(LIST_LABEL);
291 missing.setFont(missing.getFont().deriveFont(Font.PLAIN));
292 p.add(missing, GBC.eol());
293 }
294 JTextArea txt = new JTextArea();
295 txt.setFont(new Font("Monospaced", txt.getFont().getStyle(), txt.getFont().getSize()));
296 txt.setEditable(false);
297 txt.setBackground(p.getBackground());
298 txt.setColumns(40);
299 txt.setRows(1);
300 txt.setText(Utils.join(", ", errs));
301 JScrollPane scroll = new JScrollPane(txt);
302 p.add(scroll, GBC.eop().weight(1.0, 0.0).fill(GBC.HORIZONTAL));
303
304 return new ExtendedDialog(
305 Main.parent,
306 TITLE,
307 new String[] { tr("Ok") })
308 .setButtonIcons(new String[] { "ok" })
309 .setIcon(msgType)
310 .setContent(p, false);
311 }
312}
Note: See TracBrowser for help on using the repository browser.