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.gui.HelpAwareOptionPane;
022import org.openstreetmap.josm.gui.NavigatableComponent.ViewportData;
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.io.IllegalDataException;
028import org.openstreetmap.josm.io.session.SessionImporter;
029import org.openstreetmap.josm.io.session.SessionReader;
030import org.openstreetmap.josm.tools.CheckParameterUtil;
031import org.openstreetmap.josm.tools.Utils;
032
033/**
034 * Loads a JOSM session
035 * @since 4668
036 */
037public class SessionLoadAction extends DiskAccessAction {
038
039    /**
040     * Constructs a new {@code SessionLoadAction}.
041     */
042    public SessionLoadAction() {
043        super(tr("Load Session"), "open", tr("Load a session from file."), null, true, "load-session", true);
044        putValue("help", ht("/Action/SessionLoad"));
045    }
046
047    @Override
048    public void actionPerformed(ActionEvent e) {
049        JFileChooser fc = createAndOpenFileChooser(true, false, tr("Open session"), 
050                Arrays.asList(SessionImporter.FILE_FILTER, FileFilterAllFiles.getInstance()), 
051                SessionImporter.FILE_FILTER, JFileChooser.FILES_ONLY, "lastDirectory");
052        if (fc == null) return;
053        File file = fc.getSelectedFile();
054        boolean zip = file.getName().toLowerCase().endsWith(".joz");
055        Main.worker.submit(new Loader(file, zip));
056    }
057
058    /**
059     * JOSM session loader
060     */
061    public static class Loader extends PleaseWaitRunnable {
062
063        private boolean canceled;
064        private File file;
065        private final URI uri;
066        private final InputStream is;
067        private final boolean zip;
068        private List<Layer> layers;
069        private Layer active;
070        private List<Runnable> postLoadTasks;
071        private ViewportData viewport;
072
073        /**
074         * Constructs a new {@code Loader} for local session file.
075         * @param file The JOSM session file
076         * @param zip {@code true} if the file is a session archive file (*.joz)
077         */
078        public Loader(File file, boolean zip) {
079            super(tr("Loading session ''{0}''", file.getName()));
080            CheckParameterUtil.ensureParameterNotNull(file, "file");
081            this.file = file;
082            this.uri = null;
083            this.is = null;
084            this.zip = zip;
085        }
086
087        /**
088         * Constructs a new {@code Loader} for session file input stream (may be a remote file).
089         * @param is The input stream to session file
090         * @param uri The file URI
091         * @param zip {@code true} if the file is a session archive file (*.joz)
092         * @since 6245
093         */
094        public Loader(InputStream is, URI uri, boolean zip) {
095            super(tr("Loading session ''{0}''", uri));
096            CheckParameterUtil.ensureParameterNotNull(is, "is");
097            CheckParameterUtil.ensureParameterNotNull(uri, "uri");
098            this.file = null;
099            this.uri = uri;
100            this.is = is;
101            this.zip = zip;
102        }
103
104        @Override
105        public void cancel() {
106            Thread.dumpStack();
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                        FileOutputStream out = new FileOutputStream(file);
156                        try {
157                            Utils.copyStream(is, out);
158                        } finally {
159                            Utils.close(out);
160                        }
161                    }
162                    reader.loadSession(file, zip, monitor);
163                    layers = reader.getLayers();
164                    active = reader.getActive();
165                    postLoadTasks = reader.getPostLoadTasks();
166                    viewport = reader.getViewport();
167                } finally {
168                    if (tempFile) {
169                        if (!file.delete()) {
170                            file.deleteOnExit();
171                        }
172                        file = null;
173                    }
174                }
175            } catch (IllegalDataException e) {
176                e.printStackTrace();
177                HelpAwareOptionPane.showMessageDialogInEDT(
178                        Main.parent,
179                        tr("<html>Could not load session file ''{0}''.<br>Error is:<br>{1}</html>", uri != null ? uri : file.getName(), e.getMessage()),
180                        tr("Data Error"),
181                        JOptionPane.ERROR_MESSAGE,
182                        null
183                        );
184                cancel();
185            } catch (IOException e) {
186                e.printStackTrace();
187                HelpAwareOptionPane.showMessageDialogInEDT(
188                        Main.parent,
189                        tr("<html>Could not load session file ''{0}''.<br>Error is:<br>{1}</html>", uri != null ? uri : file.getName(), e.getMessage()),
190                        tr("IO Error"),
191                        JOptionPane.ERROR_MESSAGE,
192                        null
193                        );
194                cancel();
195            } catch (RuntimeException e) {
196                cancel();
197                throw e;
198            } catch (Error e) {
199                cancel();
200                throw e;
201            }
202        }
203    }
204}
205