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.I18n.tr; 006 007import java.awt.event.ActionEvent; 008import java.awt.event.KeyEvent; 009import java.awt.geom.Area; 010import java.util.ArrayList; 011import java.util.List; 012import java.util.concurrent.Future; 013 014import org.openstreetmap.josm.Main; 015import org.openstreetmap.josm.actions.downloadtasks.DownloadTaskList; 016import org.openstreetmap.josm.data.DataSource; 017import org.openstreetmap.josm.gui.layer.OsmDataLayer; 018import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor; 019import org.openstreetmap.josm.io.OnlineResource; 020import org.openstreetmap.josm.tools.Shortcut; 021 022/** 023 * This action synchronizes the dataset with the current state on the server. 024 * 025 * It does so by re-downloading all areas and thereby merging all compatible 026 * changes from the current server version. 027 */ 028public class UpdateDataAction extends JosmAction { 029 030 /** 031 * Constructs a new {@code UpdateDataAction}. 032 */ 033 public UpdateDataAction() { 034 super(tr("Update data"), 035 "updatedata", 036 tr("Updates the objects in the active data layer from the server."), 037 Shortcut.registerShortcut("file:updatedata", 038 tr("File: {0}", tr("Update data")), 039 KeyEvent.VK_U, Shortcut.CTRL), 040 true); 041 putValue("help", ht("/Action/UpdateData")); 042 } 043 044 /** 045 * Refreshes the enabled state 046 */ 047 @Override 048 protected void updateEnabledState() { 049 OsmDataLayer editLayer = getLayerManager().getEditLayer(); 050 setEnabled(editLayer != null && editLayer.isDownloadable() && !Main.isOffline(OnlineResource.OSM_API)); 051 } 052 053 @Override 054 public void actionPerformed(ActionEvent e) { 055 OsmDataLayer editLayer = getLayerManager().getEditLayer(); 056 if (!isEnabled() || editLayer == null || !editLayer.isDownloadable()) 057 return; 058 059 List<Area> areas = new ArrayList<>(); 060 for (DataSource ds : editLayer.data.getDataSources()) { 061 areas.add(new Area(ds.bounds.asRect())); 062 } 063 064 // The next two blocks removes every intersection from every DataSource Area 065 // This prevents downloading the same data numerous times at intersections 066 // and also skips smaller bounding boxes that are contained within larger ones entirely. 067 for (int i = 0; i < areas.size(); i++) { 068 for (int j = i+1; j < areas.size(); j++) { 069 areas.get(i).subtract(areas.get(j)); 070 } 071 } 072 073 for (int i = areas.size()-1; i > 0; i--) { 074 for (int j = i-1; j > 0; j--) { 075 areas.get(i).subtract(areas.get(j)); 076 } 077 } 078 079 List<Area> areasToDownload = new ArrayList<>(); 080 for (Area a : areas) { 081 if (a.isEmpty()) { 082 continue; 083 } 084 areasToDownload.add(a); 085 } 086 087 if (areasToDownload.isEmpty()) { 088 // no bounds defined in the dataset? we update all primitives in the data set using a series of multi fetch requests 089 UpdateSelectionAction.updatePrimitives(editLayer.data.allPrimitives()); 090 } else { 091 // bounds defined? => use the bbox downloader 092 final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(tr("Download data")); 093 final Future<?> future = new DownloadTaskList().download(false /* no new layer */, areasToDownload, true, false, monitor); 094 waitFuture(future, monitor); 095 } 096 } 097}