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

Last change on this file since 14628 was 14470, checked in by GerdP, 5 years ago

see #17040 Fix various memory leaks
Not sure if this will break Unit tests. Many of them don't work on my PC with a clean copy.

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