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