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}