| 1 | // License: GPL. For details, see LICENSE file.
|
|---|
| 2 | package org.openstreetmap.josm.actions;
|
|---|
| 3 |
|
|---|
| 4 | import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
|
|---|
| 5 | import static org.openstreetmap.josm.tools.I18n.tr;
|
|---|
| 6 |
|
|---|
| 7 | import java.awt.event.ActionEvent;
|
|---|
| 8 | import java.io.File;
|
|---|
| 9 | import java.io.IOException;
|
|---|
| 10 | import java.io.InputStream;
|
|---|
| 11 | import java.net.URI;
|
|---|
| 12 | import java.nio.file.Files;
|
|---|
| 13 | import java.nio.file.StandardCopyOption;
|
|---|
| 14 | import java.util.Arrays;
|
|---|
| 15 | import java.util.EnumSet;
|
|---|
| 16 | import java.util.List;
|
|---|
| 17 |
|
|---|
| 18 | import javax.swing.JFileChooser;
|
|---|
| 19 | import javax.swing.JOptionPane;
|
|---|
| 20 | import javax.swing.SwingUtilities;
|
|---|
| 21 |
|
|---|
| 22 | import org.openstreetmap.josm.data.projection.ProjectionRegistry;
|
|---|
| 23 | import org.openstreetmap.josm.gui.HelpAwareOptionPane;
|
|---|
| 24 | import org.openstreetmap.josm.gui.MainApplication;
|
|---|
| 25 | import org.openstreetmap.josm.gui.Notification;
|
|---|
| 26 | import org.openstreetmap.josm.gui.PleaseWaitRunnable;
|
|---|
| 27 | import org.openstreetmap.josm.gui.layer.Layer;
|
|---|
| 28 | import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
|
|---|
| 29 | import org.openstreetmap.josm.gui.progress.ProgressMonitor;
|
|---|
| 30 | import org.openstreetmap.josm.gui.util.FileFilterAllFiles;
|
|---|
| 31 | import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
|
|---|
| 32 | import org.openstreetmap.josm.io.IllegalDataException;
|
|---|
| 33 | import org.openstreetmap.josm.io.session.SessionImporter;
|
|---|
| 34 | import org.openstreetmap.josm.io.session.SessionReader;
|
|---|
| 35 | import org.openstreetmap.josm.io.session.SessionReader.SessionProjectionChoiceData;
|
|---|
| 36 | import org.openstreetmap.josm.io.session.SessionReader.SessionViewportData;
|
|---|
| 37 | import org.openstreetmap.josm.io.session.SessionWriter;
|
|---|
| 38 | import org.openstreetmap.josm.tools.CheckParameterUtil;
|
|---|
| 39 | import org.openstreetmap.josm.tools.JosmRuntimeException;
|
|---|
| 40 | import org.openstreetmap.josm.tools.Logging;
|
|---|
| 41 | import org.openstreetmap.josm.tools.Utils;
|
|---|
| 42 | import org.openstreetmap.josm.tools.bugreport.ReportedException;
|
|---|
| 43 |
|
|---|
| 44 | /**
|
|---|
| 45 | * Loads a JOSM session.
|
|---|
| 46 | * @since 4668
|
|---|
| 47 | */
|
|---|
| 48 | public 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 | }
|
|---|