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.io.File; 009import java.io.IOException; 010import java.io.InputStream; 011import java.net.URI; 012import java.nio.file.Files; 013import java.nio.file.StandardCopyOption; 014import java.util.Arrays; 015import java.util.List; 016 017import javax.swing.JFileChooser; 018import javax.swing.JOptionPane; 019import javax.swing.SwingUtilities; 020 021import org.openstreetmap.josm.Main; 022import org.openstreetmap.josm.data.ViewportData; 023import org.openstreetmap.josm.gui.HelpAwareOptionPane; 024import org.openstreetmap.josm.gui.PleaseWaitRunnable; 025import org.openstreetmap.josm.gui.layer.Layer; 026import org.openstreetmap.josm.gui.progress.ProgressMonitor; 027import org.openstreetmap.josm.gui.util.FileFilterAllFiles; 028import org.openstreetmap.josm.gui.widgets.AbstractFileChooser; 029import org.openstreetmap.josm.io.IllegalDataException; 030import org.openstreetmap.josm.io.session.SessionImporter; 031import org.openstreetmap.josm.io.session.SessionReader; 032import org.openstreetmap.josm.tools.CheckParameterUtil; 033import org.openstreetmap.josm.tools.Utils; 034 035/** 036 * Loads a JOSM session. 037 * @since 4668 038 */ 039public class SessionLoadAction extends DiskAccessAction { 040 041 /** 042 * Constructs a new {@code SessionLoadAction}. 043 */ 044 public SessionLoadAction() { 045 super(tr("Load Session"), "open", tr("Load a session from file."), null, true, "load-session", true); 046 putValue("help", ht("/Action/SessionLoad")); 047 } 048 049 @Override 050 public void actionPerformed(ActionEvent e) { 051 AbstractFileChooser fc = createAndOpenFileChooser(true, false, tr("Open session"), 052 Arrays.asList(SessionImporter.FILE_FILTER, FileFilterAllFiles.getInstance()), 053 SessionImporter.FILE_FILTER, JFileChooser.FILES_ONLY, "lastDirectory"); 054 if (fc == null) 055 return; 056 File file = fc.getSelectedFile(); 057 boolean zip = Utils.hasExtension(file, "joz"); 058 Main.worker.submit(new Loader(file, zip)); 059 } 060 061 /** 062 * JOSM session loader 063 */ 064 public static class Loader extends PleaseWaitRunnable { 065 066 private boolean canceled; 067 private File file; 068 private final URI uri; 069 private final InputStream is; 070 private final boolean zip; 071 private List<Layer> layers; 072 private Layer active; 073 private List<Runnable> postLoadTasks; 074 private ViewportData viewport; 075 076 /** 077 * Constructs a new {@code Loader} for local session file. 078 * @param file The JOSM session file 079 * @param zip {@code true} if the file is a session archive file (*.joz) 080 */ 081 public Loader(File file, boolean zip) { 082 super(tr("Loading session ''{0}''", file.getName())); 083 CheckParameterUtil.ensureParameterNotNull(file, "file"); 084 this.file = file; 085 this.uri = null; 086 this.is = null; 087 this.zip = zip; 088 } 089 090 /** 091 * Constructs a new {@code Loader} for session file input stream (may be a remote file). 092 * @param is The input stream to session file 093 * @param uri The file URI 094 * @param zip {@code true} if the file is a session archive file (*.joz) 095 * @since 6245 096 */ 097 public Loader(InputStream is, URI uri, boolean zip) { 098 super(tr("Loading session ''{0}''", uri)); 099 CheckParameterUtil.ensureParameterNotNull(is, "is"); 100 CheckParameterUtil.ensureParameterNotNull(uri, "uri"); 101 this.file = null; 102 this.uri = uri; 103 this.is = is; 104 this.zip = zip; 105 } 106 107 @Override 108 public void cancel() { 109 canceled = true; 110 } 111 112 @Override 113 protected void finish() { 114 SwingUtilities.invokeLater(new Runnable() { 115 @Override 116 public void run() { 117 if (canceled) 118 return; 119 addLayers(); 120 runPostLoadTasks(); 121 } 122 }); 123 } 124 125 private void addLayers() { 126 if (layers != null && !layers.isEmpty()) { 127 boolean noMap = Main.map == null; 128 for (Layer l : layers) { 129 if (canceled) 130 return; 131 Main.getLayerManager().addLayer(l); 132 } 133 if (active != null) { 134 Main.getLayerManager().setActiveLayer(active); 135 } 136 if (noMap) { 137 Main.map.mapView.scheduleZoomTo(viewport); 138 } 139 } 140 } 141 142 private void runPostLoadTasks() { 143 for (Runnable task : postLoadTasks) { 144 if (canceled) 145 return; 146 if (task == null) { 147 continue; 148 } 149 task.run(); 150 } 151 } 152 153 @Override 154 protected void realRun() { 155 try { 156 ProgressMonitor monitor = getProgressMonitor(); 157 SessionReader reader = new SessionReader(); 158 boolean tempFile = false; 159 try { 160 if (file == null) { 161 // Download and write entire joz file as a temp file on disk as we need random access later 162 file = File.createTempFile("session_", ".joz", Utils.getJosmTempDir()); 163 tempFile = true; 164 Files.copy(is, file.toPath(), StandardCopyOption.REPLACE_EXISTING); 165 } 166 reader.loadSession(file, zip, monitor); 167 layers = reader.getLayers(); 168 active = reader.getActive(); 169 postLoadTasks = reader.getPostLoadTasks(); 170 viewport = reader.getViewport(); 171 } finally { 172 if (tempFile) { 173 Utils.deleteFile(file); 174 file = null; 175 } 176 } 177 } catch (IllegalDataException e) { 178 handleException(tr("Data Error"), e); 179 } catch (IOException e) { 180 handleException(tr("IO Error"), e); 181 } catch (RuntimeException e) { 182 cancel(); 183 throw e; 184 } 185 } 186 187 private void handleException(String dialogTitle, Exception e) { 188 Main.error(e); 189 HelpAwareOptionPane.showMessageDialogInEDT( 190 Main.parent, 191 tr("<html>Could not load session file ''{0}''.<br>Error is:<br>{1}</html>", 192 uri != null ? uri : file.getName(), e.getMessage()), 193 dialogTitle, 194 JOptionPane.ERROR_MESSAGE, 195 null 196 ); 197 cancel(); 198 } 199 } 200}