001// License: GPL. See LICENSE file for details.
002package org.openstreetmap.josm.actions;
003
004import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005import static org.openstreetmap.josm.tools.I18n.tr;
006import static org.openstreetmap.josm.tools.I18n.trn;
007
008import java.awt.Font;
009import java.awt.GridBagLayout;
010import java.awt.event.ActionEvent;
011import java.awt.event.KeyEvent;
012import java.lang.reflect.InvocationTargetException;
013import java.util.List;
014import java.util.Set;
015import java.util.TreeSet;
016
017import javax.swing.JLabel;
018import javax.swing.JOptionPane;
019import javax.swing.JPanel;
020import javax.swing.JScrollPane;
021import javax.swing.SwingUtilities;
022
023import org.openstreetmap.josm.Main;
024import org.openstreetmap.josm.actions.downloadtasks.DownloadReferrersTask;
025import org.openstreetmap.josm.data.osm.DataSet;
026import org.openstreetmap.josm.data.osm.OsmPrimitive;
027import org.openstreetmap.josm.data.osm.PrimitiveId;
028import org.openstreetmap.josm.gui.ExtendedDialog;
029import org.openstreetmap.josm.gui.download.DownloadObjectDialog;
030import org.openstreetmap.josm.gui.io.DownloadPrimitivesTask;
031import org.openstreetmap.josm.gui.layer.OsmDataLayer;
032import org.openstreetmap.josm.gui.widgets.HtmlPanel;
033import org.openstreetmap.josm.gui.widgets.JosmTextArea;
034import org.openstreetmap.josm.tools.GBC;
035import org.openstreetmap.josm.tools.Shortcut;
036import org.openstreetmap.josm.tools.Utils;
037
038/**
039 * Download an OsmPrimitive by specifying type and ID
040 *
041 * @author Matthias Julius
042 */
043public class DownloadPrimitiveAction extends JosmAction {
044
045    /**
046     * Constructs a new {@code DownloadPrimitiveAction}.
047     */
048    public DownloadPrimitiveAction() {
049        super(tr("Download object..."), "downloadprimitive", tr("Download OSM object by ID."),
050                Shortcut.registerShortcut("system:download_primitive", tr("File: {0}", tr("Download object...")), KeyEvent.VK_O, Shortcut.CTRL_SHIFT), true);
051        putValue("help", ht("/Action/DownloadObject"));
052    }
053
054    @Override
055    public void actionPerformed(ActionEvent e) {
056
057        DownloadObjectDialog dialog = new DownloadObjectDialog();
058        if (dialog.showDialog().getValue() != dialog.getContinueButtonIndex()) return;
059
060        processItems(dialog.isNewLayerRequested(), dialog.getOsmIds(), dialog.isReferrersRequested(), dialog.isFullRelationRequested());
061    }
062
063    /**
064     * @param newLayer if the data should be downloaded into a new layer
065     * @param ids
066     * @param downloadReferrers if the referrers of the object should be downloaded as well, i.e., parent relations, and for nodes, additionally, parent ways
067     * @param full if the members of a relation should be downloaded as well
068     */
069    public static void processItems(boolean newLayer, final List<PrimitiveId> ids, boolean downloadReferrers, boolean full) {
070        OsmDataLayer layer = getEditLayer();
071        if ((layer == null) || newLayer) {
072            layer = new OsmDataLayer(new DataSet(), OsmDataLayer.createNewName(), null);
073            Main.main.addLayer(layer);
074        }
075        final DownloadPrimitivesTask task = new DownloadPrimitivesTask(layer, ids, full);
076        Main.worker.submit(task);
077
078        if (downloadReferrers) {
079            for (PrimitiveId id : ids) {
080                Main.worker.submit(new DownloadReferrersTask(layer, id));
081            }
082        }
083
084        Runnable showErrorsAndWarnings = new Runnable() {
085            @Override
086            public void run() {
087                final Set<PrimitiveId> errs = task.getMissingPrimitives();
088                if (errs != null && !errs.isEmpty()) {
089                    try {
090                        SwingUtilities.invokeAndWait(new Runnable() {
091                            @Override
092                            public void run() {
093                                reportProblemDialog(errs,
094                                        trn("Object could not be downloaded", "Some objects could not be downloaded", errs.size()),
095                                        trn("One object could not be downloaded.<br>",
096                                            "{0} objects could not be downloaded.<br>",
097                                            errs.size(),
098                                            errs.size())
099                                        + tr("The server replied with response code 404.<br>"
100                                            + "This usually means, the server does not know an object with the requested id."),
101                                        tr("missing objects:"),
102                                        JOptionPane.ERROR_MESSAGE
103                                ).showDialog();
104                            }
105                        });
106                    } catch (InterruptedException ex) {
107                        Main.warn("InterruptedException while displaying error dialog");
108                    } catch (InvocationTargetException ex) {
109                        Main.warn(ex);
110                    }
111                }
112
113                final Set<PrimitiveId> del = new TreeSet<PrimitiveId>();
114                DataSet ds = getCurrentDataSet();
115                for (PrimitiveId id : ids) {
116                    OsmPrimitive osm = ds.getPrimitiveById(id);
117                    if (osm != null && osm.isDeleted()) {
118                        del.add(id);
119                    }
120                }
121                if (!del.isEmpty()) {
122                    SwingUtilities.invokeLater(new Runnable() {
123                        @Override
124                        public void run() {
125                            reportProblemDialog(del,
126                                    trn("Object deleted", "Objects deleted", del.size()),
127                                    trn(
128                                        "One downloaded object is deleted.",
129                                        "{0} downloaded objects are deleted.",
130                                        del.size(),
131                                        del.size()),
132                                    null,
133                                    JOptionPane.WARNING_MESSAGE
134                            ).showDialog();
135                        }
136                    });
137                }
138            }
139        };
140        Main.worker.submit(showErrorsAndWarnings);
141    }
142
143    private static ExtendedDialog reportProblemDialog(Set<PrimitiveId> errs,
144            String TITLE, String TEXT, String LIST_LABEL, int msgType) {
145        JPanel p = new JPanel(new GridBagLayout());
146        p.add(new HtmlPanel(TEXT), GBC.eop());
147        if (LIST_LABEL != null) {
148            JLabel missing = new JLabel(LIST_LABEL);
149            missing.setFont(missing.getFont().deriveFont(Font.PLAIN));
150            p.add(missing, GBC.eol());
151        }
152        JosmTextArea txt = new JosmTextArea();
153        txt.setFont(new Font("Monospaced", txt.getFont().getStyle(), txt.getFont().getSize()));
154        txt.setEditable(false);
155        txt.setBackground(p.getBackground());
156        txt.setColumns(40);
157        txt.setRows(1);
158        txt.setText(Utils.join(", ", errs));
159        JScrollPane scroll = new JScrollPane(txt);
160        p.add(scroll, GBC.eop().weight(1.0, 0.0).fill(GBC.HORIZONTAL));
161
162        return new ExtendedDialog(
163                Main.parent,
164                TITLE,
165                new String[] { tr("Ok") })
166            .setButtonIcons(new String[] { "ok" })
167            .setIcon(msgType)
168            .setContent(p, false);
169    }
170}