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.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            canceled = true;
107        }
108
109        @Override
110        protected void finish() {
111            SwingUtilities.invokeLater(new Runnable() {
112                @Override
113                public void run() {
114                    if (canceled) return;
115                    if (!layers.isEmpty()) {
116                        Layer firstLayer = layers.iterator().next();
117                        boolean noMap = Main.map == null;
118                        if (noMap) {
119                            Main.main.createMapFrame(firstLayer, viewport);
120                        }
121                        for (Layer l : layers) {
122                            if (canceled) return;
123                            Main.main.addLayer(l);
124                        }
125                        if (active != null) {
126                            Main.map.mapView.setActiveLayer(active);
127                        }
128                        if (noMap) {
129                            Main.map.setVisible(true);
130                        }
131                    }
132                    for (Runnable task : postLoadTasks) {
133                        if (canceled) return;
134                        if (task == null) {
135                            continue;
136                        }
137                        task.run();
138                    }
139                }
140            });
141        }
142
143        @Override
144        protected void realRun() {
145            try {
146                ProgressMonitor monitor = getProgressMonitor();
147                SessionReader reader = new SessionReader();
148                boolean tempFile = false;
149                try {
150                    if (file == null) {
151                        // Download and write entire joz file as a temp file on disk as we need random access later
152                        file = File.createTempFile("session_", ".joz", Utils.getJosmTempDir());
153                        tempFile = true;
154                        try (FileOutputStream out = new FileOutputStream(file)) {
155                            Utils.copyStream(is, out);
156                        }
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                        if (!file.delete()) {
166                            file.deleteOnExit();
167                        }
168                        file = null;
169                    }
170                }
171            } catch (IllegalDataException e) {
172                handleException(tr("Data Error"), e);
173            } catch (IOException e) {
174                handleException(tr("IO Error"), e);
175            } catch (Exception e) {
176                cancel();
177                throw e;
178            }
179        }
180
181        private void handleException(String dialogTitle, Exception e) {
182            Main.error(e);
183            HelpAwareOptionPane.showMessageDialogInEDT(
184                    Main.parent,
185                    tr("<html>Could not load session file ''{0}''.<br>Error is:<br>{1}</html>", uri != null ? uri : file.getName(), e.getMessage()),
186                    dialogTitle,
187                    JOptionPane.ERROR_MESSAGE,
188                    null
189                    );
190            cancel();
191        }
192    }
193}