source: josm/trunk/src/org/openstreetmap/josm/actions/SessionSaveAsAction.java@ 11848

Last change on this file since 11848 was 11848, checked in by Don-vip, 7 years ago

fix #14613 - Special HTML characters not escaped in GUI error messages

  • Property svn:eol-style set to native
File size: 10.3 KB
RevLine 
[4685]1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
[5438]4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
[4685]5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.Component;
8import java.awt.Dimension;
9import java.awt.GridBagLayout;
10import java.awt.event.ActionEvent;
11import java.io.File;
12import java.io.IOException;
13import java.util.ArrayList;
[5438]14import java.util.Arrays;
[4685]15import java.util.Collection;
16import java.util.HashMap;
17import java.util.HashSet;
18import java.util.List;
19import java.util.Map;
20import java.util.Set;
21
22import javax.swing.BorderFactory;
23import javax.swing.JCheckBox;
24import javax.swing.JFileChooser;
25import javax.swing.JLabel;
26import javax.swing.JOptionPane;
27import javax.swing.JPanel;
28import javax.swing.JScrollPane;
29import javax.swing.JTabbedPane;
30import javax.swing.SwingConstants;
31import javax.swing.border.EtchedBorder;
32import javax.swing.filechooser.FileFilter;
33
34import org.openstreetmap.josm.Main;
35import org.openstreetmap.josm.gui.ExtendedDialog;
36import org.openstreetmap.josm.gui.HelpAwareOptionPane;
[9629]37import org.openstreetmap.josm.gui.MapFrame;
38import org.openstreetmap.josm.gui.MapFrameListener;
[4685]39import org.openstreetmap.josm.gui.layer.Layer;
[7578]40import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
[4685]41import org.openstreetmap.josm.io.session.SessionLayerExporter;
42import org.openstreetmap.josm.io.session.SessionWriter;
43import org.openstreetmap.josm.tools.GBC;
44import org.openstreetmap.josm.tools.MultiMap;
[8919]45import org.openstreetmap.josm.tools.UserCancelException;
[8404]46import org.openstreetmap.josm.tools.Utils;
[4685]47import org.openstreetmap.josm.tools.WindowGeometry;
48
[6245]49/**
50 * Saves a JOSM session
51 * @since 4685
52 */
[9629]53public class SessionSaveAsAction extends DiskAccessAction implements MapFrameListener {
[4685]54
[8308]55 private transient List<Layer> layers;
56 private transient Map<Layer, SessionLayerExporter> exporters;
57 private transient MultiMap<Layer, Layer> dependencies;
[4685]58
[6245]59 /**
60 * Constructs a new {@code SessionSaveAsAction}.
61 */
[4685]62 public SessionSaveAsAction() {
[9152]63 this(true, true);
64 }
65
66 /**
67 * Constructs a new {@code SessionSaveAsAction}.
68 * @param toolbar Register this action for the toolbar preferences?
69 * @param installAdapters False, if you don't want to install layer changed and selection changed adapters
70 */
71 protected SessionSaveAsAction(boolean toolbar, boolean installAdapters) {
[9173]72 super(tr("Save Session As..."), "session", tr("Save the current session to a new file."),
73 null, toolbar, "save_as-session", installAdapters);
[4685]74 putValue("help", ht("/Action/SessionSaveAs"));
[9629]75 Main.addMapFrameListener(this);
[4685]76 }
77
78 @Override
79 public void actionPerformed(ActionEvent e) {
[8913]80 try {
81 saveSession();
[8919]82 } catch (UserCancelException ignore) {
[10420]83 Main.trace(ignore);
[8913]84 }
85 }
86
87 /**
88 * Attempts to save the session.
[8919]89 * @throws UserCancelException when the user has cancelled the save process.
[8913]90 * @since 8913
91 */
[8919]92 public void saveSession() throws UserCancelException {
[4685]93 if (!isEnabled()) {
94 return;
95 }
96
97 SessionSaveAsDialog dlg = new SessionSaveAsDialog();
98 dlg.showDialog();
[8913]99 if (dlg.getValue() != 1) {
[8919]100 throw new UserCancelException();
[8913]101 }
[4685]102
[6267]103 boolean zipRequired = false;
[4685]104 for (Layer l : layers) {
105 SessionLayerExporter ex = exporters.get(l);
[5501]106 if (ex != null && ex.requiresZip()) {
[4685]107 zipRequired = true;
108 break;
109 }
110 }
[6069]111
[4685]112 FileFilter joz = new ExtensionFileFilter("joz", "joz", tr("Session file (archive) (*.joz)"));
113 FileFilter jos = new ExtensionFileFilter("jos", "jos", tr("Session file (*.jos)"));
[5438]114
[7578]115 AbstractFileChooser fc;
[5505]116
[4685]117 if (zipRequired) {
[5438]118 fc = createAndOpenFileChooser(false, false, tr("Save session"), joz, JFileChooser.FILES_ONLY, "lastDirectory");
[4685]119 } else {
[8509]120 fc = createAndOpenFileChooser(false, false, tr("Save session"), Arrays.asList(new FileFilter[]{jos, joz}), jos,
121 JFileChooser.FILES_ONLY, "lastDirectory");
[4685]122 }
[5438]123
[8913]124 if (fc == null) {
[8919]125 throw new UserCancelException();
[8913]126 }
[4685]127
128 File file = fc.getSelectedFile();
129 String fn = file.getName();
130
131 boolean zip;
132 FileFilter ff = fc.getFileFilter();
[11109]133 if (zipRequired || joz.equals(ff)) {
[4685]134 zip = true;
[6981]135 } else if (jos.equals(ff)) {
[4685]136 zip = false;
137 } else {
[8404]138 if (Utils.hasExtension(fn, "joz")) {
[4685]139 zip = true;
140 } else {
141 zip = false;
142 }
143 }
144 if (fn.indexOf('.') == -1) {
145 file = new File(file.getPath() + (zip ? ".joz" : ".jos"));
[8913]146 if (!SaveActionBase.confirmOverwrite(file)) {
[8919]147 throw new UserCancelException();
[8913]148 }
[4685]149 }
150
[7005]151 List<Layer> layersOut = new ArrayList<>();
[4685]152 for (Layer layer : layers) {
153 if (exporters.get(layer) == null || !exporters.get(layer).shallExport()) continue;
154 // TODO: resolve dependencies for layers excluded by the user
155 layersOut.add(layer);
156 }
[7509]157
[6271]158 int active = -1;
[10318]159 Layer activeLayer = Main.getLayerManager().getActiveLayer();
[6271]160 if (activeLayer != null) {
161 active = layersOut.indexOf(activeLayer);
162 }
[4685]163
[6271]164 SessionWriter sw = new SessionWriter(layersOut, active, exporters, dependencies, zip);
[4685]165 try {
166 sw.write(file);
[8802]167 SaveActionBase.addToFileOpenHistory(file);
[4685]168 } catch (IOException ex) {
[6643]169 Main.error(ex);
[4685]170 HelpAwareOptionPane.showMessageDialogInEDT(
171 Main.parent,
[11848]172 tr("<html>Could not save session file ''{0}''.<br>Error is:<br>{1}</html>",
173 file.getName(), Utils.escapeReservedCharactersHTML(ex.getMessage())),
[4685]174 tr("IO Error"),
175 JOptionPane.ERROR_MESSAGE,
176 null
177 );
178 }
179 }
180
[6245]181 /**
182 * The "Save Session" dialog
183 */
[4685]184 public class SessionSaveAsDialog extends ExtendedDialog {
185
[6245]186 /**
187 * Constructs a new {@code SessionSaveAsDialog}.
188 */
[4685]189 public SessionSaveAsDialog() {
[5684]190 super(Main.parent, tr("Save Session"), new String[] {tr("Save As"), tr("Cancel")});
[4685]191 initialize();
[5684]192 setButtonIcons(new String[] {"save_as", "cancel"});
193 setDefaultButton(1);
[4685]194 setRememberWindowGeometry(getClass().getName() + ".geometry",
195 WindowGeometry.centerInWindow(Main.parent, new Dimension(350, 450)));
196 setContent(build(), false);
197 }
198
[6271]199 /**
200 * Initializes action.
201 */
[6890]202 public final void initialize() {
[10318]203 layers = new ArrayList<>(Main.getLayerManager().getLayers());
[7005]204 exporters = new HashMap<>();
205 dependencies = new MultiMap<>();
[4685]206
[7005]207 Set<Layer> noExporter = new HashSet<>();
[4685]208
209 for (Layer layer : layers) {
210 SessionLayerExporter exporter = SessionWriter.getSessionLayerExporter(layer);
211 if (exporter != null) {
212 exporters.put(layer, exporter);
213 Collection<Layer> deps = exporter.getDependencies();
214 if (deps != null) {
215 dependencies.putAll(layer, deps);
216 } else {
217 dependencies.putVoid(layer);
218 }
219 } else {
220 noExporter.add(layer);
221 exporters.put(layer, null);
222 }
223 }
224
225 int numNoExporter = 0;
[8510]226 WHILE: while (numNoExporter != noExporter.size()) {
[4685]227 numNoExporter = noExporter.size();
228 for (Layer layer : layers) {
229 if (noExporter.contains(layer)) continue;
230 for (Layer depLayer : dependencies.get(layer)) {
231 if (noExporter.contains(depLayer)) {
232 noExporter.add(layer);
233 exporters.put(layer, null);
234 break WHILE;
235 }
236 }
237 }
238 }
239 }
240
[6890]241 protected final Component build() {
[4685]242 JPanel ip = new JPanel(new GridBagLayout());
243 for (Layer layer : layers) {
244 JPanel wrapper = new JPanel(new GridBagLayout());
245 wrapper.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
246 Component exportPanel;
247 SessionLayerExporter exporter = exporters.get(layer);
248 if (exporter == null) {
249 if (!exporters.containsKey(layer)) throw new AssertionError();
250 exportPanel = getDisabledExportPanel(layer);
251 } else {
252 exportPanel = exporter.getExportPanel();
253 }
254 wrapper.add(exportPanel, GBC.std().fill(GBC.HORIZONTAL));
[8510]255 ip.add(wrapper, GBC.eol().fill(GBC.HORIZONTAL).insets(2, 2, 4, 2));
[4685]256 }
[8510]257 ip.add(GBC.glue(0, 1), GBC.eol().fill(GBC.VERTICAL));
[4685]258 JScrollPane sp = new JScrollPane(ip);
259 sp.setBorder(BorderFactory.createEmptyBorder());
[9062]260 JPanel p = new JPanel(new GridBagLayout());
[4685]261 p.add(sp, GBC.eol().fill());
262 final JTabbedPane tabs = new JTabbedPane();
263 tabs.addTab(tr("Layers"), p);
264 return tabs;
265 }
266
[6981]267 protected final Component getDisabledExportPanel(Layer layer) {
[4685]268 JPanel p = new JPanel(new GridBagLayout());
269 JCheckBox include = new JCheckBox();
270 include.setEnabled(false);
271 JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEFT);
272 lbl.setToolTipText(tr("No exporter for this layer"));
[8426]273 lbl.setLabelFor(include);
[4685]274 lbl.setEnabled(false);
275 p.add(include, GBC.std());
276 p.add(lbl, GBC.std());
[8510]277 p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
[4685]278 return p;
279 }
280 }
281
[6149]282 @Override
283 protected void updateEnabledState() {
284 setEnabled(Main.isDisplayingMapView());
285 }
[9629]286
287 @Override
288 public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
289 updateEnabledState();
[9631]290 }
[4685]291}
Note: See TracBrowser for help on using the repository browser.