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

Last change on this file since 13607 was 13568, checked in by Don-vip, 6 years ago

use OsmDataLayer.getDataSet()

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