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

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

see #16709 - fix #20755 - Display a notification while/after saving session files

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