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