| 1 | // License: GPL. For details, see LICENSE file. |
|---|
| 2 | package org.openstreetmap.josm.actions; |
|---|
| 3 | |
|---|
| 4 | import static org.openstreetmap.josm.tools.I18n.tr; |
|---|
| 5 | import static org.openstreetmap.josm.gui.help.HelpUtil.ht; |
|---|
| 6 | |
|---|
| 7 | import java.awt.Component; |
|---|
| 8 | import java.awt.Dimension; |
|---|
| 9 | import java.awt.GridBagLayout; |
|---|
| 10 | import java.awt.event.ActionEvent; |
|---|
| 11 | import java.io.File; |
|---|
| 12 | import java.io.IOException; |
|---|
| 13 | import java.util.ArrayList; |
|---|
| 14 | import java.util.Collection; |
|---|
| 15 | import java.util.HashMap; |
|---|
| 16 | import java.util.HashSet; |
|---|
| 17 | import java.util.List; |
|---|
| 18 | import java.util.Map; |
|---|
| 19 | import java.util.Set; |
|---|
| 20 | |
|---|
| 21 | import javax.swing.BorderFactory; |
|---|
| 22 | import javax.swing.JCheckBox; |
|---|
| 23 | import javax.swing.JFileChooser; |
|---|
| 24 | import javax.swing.JLabel; |
|---|
| 25 | import javax.swing.JOptionPane; |
|---|
| 26 | import javax.swing.JPanel; |
|---|
| 27 | import javax.swing.JScrollPane; |
|---|
| 28 | import javax.swing.JTabbedPane; |
|---|
| 29 | import javax.swing.SwingConstants; |
|---|
| 30 | import javax.swing.border.EtchedBorder; |
|---|
| 31 | import javax.swing.filechooser.FileFilter; |
|---|
| 32 | |
|---|
| 33 | import org.openstreetmap.josm.Main; |
|---|
| 34 | import org.openstreetmap.josm.actions.ExtensionFileFilter; |
|---|
| 35 | import org.openstreetmap.josm.gui.ExtendedDialog; |
|---|
| 36 | import org.openstreetmap.josm.gui.HelpAwareOptionPane; |
|---|
| 37 | import org.openstreetmap.josm.gui.layer.Layer; |
|---|
| 38 | import org.openstreetmap.josm.io.session.SessionLayerExporter; |
|---|
| 39 | import org.openstreetmap.josm.io.session.SessionWriter; |
|---|
| 40 | import org.openstreetmap.josm.tools.GBC; |
|---|
| 41 | import org.openstreetmap.josm.tools.MultiMap; |
|---|
| 42 | import org.openstreetmap.josm.tools.WindowGeometry; |
|---|
| 43 | |
|---|
| 44 | public class SessionSaveAsAction extends JosmAction { |
|---|
| 45 | |
|---|
| 46 | private List<Layer> layers; |
|---|
| 47 | private Map<Layer, SessionLayerExporter> exporters; |
|---|
| 48 | private MultiMap<Layer, Layer> dependencies; |
|---|
| 49 | |
|---|
| 50 | private boolean zipRequired; |
|---|
| 51 | |
|---|
| 52 | /** |
|---|
| 53 | * Construct the action with "Save" as label. |
|---|
| 54 | * @param layer Save this layer. |
|---|
| 55 | */ |
|---|
| 56 | public SessionSaveAsAction() { |
|---|
| 57 | super(tr("Save Session As..."), "save_as", tr("Save the current session to a new file."), null, true, "save_as-session", true); |
|---|
| 58 | putValue("help", ht("/Action/SessionSaveAs")); |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | @Override |
|---|
| 62 | public void actionPerformed(ActionEvent e) { |
|---|
| 63 | if (!isEnabled()) { |
|---|
| 64 | return; |
|---|
| 65 | } |
|---|
| 66 | |
|---|
| 67 | SessionSaveAsDialog dlg = new SessionSaveAsDialog(); |
|---|
| 68 | dlg.showDialog(); |
|---|
| 69 | if (dlg.getValue() != 2) return; |
|---|
| 70 | |
|---|
| 71 | zipRequired = false; |
|---|
| 72 | for (Layer l : layers) { |
|---|
| 73 | SessionLayerExporter ex = exporters.get(l); |
|---|
| 74 | if (ex.requiresZip()) { |
|---|
| 75 | zipRequired = true; |
|---|
| 76 | break; |
|---|
| 77 | } |
|---|
| 78 | } |
|---|
| 79 | |
|---|
| 80 | String curDir = Main.pref.get("lastDirectory"); |
|---|
| 81 | if (curDir.equals("")) { |
|---|
| 82 | curDir = "."; |
|---|
| 83 | } |
|---|
| 84 | JFileChooser fc = new JFileChooser(new File(curDir)); |
|---|
| 85 | fc.setDialogTitle(tr("Save session")); |
|---|
| 86 | fc.setFileSelectionMode(JFileChooser.FILES_ONLY); |
|---|
| 87 | FileFilter joz = new ExtensionFileFilter("joz", "joz", tr("Session file (archive) (*.joz)")); |
|---|
| 88 | FileFilter jos = new ExtensionFileFilter("jos", "jos", tr("Session file (*.jos)")); |
|---|
| 89 | if (zipRequired) { |
|---|
| 90 | fc.addChoosableFileFilter(joz); |
|---|
| 91 | } else { |
|---|
| 92 | fc.addChoosableFileFilter(jos); |
|---|
| 93 | fc.addChoosableFileFilter(joz); |
|---|
| 94 | fc.setFileFilter(jos); |
|---|
| 95 | } |
|---|
| 96 | int answer = fc.showSaveDialog(Main.parent); |
|---|
| 97 | if (answer != JFileChooser.APPROVE_OPTION) |
|---|
| 98 | return; |
|---|
| 99 | |
|---|
| 100 | if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) { |
|---|
| 101 | Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath()); |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | File file = fc.getSelectedFile(); |
|---|
| 105 | String fn = file.getName(); |
|---|
| 106 | |
|---|
| 107 | boolean zip; |
|---|
| 108 | FileFilter ff = fc.getFileFilter(); |
|---|
| 109 | if (zipRequired) { |
|---|
| 110 | zip = true; |
|---|
| 111 | } else if (ff == joz) { |
|---|
| 112 | zip = true; |
|---|
| 113 | } else if (ff == jos) { |
|---|
| 114 | zip = false; |
|---|
| 115 | } else { |
|---|
| 116 | if (fn.toLowerCase().endsWith(".joz")) { |
|---|
| 117 | zip = true; |
|---|
| 118 | } else { |
|---|
| 119 | zip = false; |
|---|
| 120 | } |
|---|
| 121 | } |
|---|
| 122 | if (fn.indexOf('.') == -1) { |
|---|
| 123 | file = new File(file.getPath() + (zip ? ".joz" : ".jos")); |
|---|
| 124 | } |
|---|
| 125 | if (!SaveActionBase.confirmOverwrite(file)) |
|---|
| 126 | return; |
|---|
| 127 | |
|---|
| 128 | List<Layer> layersOut = new ArrayList<Layer>(); |
|---|
| 129 | for (Layer layer : layers) { |
|---|
| 130 | if (exporters.get(layer) == null || !exporters.get(layer).shallExport()) continue; |
|---|
| 131 | // TODO: resolve dependencies for layers excluded by the user |
|---|
| 132 | layersOut.add(layer); |
|---|
| 133 | } |
|---|
| 134 | |
|---|
| 135 | SessionWriter sw = new SessionWriter(layersOut, exporters, dependencies, zip); |
|---|
| 136 | try { |
|---|
| 137 | sw.write(file); |
|---|
| 138 | } catch (IOException ex) { |
|---|
| 139 | ex.printStackTrace(); |
|---|
| 140 | HelpAwareOptionPane.showMessageDialogInEDT( |
|---|
| 141 | Main.parent, |
|---|
| 142 | tr("<html>Could not save session file ''{0}''.<br>Error is:<br>{1}</html>", file.getName(), ex.getMessage()), |
|---|
| 143 | tr("IO Error"), |
|---|
| 144 | JOptionPane.ERROR_MESSAGE, |
|---|
| 145 | null |
|---|
| 146 | ); |
|---|
| 147 | } |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | public class SessionSaveAsDialog extends ExtendedDialog { |
|---|
| 151 | |
|---|
| 152 | public SessionSaveAsDialog() { |
|---|
| 153 | super(Main.parent, tr("Save Session"), new String[] {tr("Cancel"), tr("Save As")}); |
|---|
| 154 | initialize(); |
|---|
| 155 | setButtonIcons(new String[] {"cancel", "save_as"}); |
|---|
| 156 | setDefaultButton(2); |
|---|
| 157 | setRememberWindowGeometry(getClass().getName() + ".geometry", |
|---|
| 158 | WindowGeometry.centerInWindow(Main.parent, new Dimension(350, 450))); |
|---|
| 159 | setContent(build(), false); |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | public void initialize() { |
|---|
| 163 | layers = new ArrayList<Layer>(Main.map.mapView.getAllLayersAsList()); |
|---|
| 164 | exporters = new HashMap<Layer, SessionLayerExporter>(); |
|---|
| 165 | dependencies = new MultiMap<Layer, Layer>(); |
|---|
| 166 | |
|---|
| 167 | Set<Layer> noExporter = new HashSet<Layer>(); |
|---|
| 168 | |
|---|
| 169 | for (Layer layer : layers) { |
|---|
| 170 | SessionLayerExporter exporter = SessionWriter.getSessionLayerExporter(layer); |
|---|
| 171 | if (exporter != null) { |
|---|
| 172 | exporters.put(layer, exporter); |
|---|
| 173 | Collection<Layer> deps = exporter.getDependencies(); |
|---|
| 174 | if (deps != null) { |
|---|
| 175 | dependencies.putAll(layer, deps); |
|---|
| 176 | } else { |
|---|
| 177 | dependencies.putVoid(layer); |
|---|
| 178 | } |
|---|
| 179 | } else { |
|---|
| 180 | noExporter.add(layer); |
|---|
| 181 | exporters.put(layer, null); |
|---|
| 182 | } |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | int numNoExporter = 0; |
|---|
| 186 | WHILE:while (numNoExporter != noExporter.size()) { |
|---|
| 187 | numNoExporter = noExporter.size(); |
|---|
| 188 | for (Layer layer : layers) { |
|---|
| 189 | if (noExporter.contains(layer)) continue; |
|---|
| 190 | for (Layer depLayer : dependencies.get(layer)) { |
|---|
| 191 | if (noExporter.contains(depLayer)) { |
|---|
| 192 | noExporter.add(layer); |
|---|
| 193 | exporters.put(layer, null); |
|---|
| 194 | break WHILE; |
|---|
| 195 | } |
|---|
| 196 | } |
|---|
| 197 | } |
|---|
| 198 | } |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | public Component build() { |
|---|
| 202 | JPanel p = new JPanel(new GridBagLayout()); |
|---|
| 203 | JPanel ip = new JPanel(new GridBagLayout()); |
|---|
| 204 | for (Layer layer : layers) { |
|---|
| 205 | JPanel wrapper = new JPanel(new GridBagLayout()); |
|---|
| 206 | wrapper.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED)); |
|---|
| 207 | Component exportPanel; |
|---|
| 208 | SessionLayerExporter exporter = exporters.get(layer); |
|---|
| 209 | if (exporter == null) { |
|---|
| 210 | if (!exporters.containsKey(layer)) throw new AssertionError(); |
|---|
| 211 | exportPanel = getDisabledExportPanel(layer); |
|---|
| 212 | } else { |
|---|
| 213 | exportPanel = exporter.getExportPanel(); |
|---|
| 214 | } |
|---|
| 215 | wrapper.add(exportPanel, GBC.std().fill(GBC.HORIZONTAL)); |
|---|
| 216 | ip.add(wrapper, GBC.eol().fill(GBC.HORIZONTAL).insets(2,2,4,2)); |
|---|
| 217 | } |
|---|
| 218 | ip.add(GBC.glue(0,1), GBC.eol().fill(GBC.VERTICAL)); |
|---|
| 219 | JScrollPane sp = new JScrollPane(ip); |
|---|
| 220 | sp.setBorder(BorderFactory.createEmptyBorder()); |
|---|
| 221 | p.add(sp, GBC.eol().fill()); |
|---|
| 222 | final JTabbedPane tabs = new JTabbedPane(); |
|---|
| 223 | tabs.addTab(tr("Layers"), p); |
|---|
| 224 | return tabs; |
|---|
| 225 | } |
|---|
| 226 | |
|---|
| 227 | protected Component getDisabledExportPanel(Layer layer) { |
|---|
| 228 | JPanel p = new JPanel(new GridBagLayout()); |
|---|
| 229 | JCheckBox include = new JCheckBox(); |
|---|
| 230 | include.setEnabled(false); |
|---|
| 231 | JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEFT); |
|---|
| 232 | lbl.setToolTipText(tr("No exporter for this layer")); |
|---|
| 233 | lbl.setEnabled(false); |
|---|
| 234 | p.add(include, GBC.std()); |
|---|
| 235 | p.add(lbl, GBC.std()); |
|---|
| 236 | p.add(GBC.glue(1,0), GBC.std().fill(GBC.HORIZONTAL)); |
|---|
| 237 | return p; |
|---|
| 238 | } |
|---|
| 239 | } |
|---|
| 240 | |
|---|
| 241 | } |
|---|