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                Layer firstLayer = layers.get(0);
128                boolean noMap = Main.map == null;
129                if (noMap) {
130                    Main.main.createMapFrame(firstLayer, viewport);
131                }
132                for (Layer l : layers) {
133                    if (canceled)
134                        return;
135                    Main.main.addLayer(l, (ViewportData) null);
136                }
137                if (active != null) {
138                    Main.getLayerManager().setActiveLayer(active);
139                }
140                if (noMap) {
141                    Main.map.setVisible(true);
142                }
143            }
144        }
145
146        private void runPostLoadTasks() {
147            for (Runnable task : postLoadTasks) {
148                if (canceled)
149                    return;
150                if (task == null) {
151                    continue;
152                }
153                task.run();
154            }
155        }
156
157        @Override
158        protected void realRun() {
159            try {
160                ProgressMonitor monitor = getProgressMonitor();
161                SessionReader reader = new SessionReader();
162                boolean tempFile = false;
163                try {
164                    if (file == null) {
165                        // Download and write entire joz file as a temp file on disk as we need random access later
166                        file = File.createTempFile("session_", ".joz", Utils.getJosmTempDir());
167                        tempFile = true;
168                        Files.copy(is, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
169                    }
170                    reader.loadSession(file, zip, monitor);
171                    layers = reader.getLayers();
172                    active = reader.getActive();
173                    postLoadTasks = reader.getPostLoadTasks();
174                    viewport = reader.getViewport();
175                } finally {
176                    if (tempFile) {
177                        Utils.deleteFile(file);
178                        file = null;
179                    }
180                }
181            } catch (IllegalDataException e) {
182                handleException(tr("Data Error"), e);
183            } catch (IOException e) {
184                handleException(tr("IO Error"), e);
185            } catch (RuntimeException e) {
186                cancel();
187                throw e;
188            }
189        }
190
191        private void handleException(String dialogTitle, Exception e) {
192            Main.error(e);
193            HelpAwareOptionPane.showMessageDialogInEDT(
194                    Main.parent,
195                    tr("<html>Could not load session file ''{0}''.<br>Error is:<br>{1}</html>",
196                            uri != null ? uri : file.getName(), e.getMessage()),
197                    dialogTitle,
198                    JOptionPane.ERROR_MESSAGE,
199                    null
200                    );
201            cancel();
202        }
203    }
204}