001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions; 003 004import static org.openstreetmap.josm.gui.help.HelpUtil.ht; 005import static org.openstreetmap.josm.tools.CheckParameterUtil.ensureParameterNotNull; 006import static org.openstreetmap.josm.tools.I18n.tr; 007 008import java.awt.event.ActionEvent; 009import java.awt.event.KeyEvent; 010import java.util.Collection; 011import java.util.Collections; 012import java.util.Optional; 013 014import javax.swing.JOptionPane; 015 016import org.openstreetmap.josm.data.osm.DataSet; 017import org.openstreetmap.josm.data.osm.DownloadPolicy; 018import org.openstreetmap.josm.data.osm.OsmPrimitive; 019import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 020import org.openstreetmap.josm.data.osm.PrimitiveId; 021import org.openstreetmap.josm.gui.ExceptionDialogUtil; 022import org.openstreetmap.josm.gui.MainApplication; 023import org.openstreetmap.josm.gui.io.UpdatePrimitivesTask; 024import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 025import org.openstreetmap.josm.io.MultiFetchServerObjectReader; 026import org.openstreetmap.josm.io.NetworkManager; 027import org.openstreetmap.josm.io.OnlineResource; 028import org.openstreetmap.josm.io.OsmTransferException; 029import org.openstreetmap.josm.tools.Shortcut; 030 031/** 032 * This action synchronizes a set of primitives with their state on the server. 033 * @since 1670 034 */ 035public class UpdateSelectionAction extends JosmAction { 036 037 /** 038 * handle an exception thrown because a primitive was deleted on the server 039 * 040 * @param id the primitive id 041 * @param type The primitive type. Must be one of {@link OsmPrimitiveType#NODE NODE}, 042 * {@link OsmPrimitiveType#WAY WAY}, {@link OsmPrimitiveType#RELATION RELATION} 043 */ 044 public static void handlePrimitiveGoneException(long id, OsmPrimitiveType type) { 045 MultiFetchServerObjectReader reader = MultiFetchServerObjectReader.create(); 046 reader.append(MainApplication.getLayerManager().getEditDataSet(), id, type); 047 try { 048 DataSet ds = reader.parseOsm(NullProgressMonitor.INSTANCE); 049 MainApplication.getLayerManager().getEditLayer().mergeFrom(ds); 050 } catch (OsmTransferException e) { 051 ExceptionDialogUtil.explainException(e); 052 } 053 } 054 055 /** 056 * Updates the data for for the {@link OsmPrimitive}s in <code>selection</code> 057 * with the data currently kept on the server. 058 * 059 * @param selection a collection of {@link OsmPrimitive}s to update 060 * 061 */ 062 public static void updatePrimitives(final Collection<OsmPrimitive> selection) { 063 MainApplication.worker.submit(new UpdatePrimitivesTask(MainApplication.getLayerManager().getEditLayer(), selection)); 064 } 065 066 /** 067 * Updates the data for the {@link OsmPrimitive}s with id <code>id</code> 068 * with the data currently kept on the server. 069 * 070 * @param id the id of a primitive in the {@link DataSet} of the current edit layer. Must not be null. 071 * @throws IllegalArgumentException if id is null 072 * @throws IllegalStateException if there is no primitive with <code>id</code> in the current dataset 073 * @throws IllegalStateException if there is no current dataset 074 */ 075 public static void updatePrimitive(PrimitiveId id) { 076 ensureParameterNotNull(id, "id"); 077 updatePrimitives(Collections.<OsmPrimitive>singleton(Optional.ofNullable(Optional.ofNullable( 078 MainApplication.getLayerManager().getEditLayer()).orElseThrow( 079 () -> new IllegalStateException(tr("No current dataset found"))) 080 .data.getPrimitiveById(id)).orElseThrow( 081 () -> new IllegalStateException(tr("Did not find an object with id {0} in the current dataset", id))))); 082 } 083 084 /** 085 * Constructs a new {@code UpdateSelectionAction}. 086 */ 087 public UpdateSelectionAction() { 088 super(tr("Update selection"), "updatedata", 089 tr("Updates the currently selected objects from the server (re-downloads data)"), 090 Shortcut.registerShortcut("file:updateselection", 091 tr("File: {0}", tr("Update selection")), KeyEvent.VK_U, 092 Shortcut.ALT_CTRL), 093 true, "updateselection", true); 094 setHelpId(ht("/Action/UpdateSelection")); 095 } 096 097 /** 098 * Constructs a new {@code UpdateSelectionAction}. 099 * 100 * @param name the action's text as displayed on the menu (if it is added to a menu) 101 * @param iconName the filename of the icon to use 102 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note 103 * that html is not supported for menu actions on some platforms. 104 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always 105 * do want a shortcut, remember you can always register it with group=none, so you 106 * won't be assigned a shortcut unless the user configures one. If you pass null here, 107 * the user CANNOT configure a shortcut for your action. 108 * @param register register this action for the toolbar preferences? 109 * @param toolbarId identifier for the toolbar preferences. The iconName is used, if this parameter is null 110 */ 111 public UpdateSelectionAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean register, String toolbarId) { 112 super(name, iconName, tooltip, shortcut, register, toolbarId, true); 113 } 114 115 @Override 116 protected void updateEnabledState() { 117 updateEnabledStateOnCurrentSelection(); 118 } 119 120 @Override 121 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) { 122 if (selection == null || selection.isEmpty()) { 123 setEnabled(false); 124 } else { 125 DataSet ds = selection.iterator().next().getDataSet(); 126 setEnabled(!ds.isLocked() && DownloadPolicy.BLOCKED != ds.getDownloadPolicy() 127 && !NetworkManager.isOffline(OnlineResource.OSM_API)); 128 } 129 } 130 131 @Override 132 public void actionPerformed(ActionEvent e) { 133 if (!isEnabled()) 134 return; 135 Collection<OsmPrimitive> toUpdate = getData(); 136 if (toUpdate.isEmpty()) { 137 JOptionPane.showMessageDialog( 138 MainApplication.getMainFrame(), 139 tr("There are no selected objects to update."), 140 tr("Selection empty"), 141 JOptionPane.INFORMATION_MESSAGE 142 ); 143 return; 144 } 145 updatePrimitives(toUpdate); 146 } 147 148 /** 149 * Returns the data on which this action operates. Override if needed. 150 * @return the data on which this action operates 151 */ 152 public Collection<OsmPrimitive> getData() { 153 return getLayerManager().getEditDataSet().getAllSelected(); 154 } 155}