source: josm/trunk/src/org/openstreetmap/josm/actions/UploadAction.java@ 11848

Last change on this file since 11848 was 11848, checked in by Don-vip, 7 years ago

fix #14613 - Special HTML characters not escaped in GUI error messages

  • Property svn:eol-style set to native
File size: 10.0 KB
RevLine 
[6380]1// License: GPL. For details, see LICENSE file.
[230]2package org.openstreetmap.josm.actions;
3
[2390]4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
[230]5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.event.ActionEvent;
8import java.awt.event.KeyEvent;
9import java.util.LinkedList;
[6316]10import java.util.List;
[230]11
12import javax.swing.JOptionPane;
13
14import org.openstreetmap.josm.Main;
[2168]15import org.openstreetmap.josm.actions.upload.ApiPreconditionCheckerHook;
[5497]16import org.openstreetmap.josm.actions.upload.DiscardTagsHook;
[5621]17import org.openstreetmap.josm.actions.upload.FixDataHook;
[2168]18import org.openstreetmap.josm.actions.upload.RelationUploadOrderHook;
19import org.openstreetmap.josm.actions.upload.UploadHook;
[3669]20import org.openstreetmap.josm.actions.upload.ValidateUploadHook;
[2025]21import org.openstreetmap.josm.data.APIDataSet;
[1750]22import org.openstreetmap.josm.data.conflict.ConflictCollection;
[2979]23import org.openstreetmap.josm.gui.HelpAwareOptionPane;
[2081]24import org.openstreetmap.josm.gui.io.UploadDialog;
[2598]25import org.openstreetmap.josm.gui.io.UploadPrimitivesTask;
[7402]26import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
[2025]27import org.openstreetmap.josm.gui.layer.OsmDataLayer;
[5233]28import org.openstreetmap.josm.gui.util.GuiHelper;
[5025]29import org.openstreetmap.josm.tools.ImageProvider;
[1575]30import org.openstreetmap.josm.tools.Shortcut;
[11848]31import org.openstreetmap.josm.tools.Utils;
[230]32
33/**
[655]34 * Action that opens a connection to the osm server and uploads all changes.
[230]35 *
36 * An dialog is displayed asking the user to specify a rectangle to grab.
37 * The url and account settings from the preferences are used.
[1677]38 *
[1670]39 * If the upload fails this action offers various options to resolve conflicts.
[230]40 *
41 * @author imi
42 */
[9059]43public class UploadAction extends JosmAction {
[1169]44 /**
45 * The list of upload hooks. These hooks will be called one after the other
46 * when the user wants to upload data. Plugins can insert their own hooks here
47 * if they want to be able to veto an upload.
48 *
49 * Be default, the standard upload dialog is the only element in the list.
50 * Plugins should normally insert their code before that, so that the upload
51 * dialog is the last thing shown before upload really starts; on occasion
52 * however, a plugin might also want to insert something after that.
53 */
[7005]54 private static final List<UploadHook> uploadHooks = new LinkedList<>();
55 private static final List<UploadHook> lateUploadHooks = new LinkedList<>();
[8510]56
[2081]57 static {
[5621]58 /**
59 * Calls validator before upload.
60 */
[3669]61 uploadHooks.add(new ValidateUploadHook());
[5621]62
[1169]63 /**
[5621]64 * Fixes database errors
65 */
66 uploadHooks.add(new FixDataHook());
67
68 /**
[1691]69 * Checks server capabilities before upload.
70 */
[2168]71 uploadHooks.add(new ApiPreconditionCheckerHook());
[1691]72
73 /**
[2168]74 * Adjusts the upload order of new relations
75 */
76 uploadHooks.add(new RelationUploadOrderHook());
[5497]77
78 /**
79 * Removes discardable tags like created_by on modified objects
80 */
81 lateUploadHooks.add(new DiscardTagsHook());
[1169]82 }
[230]83
[1808]84 /**
[2083]85 * Registers an upload hook. Adds the hook at the first position of the upload hooks.
[2512]86 *
[2081]87 * @param hook the upload hook. Ignored if null.
88 */
89 public static void registerUploadHook(UploadHook hook) {
[5497]90 registerUploadHook(hook, false);
91 }
92
93 /**
94 * Registers an upload hook. Adds the hook at the first position of the upload hooks.
95 *
96 * @param hook the upload hook. Ignored if null.
97 * @param late true, if the hook should be executed after the upload dialog
98 * has been confirmed. Late upload hooks should in general succeed and not
99 * abort the upload.
100 */
101 public static void registerUploadHook(UploadHook hook, boolean late) {
[8510]102 if (hook == null) return;
[5497]103 if (late) {
104 if (!lateUploadHooks.contains(hook)) {
105 lateUploadHooks.add(0, hook);
106 }
107 } else {
108 if (!uploadHooks.contains(hook)) {
109 uploadHooks.add(0, hook);
110 }
[2081]111 }
112 }
113
114 /**
115 * Unregisters an upload hook. Removes the hook from the list of upload hooks.
[2512]116 *
[2081]117 * @param hook the upload hook. Ignored if null.
118 */
119 public static void unregisterUploadHook(UploadHook hook) {
[8510]120 if (hook == null) return;
[2081]121 if (uploadHooks.contains(hook)) {
122 uploadHooks.remove(hook);
123 }
[5497]124 if (lateUploadHooks.contains(hook)) {
125 lateUploadHooks.remove(hook);
126 }
[2081]127 }
128
[10382]129 /**
130 * Constructs a new {@code UploadAction}.
131 */
[2081]132 public UploadAction() {
[2317]133 super(tr("Upload data"), "upload", tr("Upload all changes in the active data layer to the OSM server"),
[4982]134 Shortcut.registerShortcut("file:upload", tr("File: {0}", tr("Upload data")), KeyEvent.VK_UP, Shortcut.CTRL_SHIFT), true);
[2323]135 putValue("help", ht("/Action/Upload"));
[2081]136 }
137
138 /**
[1808]139 * Refreshes the enabled state
[1811]140 *
[1808]141 */
[1820]142 @Override
143 protected void updateEnabledState() {
[11709]144 OsmDataLayer editLayer = getLayerManager().getEditLayer();
145 setEnabled(editLayer != null && editLayer.isUploadable());
[1808]146 }
147
[7402]148 public static boolean checkPreUploadConditions(AbstractModifiableLayer layer) {
[7358]149 return checkPreUploadConditions(layer,
[8510]150 layer instanceof OsmDataLayer ? new APIDataSet(((OsmDataLayer) layer).data) : null);
[2025]151 }
152
[5025]153 protected static void alertUnresolvedConflicts(OsmDataLayer layer) {
[2979]154 HelpAwareOptionPane.showOptionDialog(
155 Main.parent,
156 tr("<html>The data to be uploaded participates in unresolved conflicts of layer ''{0}''.<br>"
[11848]157 + "You have to resolve them first.</html>", Utils.escapeReservedCharactersHTML(layer.getName())
[2979]158 ),
159 tr("Warning"),
160 JOptionPane.WARNING_MESSAGE,
[9972]161 ht("/Action/Upload#PrimitivesParticipateInConflicts")
[2979]162 );
163 }
[6069]164
[5025]165 /**
[8931]166 * Warn user about discouraged upload, propose to cancel operation.
167 * @param layer incriminated layer
168 * @return true if the user wants to cancel, false if they want to continue
[5025]169 */
[7402]170 public static boolean warnUploadDiscouraged(AbstractModifiableLayer layer) {
[5233]171 return GuiHelper.warnUser(tr("Upload discouraged"),
172 "<html>" +
[5025]173 tr("You are about to upload data from the layer ''{0}''.<br /><br />"+
[5233]174 "Sending data from this layer is <b>strongly discouraged</b>. If you continue,<br />"+
175 "it may require you subsequently have to revert your changes, or force other contributors to.<br /><br />"+
[11848]176 "Are you sure you want to continue?", Utils.escapeReservedCharactersHTML(layer.getName()))+
[5233]177 "</html>",
178 ImageProvider.get("upload"), tr("Ignore this hint and upload anyway"));
[5025]179 }
[2979]180
181 /**
182 * Check whether the preconditions are met to upload data in <code>apiData</code>.
[5025]183 * Makes sure upload is allowed, primitives in <code>apiData</code> don't participate in conflicts and
[5266]184 * runs the installed {@link UploadHook}s.
[3530]185 *
[2979]186 * @param layer the source layer of the data to be uploaded
187 * @param apiData the data to be uploaded
188 * @return true, if the preconditions are met; false, otherwise
189 */
[7402]190 public static boolean checkPreUploadConditions(AbstractModifiableLayer layer, APIDataSet apiData) {
[11385]191 if (layer.isUploadDiscouraged() && warnUploadDiscouraged(layer)) {
192 return false;
[5025]193 }
[7358]194 if (layer instanceof OsmDataLayer) {
195 OsmDataLayer osmLayer = (OsmDataLayer) layer;
196 ConflictCollection conflicts = osmLayer.getConflicts();
197 if (apiData.participatesInConflict(conflicts)) {
198 alertUnresolvedConflicts(osmLayer);
199 return false;
200 }
[2025]201 }
[2979]202 // Call all upload hooks in sequence.
203 // FIXME: this should become an asynchronous task
204 //
[7358]205 if (apiData != null) {
206 for (UploadHook hook : uploadHooks) {
207 if (!hook.checkUpload(apiData))
208 return false;
209 }
[3671]210 }
[2025]211
212 return true;
213 }
214
[2979]215 /**
216 * Uploads data to the OSM API.
[3530]217 *
[2979]218 * @param layer the source layer for the data to upload
219 * @param apiData the primitives to be added, updated, or deleted
220 */
[4414]221 public void uploadData(final OsmDataLayer layer, APIDataSet apiData) {
[2025]222 if (apiData.isEmpty()) {
[2005]223 JOptionPane.showMessageDialog(
[1857]224 Main.parent,
[2025]225 tr("No changes to upload."),
[1857]226 tr("Warning"),
[2025]227 JOptionPane.INFORMATION_MESSAGE
[1857]228 );
[1169]229 return;
230 }
[2250]231 if (!checkPreUploadConditions(layer, apiData))
[1169]232 return;
[2598]233
234 final UploadDialog dialog = UploadDialog.getUploadDialog();
[9514]235 dialog.setChangesetTags(layer.data);
[2598]236 dialog.setUploadedPrimitives(apiData);
237 dialog.setVisible(true);
[9462]238 dialog.rememberUserInput();
[2598]239 if (dialog.isCanceled())
240 return;
241
[5497]242 for (UploadHook hook : lateUploadHooks) {
243 if (!hook.checkUpload(apiData))
244 return;
245 }
246
[2040]247 Main.worker.execute(
[2569]248 new UploadPrimitivesTask(
249 UploadDialog.getUploadDialog().getUploadStrategySpecification(),
[2250]250 layer,
[2598]251 apiData,
252 UploadDialog.getUploadDialog().getChangeset()
[2040]253 )
254 );
[1663]255 }
256
[6084]257 @Override
[2250]258 public void actionPerformed(ActionEvent e) {
259 if (!isEnabled())
260 return;
261 if (Main.map == null) {
262 JOptionPane.showMessageDialog(
263 Main.parent,
264 tr("Nothing to upload. Get some data first."),
265 tr("Warning"),
266 JOptionPane.WARNING_MESSAGE
267 );
268 return;
269 }
[10446]270 APIDataSet apiData = new APIDataSet(Main.getLayerManager().getEditDataSet());
[10413]271 uploadData(Main.getLayerManager().getEditLayer(), apiData);
[2250]272 }
[230]273}
Note: See TracBrowser for help on using the repository browser.