001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.actions;
003    
004    import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005    import static org.openstreetmap.josm.tools.I18n.tr;
006    
007    import java.awt.Component;
008    import java.awt.Dimension;
009    import java.awt.GridBagLayout;
010    import java.awt.event.ActionEvent;
011    import java.io.File;
012    import java.io.IOException;
013    import java.util.ArrayList;
014    import java.util.Arrays;
015    import java.util.Collection;
016    import java.util.Collections;
017    import java.util.HashMap;
018    import java.util.HashSet;
019    import java.util.List;
020    import java.util.Map;
021    import java.util.Set;
022    
023    import javax.swing.BorderFactory;
024    import javax.swing.JCheckBox;
025    import javax.swing.JFileChooser;
026    import javax.swing.JLabel;
027    import javax.swing.JOptionPane;
028    import javax.swing.JPanel;
029    import javax.swing.JScrollPane;
030    import javax.swing.JTabbedPane;
031    import javax.swing.SwingConstants;
032    import javax.swing.border.EtchedBorder;
033    import javax.swing.filechooser.FileFilter;
034    
035    import org.openstreetmap.josm.Main;
036    import org.openstreetmap.josm.gui.ExtendedDialog;
037    import org.openstreetmap.josm.gui.HelpAwareOptionPane;
038    import org.openstreetmap.josm.gui.layer.Layer;
039    import org.openstreetmap.josm.io.session.SessionLayerExporter;
040    import org.openstreetmap.josm.io.session.SessionWriter;
041    import org.openstreetmap.josm.tools.GBC;
042    import org.openstreetmap.josm.tools.MultiMap;
043    import org.openstreetmap.josm.tools.WindowGeometry;
044    
045    public class SessionSaveAsAction extends DiskAccessAction {
046    
047        private List<Layer> layers;
048        private Map<Layer, SessionLayerExporter> exporters;
049        private MultiMap<Layer, Layer> dependencies;
050    
051        private boolean zipRequired;
052    
053        public SessionSaveAsAction() {
054            super(tr("Save Session As..."), "save_as", tr("Save the current session to a new file."), null, true, "save_as-session", true);
055            putValue("help", ht("/Action/SessionSaveAs"));
056        }
057    
058        @Override
059        public void actionPerformed(ActionEvent e) {
060            if (!isEnabled()) {
061                return;
062            }
063    
064            SessionSaveAsDialog dlg = new SessionSaveAsDialog();
065            dlg.showDialog();
066            if (dlg.getValue() != 2) return;
067    
068            zipRequired = false;
069            for (Layer l : layers) {
070                SessionLayerExporter ex = exporters.get(l);
071                if (ex != null && ex.requiresZip()) {
072                    zipRequired = true;
073                    break;
074                }
075            }
076            
077            FileFilter joz = new ExtensionFileFilter("joz", "joz", tr("Session file (archive) (*.joz)"));
078            FileFilter jos = new ExtensionFileFilter("jos", "jos", tr("Session file (*.jos)"));
079    
080            JFileChooser fc;
081    
082            if (zipRequired) {
083                fc = createAndOpenFileChooser(false, false, tr("Save session"), joz, JFileChooser.FILES_ONLY, "lastDirectory");
084            } else {
085                fc = createAndOpenFileChooser(false, false, tr("Save session"), Arrays.asList(new FileFilter[]{jos, joz}), jos, JFileChooser.FILES_ONLY, "lastDirectory");
086            }
087    
088            if (fc == null)
089                return;
090    
091            File file = fc.getSelectedFile();
092            String fn = file.getName();
093    
094            boolean zip;
095            FileFilter ff = fc.getFileFilter();
096            if (zipRequired) {
097                zip = true;
098            } else if (ff == joz) {
099                zip = true;
100            } else if (ff == jos) {
101                zip = false;
102            } else {
103                if (fn.toLowerCase().endsWith(".joz")) {
104                    zip = true;
105                } else {
106                    zip = false;
107                }
108            }
109            if (fn.indexOf('.') == -1) {
110                file = new File(file.getPath() + (zip ? ".joz" : ".jos"));
111                if (!SaveActionBase.confirmOverwrite(file))
112                    return;
113            }
114    
115            List<Layer> layersOut = new ArrayList<Layer>();
116            for (Layer layer : layers) {
117                if (exporters.get(layer) == null || !exporters.get(layer).shallExport()) continue;
118                // TODO: resolve dependencies for layers excluded by the user
119                layersOut.add(layer);
120            }
121    
122            SessionWriter sw = new SessionWriter(layersOut, exporters, dependencies, zip);
123            try {
124                sw.write(file);
125            } catch (IOException ex) {
126                ex.printStackTrace();
127                HelpAwareOptionPane.showMessageDialogInEDT(
128                        Main.parent,
129                        tr("<html>Could not save session file ''{0}''.<br>Error is:<br>{1}</html>", file.getName(), ex.getMessage()),
130                        tr("IO Error"),
131                        JOptionPane.ERROR_MESSAGE,
132                        null
133                );
134            }
135        }
136    
137        public class SessionSaveAsDialog extends ExtendedDialog {
138    
139            public SessionSaveAsDialog() {
140                super(Main.parent, tr("Save Session"), new String[] {tr("Cancel"), tr("Save As")});
141                initialize();
142                setButtonIcons(new String[] {"cancel", "save_as"});
143                setDefaultButton(2);
144                setRememberWindowGeometry(getClass().getName() + ".geometry",
145                        WindowGeometry.centerInWindow(Main.parent, new Dimension(350, 450)));
146                setContent(build(), false);
147            }
148    
149            public void initialize() {
150                layers = new ArrayList<Layer>(Main.map.mapView.getAllLayersAsList());
151                exporters = new HashMap<Layer, SessionLayerExporter>();
152                dependencies = new MultiMap<Layer, Layer>();
153    
154                Set<Layer> noExporter = new HashSet<Layer>();
155    
156                for (Layer layer : layers) {
157                    SessionLayerExporter exporter = SessionWriter.getSessionLayerExporter(layer);
158                    if (exporter != null) {
159                        exporters.put(layer, exporter);
160                        Collection<Layer> deps = exporter.getDependencies();
161                        if (deps != null) {
162                            dependencies.putAll(layer, deps);
163                        } else {
164                            dependencies.putVoid(layer);
165                        }
166                    } else {
167                        noExporter.add(layer);
168                        exporters.put(layer, null);
169                    }
170                }
171    
172                int numNoExporter = 0;
173                WHILE:while (numNoExporter != noExporter.size()) {
174                    numNoExporter = noExporter.size();
175                    for (Layer layer : layers) {
176                        if (noExporter.contains(layer)) continue;
177                        for (Layer depLayer : dependencies.get(layer)) {
178                            if (noExporter.contains(depLayer)) {
179                                noExporter.add(layer);
180                                exporters.put(layer, null);
181                                break WHILE;
182                            }
183                        }
184                    }
185                }
186            }
187    
188            public Component build() {
189                JPanel p = new JPanel(new GridBagLayout());
190                JPanel ip = new JPanel(new GridBagLayout());
191                for (Layer layer : layers) {
192                    JPanel wrapper = new JPanel(new GridBagLayout());
193                    wrapper.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
194                    Component exportPanel;
195                    SessionLayerExporter exporter = exporters.get(layer);
196                    if (exporter == null) {
197                        if (!exporters.containsKey(layer)) throw new AssertionError();
198                        exportPanel = getDisabledExportPanel(layer);
199                    } else {
200                        exportPanel = exporter.getExportPanel();
201                    }
202                    wrapper.add(exportPanel, GBC.std().fill(GBC.HORIZONTAL));
203                    ip.add(wrapper, GBC.eol().fill(GBC.HORIZONTAL).insets(2,2,4,2));
204                }
205                ip.add(GBC.glue(0,1), GBC.eol().fill(GBC.VERTICAL));
206                JScrollPane sp = new JScrollPane(ip);
207                sp.setBorder(BorderFactory.createEmptyBorder());
208                p.add(sp, GBC.eol().fill());
209                final JTabbedPane tabs = new JTabbedPane();
210                tabs.addTab(tr("Layers"), p);
211                return tabs;
212            }
213    
214            protected Component getDisabledExportPanel(Layer layer) {
215                JPanel p = new JPanel(new GridBagLayout());
216                JCheckBox include = new JCheckBox();
217                include.setEnabled(false);
218                JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEFT);
219                lbl.setToolTipText(tr("No exporter for this layer"));
220                lbl.setEnabled(false);
221                p.add(include, GBC.std());
222                p.add(lbl, GBC.std());
223                p.add(GBC.glue(1,0), GBC.std().fill(GBC.HORIZONTAL));
224                return p;
225            }
226        }
227    
228    }