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

Revision 5211, 13.5 KB checked in by simon04, 3 weeks ago (diff)

fix #7666 - Download object exception with invalid value

  • Property svn:eol-style set to native
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.