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.List; 011import java.util.concurrent.Future; 012import java.util.stream.Collectors; 013 014import org.openstreetmap.josm.actions.downloadtasks.DownloadTaskList; 015import org.openstreetmap.josm.gui.layer.OsmDataLayer; 016import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor; 017import org.openstreetmap.josm.io.NetworkManager; 018import org.openstreetmap.josm.io.OnlineResource; 019import org.openstreetmap.josm.spi.preferences.Config; 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 setHelpId(ht("/Action/UpdateData")); 042 } 043 044 @Override 045 protected boolean listenToSelectionChange() { 046 return false; 047 } 048 049 /** 050 * Refreshes the enabled state 051 */ 052 @Override 053 protected void updateEnabledState() { 054 OsmDataLayer editLayer = getLayerManager().getEditLayer(); 055 setEnabled(editLayer != null && editLayer.isDownloadable() && !NetworkManager.isOffline(OnlineResource.OSM_API)); 056 } 057 058 @Override 059 public void actionPerformed(ActionEvent e) { 060 OsmDataLayer editLayer = getLayerManager().getEditLayer(); 061 if (!isEnabled() || editLayer == null || !editLayer.isDownloadable()) 062 return; 063 064 List<Area> areas = editLayer.data.getDataSources().stream() 065 .map(ds -> new Area(ds.bounds.asRect())) 066 .collect(Collectors.toList()); 067 068 // The next two blocks removes every intersection from every DataSource Area 069 // This prevents downloading the same data numerous times at intersections 070 // and also skips smaller bounding boxes that are contained within larger ones entirely. 071 for (int i = 0; i < areas.size(); i++) { 072 for (int j = i+1; j < areas.size(); j++) { 073 areas.get(i).subtract(areas.get(j)); 074 } 075 } 076 077 for (int i = areas.size()-1; i > 0; i--) { 078 for (int j = i-1; j > 0; j--) { 079 areas.get(i).subtract(areas.get(j)); 080 } 081 } 082 083 List<Area> areasToDownload = areas.stream() 084 .filter(a -> !a.isEmpty()) 085 .collect(Collectors.toList()); 086 087 if (areasToDownload.isEmpty()) { 088 // no bounds defined in the dataset? We update all but the incomplete primitives in the data set 089 UpdateSelectionAction.updatePrimitives(editLayer.data.allPrimitives().stream() 090 .filter(p -> !p.isNew() && !p.isIncomplete()).collect(Collectors.toList())); 091 } else { 092 // bounds defined? => use the bbox downloader 093 final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(tr("Download data")); 094 final Future<?> future = new DownloadTaskList(Config.getPref().getBoolean("update.data.zoom-after-download")) 095 .download(false /* no new layer */, areasToDownload, true, false, monitor); 096 waitFuture(future, monitor); 097 } 098 } 099}