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) return;
055        File file = fc.getSelectedFile();
056        boolean zip = Utils.hasExtension(file, "joz");
057        Main.worker.submit(new Loader(file, zip));
058    }
059
060    /**
061     * JOSM session loader
062     */
063    public static class Loader extends PleaseWaitRunnable {
064
065        private boolean canceled;
066        private File file;
067        private final URI uri;
068        private final InputStream is;
069        private final boolean zip;
070        private List<Layer> layers;
071        private Layer active;
072        private List<Runnable> postLoadTasks;
073        private ViewportData viewport;
074
075        /**
076         * Constructs a new {@code Loader} for local session file.
077         * @param file The JOSM session file
078         * @param zip {@code true} if the file is a session archive file (*.joz)
079         */
080        public Loader(File file, boolean zip) {
081            super(tr("Loading session ''{0}''", file.getName()));
082            CheckParameterUtil.ensureParameterNotNull(file, "file");
083            this.file = file;
084            this.uri = null;
085            this.is = null;
086            this.zip = zip;
087        }
088
089        /**
090         * Constructs a new {@code Loader} for session file input stream (may be a remote file).
091         * @param is The input stream to session file
092         * @param uri The file URI
093         * @param zip {@code true} if the file is a session archive file (*.joz)
094         * @since 6245
095         */
096        public Loader(InputStream is, URI uri, boolean zip) {
097            super(tr("Loading session ''{0}''", uri));
098            CheckParameterUtil.ensureParameterNotNull(is, "is");
099            CheckParameterUtil.ensureParameterNotNull(uri, "uri");
100            this.file = null;
101            this.uri = uri;
102            this.is = is;
103            this.zip = zip;
104        }
105
106        @Override
107        public void cancel() {
108            canceled = true;
109        }
110
111        @Override
112        protected void finish() {
113            SwingUtilities.invokeLater(new Runnable() {
114                @Override
115                public void run() {
116                    if (canceled) return;
117                    if (!layers.isEmpty()) {
118                        Layer firstLayer = layers.get(0);
119                        boolean noMap = Main.map == null;
120                        if (noMap) {
121                            Main.main.createMapFrame(firstLayer, viewport);
122                        }
123                        for (Layer l : layers) {
124                            if (canceled) return;
125                            Main.main.addLayer(l, (ViewportData) null);
126                        }
127                        if (active != null) {
128                            Main.map.mapView.setActiveLayer(active);
129                        }
130                        if (noMap) {
131                            Main.map.setVisible(true);
132                        }
133                    }
134                    for (Runnable task : postLoadTasks) {
135                        if (canceled) return;
136                        if (task == null) {
137                            continue;
138                        }
139                        task.run();
140                    }
141                }
142            });
143        }
144
145        @Override
146        protected void realRun() {
147            try {
148                ProgressMonitor monitor = getProgressMonitor();
149                SessionReader reader = new SessionReader();
150                boolean tempFile = false;
151                try {
152                    if (file == null) {
153                        // Download and write entire joz file as a temp file on disk as we need random access later
154                        file = File.createTempFile("session_", ".joz", Utils.getJosmTempDir());
155                        tempFile = true;
156                        Files.copy(is, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
157                    }
158                    reader.loadSession(file, zip, monitor);
159                    layers = reader.getLayers();
160                    active = reader.getActive();
161                    postLoadTasks = reader.getPostLoadTasks();
162                    viewport = reader.getViewport();
163                } finally {
164                    if (tempFile) {
165                        Utils.deleteFile(file);
166                        file = null;
167                    }
168                }
169            } catch (IllegalDataException e) {
170                handleException(tr("Data Error"), e);
171            } catch (IOException e) {
172                handleException(tr("IO Error"), e);
173            } catch (Exception e) {
174                cancel();
175                throw e;
176            }
177        }
178
179        private void handleException(String dialogTitle, Exception e) {
180            Main.error(e);
181            HelpAwareOptionPane.showMessageDialogInEDT(
182                    Main.parent,
183                    tr("<html>Could not load session file ''{0}''.<br>Error is:<br>{1}</html>",
184                            uri != null ? uri : file.getName(), e.getMessage()),
185                    dialogTitle,
186                    JOptionPane.ERROR_MESSAGE,
187                    null
188                    );
189            cancel();
190        }
191    }
192}