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