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 }