source: josm/trunk/src/org/openstreetmap/josm/actions/SessionLoadAction.java

Last change on this file was 18833, checked in by taylor.smock, 2 years ago

Fix #17052: Allow plugins to save state to session file

The primary feature request was for the TODO plugin to save the list elements for
a future session.

This allows plugins to register via ServiceLoader classes which need to be
called to save or restore their state.

In addition, this fixes an ordering issue with tests whereby the OsmApi cache
would be cleared, but the FakeOsmApi class would not recache itself when called.

  • Property svn:eol-style set to native
File size: 9.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.event.ActionEvent;
8import java.io.File;
9import java.io.IOException;
10import java.io.InputStream;
11import java.net.URI;
12import java.nio.file.Files;
13import java.nio.file.StandardCopyOption;
14import java.util.Arrays;
15import java.util.EnumSet;
16import java.util.List;
17
18import javax.swing.JFileChooser;
19import javax.swing.JOptionPane;
20import javax.swing.SwingUtilities;
21
22import org.openstreetmap.josm.data.projection.ProjectionRegistry;
23import org.openstreetmap.josm.gui.HelpAwareOptionPane;
24import org.openstreetmap.josm.gui.MainApplication;
25import org.openstreetmap.josm.gui.Notification;
26import org.openstreetmap.josm.gui.PleaseWaitRunnable;
27import org.openstreetmap.josm.gui.layer.Layer;
28import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
29import org.openstreetmap.josm.gui.progress.ProgressMonitor;
30import org.openstreetmap.josm.gui.util.FileFilterAllFiles;
31import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
32import org.openstreetmap.josm.io.IllegalDataException;
33import org.openstreetmap.josm.io.session.SessionImporter;
34import org.openstreetmap.josm.io.session.SessionReader;
35import org.openstreetmap.josm.io.session.SessionReader.SessionProjectionChoiceData;
36import org.openstreetmap.josm.io.session.SessionReader.SessionViewportData;
37import org.openstreetmap.josm.io.session.SessionWriter;
38import org.openstreetmap.josm.tools.CheckParameterUtil;
39import org.openstreetmap.josm.tools.JosmRuntimeException;
40import org.openstreetmap.josm.tools.Logging;
41import org.openstreetmap.josm.tools.Utils;
42import org.openstreetmap.josm.tools.bugreport.ReportedException;
43
44/**
45 * Loads a JOSM session.
46 * @since 4668
47 */
48public class SessionLoadAction extends DiskAccessAction {
49
50 /**
51 * Constructs a new {@code SessionLoadAction}.
52 */
53 public SessionLoadAction() {
54 super(tr("Load Session"), "open", tr("Load a session from file."), null, true, "load-session", true);
55 setHelpId(ht("/Action/SessionLoad"));
56 }
57
58 @Override
59 public void actionPerformed(ActionEvent e) {
60 AbstractFileChooser fc = createAndOpenFileChooser(true, false, tr("Open session"),
61 Arrays.asList(SessionImporter.FILE_FILTER, FileFilterAllFiles.getInstance()),
62 SessionImporter.FILE_FILTER, JFileChooser.FILES_ONLY, "lastDirectory");
63 if (fc == null)
64 return;
65 File file = fc.getSelectedFile();
66 boolean zip = Utils.hasExtension(file, "joz");
67 MainApplication.worker.submit(new Loader(file, zip));
68 }
69
70 /**
71 * JOSM session loader
72 */
73 public static class Loader extends PleaseWaitRunnable {
74
75 private boolean canceled;
76 private File file;
77 private final URI uri;
78 private final InputStream is;
79 private final boolean zip;
80 private List<Layer> layers;
81 private Layer active;
82 private List<Runnable> postLoadTasks;
83 private SessionViewportData viewport;
84 private SessionProjectionChoiceData projectionChoice;
85
86 /**
87 * Constructs a new {@code Loader} for local session file.
88 * @param file The JOSM session file
89 * @param zip {@code true} if the file is a session archive file (*.joz)
90 */
91 public Loader(File file, boolean zip) {
92 super(tr("Loading session ''{0}''", file.getName()));
93 CheckParameterUtil.ensureParameterNotNull(file, "file");
94 this.file = file;
95 this.uri = null;
96 this.is = null;
97 this.zip = zip;
98 }
99
100 /**
101 * Constructs a new {@code Loader} for session file input stream (may be a remote file).
102 * @param is The input stream to session file
103 * @param uri The file URI
104 * @param zip {@code true} if the file is a session archive file (*.joz)
105 * @since 6245
106 */
107 public Loader(InputStream is, URI uri, boolean zip) {
108 super(tr("Loading session ''{0}''", uri));
109 CheckParameterUtil.ensureParameterNotNull(is, "is");
110 CheckParameterUtil.ensureParameterNotNull(uri, "uri");
111 this.file = null;
112 this.uri = uri;
113 this.is = is;
114 this.zip = zip;
115 }
116
117 @Override
118 public void cancel() {
119 canceled = true;
120 }
121
122 @Override
123 protected void finish() {
124 SwingUtilities.invokeLater(() -> {
125 if (canceled)
126 return;
127 if (projectionChoice != null) {
128 ProjectionPreference.setProjection(
129 projectionChoice.getProjectionChoiceId(),
130 projectionChoice.getSubPreferences(),
131 false);
132 }
133 addLayers();
134 runPostLoadTasks();
135 });
136 }
137
138 private void addLayers() {
139 if (!Utils.isEmpty(layers)) {
140 boolean noMap = MainApplication.getMap() == null;
141 for (Layer l : layers) {
142 if (canceled)
143 return;
144 addLayer(l);
145 }
146 if (active != null) {
147 MainApplication.getLayerManager().setActiveLayer(active);
148 }
149 if (noMap && viewport != null) {
150 MainApplication.getMap().mapView.scheduleZoomTo(viewport.getEastNorthViewport(ProjectionRegistry.getProjection()));
151 }
152 }
153 }
154
155 /**
156 * Tries to add a new layer.
157 * @param l layer to add
158 * @return {@code true} if layer has been added, {@code false} if it wasn't needed or if an error occurred
159 */
160 static boolean addLayer(Layer l) {
161 // NoteImporter directly loads notes into current note layer
162 if (!MainApplication.getLayerManager().containsLayer(l)) {
163 try {
164 MainApplication.getLayerManager().addLayer(l);
165 } catch (ReportedException e) {
166 Logging.error(e);
167 new Notification(tr("Unable to add layer ''{0}'': {1}", l.getName(), e.getMessage()))
168 .setIcon(JOptionPane.ERROR_MESSAGE).setDuration(Notification.TIME_LONG).show();
169 if (MainApplication.getLayerManager().containsLayer(l)) {
170 MainApplication.getLayerManager().removeLayer(l);
171 }
172 return false;
173 }
174 }
175 return true;
176 }
177
178 private void runPostLoadTasks() {
179 if (postLoadTasks != null) {
180 for (Runnable task : postLoadTasks) {
181 if (canceled)
182 return;
183 if (task == null) {
184 continue;
185 }
186 task.run();
187 }
188 }
189 }
190
191 @Override
192 protected void realRun() {
193 try {
194 ProgressMonitor monitor = getProgressMonitor();
195 SessionReader reader = new SessionReader();
196 boolean tempFile = false;
197 try {
198 if (file == null) {
199 // Download and write entire joz file as a temp file on disk as we need random access later
200 file = File.createTempFile("session_", ".joz", Utils.getJosmTempDir());
201 tempFile = true;
202 Files.copy(is, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
203 }
204 reader.loadSession(file, zip, monitor);
205 layers = reader.getLayers();
206 active = reader.getActive();
207 postLoadTasks = reader.getPostLoadTasks();
208 viewport = reader.getViewport();
209 projectionChoice = reader.getProjectionChoice();
210 final EnumSet<SessionWriter.SessionWriterFlags> flagSet = EnumSet.noneOf(SessionWriter.SessionWriterFlags.class);
211 if (zip) {
212 flagSet.add(SessionWriter.SessionWriterFlags.IS_ZIP);
213 }
214 if (reader.loadedPluginData()) {
215 flagSet.add(SessionWriter.SessionWriterFlags.SAVE_PLUGIN_INFORMATION);
216 }
217 SessionSaveAction.setCurrentSession(file, reader.getLayers(), flagSet);
218 } finally {
219 if (tempFile) {
220 Utils.deleteFile(file);
221 file = null;
222 }
223 }
224 } catch (IllegalDataException e) {
225 handleException(tr("Data Error"), e);
226 } catch (IOException e) {
227 handleException(tr("IO Error"), e);
228 } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) {
229 cancel();
230 throw e;
231 }
232 }
233
234 private void handleException(String dialogTitle, Exception e) {
235 Logging.error(e);
236 HelpAwareOptionPane.showMessageDialogInEDT(
237 MainApplication.getMainFrame(),
238 tr("<html>Could not load session file ''{0}''.<br>Error is:<br>{1}</html>",
239 uri != null ? uri : file.getName(), Utils.escapeReservedCharactersHTML(e.getMessage())),
240 dialogTitle,
241 JOptionPane.ERROR_MESSAGE,
242 null
243 );
244 cancel();
245 }
246 }
247}
Note: See TracBrowser for help on using the repository browser.