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