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

Last change on this file since 16509 was 16509, checked in by GerdP, 4 years ago

see #19296: Actions should avoid to install listeners which are not needed

  • either don't call installAdapters() or overwrite listenToSelectionChange()
  • partly reverts previous changes so that installAdapters() is not overwritten

One has to be careful because installAdapters() also calls initEnabledState()

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