source: josm/trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java@ 17379

Last change on this file since 17379 was 16827, checked in by Klumbumbus, 4 years ago

see #15240 - Change a lot png icons to svg:

  • 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.tools.I18n.tr;
5
6import java.awt.event.ActionEvent;
7import java.io.File;
8import java.io.IOException;
9import java.nio.file.InvalidPathException;
10import java.util.Collection;
11import java.util.LinkedList;
12import java.util.List;
13
14import javax.swing.JFileChooser;
15import javax.swing.JOptionPane;
16import javax.swing.filechooser.FileFilter;
17
18import org.openstreetmap.josm.data.PreferencesUtils;
19import org.openstreetmap.josm.gui.ExtendedDialog;
20import org.openstreetmap.josm.gui.MainApplication;
21import org.openstreetmap.josm.gui.io.importexport.FileExporter;
22import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
23import org.openstreetmap.josm.gui.layer.Layer;
24import org.openstreetmap.josm.gui.util.GuiHelper;
25import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
26import org.openstreetmap.josm.spi.preferences.Config;
27import org.openstreetmap.josm.tools.Logging;
28import org.openstreetmap.josm.tools.Shortcut;
29import org.openstreetmap.josm.tools.Utils;
30
31/**
32 * Abstract superclass of save actions.
33 * @since 290
34 */
35public abstract class SaveActionBase extends DiskAccessAction {
36
37 private boolean quiet;
38
39 /**
40 * Constructs a new {@code SaveActionBase}.
41 * @param name The action's text as displayed on the menu (if it is added to a menu)
42 * @param iconName The filename of the icon to use
43 * @param tooltip A longer description of the action that will be displayed in the tooltip
44 * @param shortcut A ready-created shortcut object or {@code null} if you don't want a shortcut
45 */
46 protected SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut) {
47 super(name, iconName, tooltip, shortcut);
48 }
49
50 /**
51 * Constructs a new {@code SaveActionBase}.
52 * @param name The action's text as displayed on the menu (if it is added to a menu)
53 * @param iconName The filename of the icon to use
54 * @param tooltip A longer description of the action that will be displayed in the tooltip
55 * @param shortcut A ready-created shortcut object or {@code null} if you don't want a shortcut
56 * @param quiet whether the quiet exporter is called
57 * @since 15496
58 */
59 protected SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut, boolean quiet) {
60 super(name, iconName, tooltip, shortcut);
61 this.quiet = quiet;
62 }
63
64 @Override
65 public void actionPerformed(ActionEvent e) {
66 if (!isEnabled())
67 return;
68 doSave(quiet);
69 }
70
71 /**
72 * Saves the active layer.
73 * @return {@code true} if the save operation succeeds
74 */
75 public boolean doSave() {
76 return doSave(false);
77 }
78
79 /**
80 * Saves the active layer.
81 * @param quiet If the file is saved without prompting the user
82 * @return {@code true} if the save operation succeeds
83 * @since 15496
84 */
85 public boolean doSave(boolean quiet) {
86 Layer layer = getLayerManager().getActiveLayer();
87 if (layer != null && layer.isSavable()) {
88 return doSave(layer, quiet);
89 }
90 return false;
91 }
92
93 /**
94 * Saves the given layer.
95 * @param layer layer to save
96 * @return {@code true} if the save operation succeeds
97 */
98 public boolean doSave(Layer layer) {
99 return doSave(layer, false);
100 }
101
102 /**
103 * Saves the given layer.
104 * @param layer layer to save
105 * @param quiet If the file is saved without prompting the user
106 * @return {@code true} if the save operation succeeds
107 * @since 15496
108 */
109 public boolean doSave(Layer layer, boolean quiet) {
110 if (!layer.checkSaveConditions())
111 return false;
112 final boolean result = doInternalSave(layer, getFile(layer), quiet);
113 updateEnabledState();
114 return result;
115 }
116
117 /**
118 * Saves a layer to a given file.
119 * @param layer The layer to save
120 * @param file The destination file
121 * @param checkSaveConditions if {@code true}, checks preconditions before saving. Set it to {@code false} to skip it
122 * and prevent dialogs from being shown.
123 * @return {@code true} if the layer has been successfully saved, {@code false} otherwise
124 * @since 7204
125 */
126 public static boolean doSave(Layer layer, File file, boolean checkSaveConditions) {
127 if (checkSaveConditions && !layer.checkSaveConditions())
128 return false;
129 return doInternalSave(layer, file, !checkSaveConditions);
130 }
131
132 private static boolean doInternalSave(Layer layer, File file, boolean quiet) {
133 if (file == null)
134 return false;
135
136 try {
137 boolean exported = false;
138 boolean canceled = false;
139 for (FileExporter exporter : ExtensionFileFilter.getExporters()) {
140 if (exporter.acceptFile(file, layer)) {
141 if (quiet) {
142 exporter.exportDataQuiet(file, layer);
143 } else {
144 exporter.exportData(file, layer);
145 }
146 exported = true;
147 canceled = exporter.isCanceled();
148 break;
149 }
150 }
151 if (!exported) {
152 GuiHelper.runInEDT(() ->
153 JOptionPane.showMessageDialog(MainApplication.getMainFrame(), tr("No Exporter found! Nothing saved."), tr("Warning"),
154 JOptionPane.WARNING_MESSAGE));
155 return false;
156 } else if (canceled) {
157 return false;
158 }
159 if (!layer.isRenamed()) {
160 layer.setName(file.getName());
161 }
162 layer.setAssociatedFile(file);
163 if (layer instanceof AbstractModifiableLayer) {
164 ((AbstractModifiableLayer) layer).onPostSaveToFile();
165 }
166 } catch (IOException | InvalidPathException e) {
167 showAndLogException(e);
168 return false;
169 }
170 addToFileOpenHistory(file);
171 return true;
172 }
173
174 protected abstract File getFile(Layer layer);
175
176 @Override
177 protected boolean listenToSelectionChange() {
178 return false;
179 }
180
181 @Override
182 protected void updateEnabledState() {
183 Layer activeLayer = getLayerManager().getActiveLayer();
184 setEnabled(activeLayer != null && activeLayer.isSavable());
185 }
186
187 /**
188 * Creates a new "Save" dialog for a single {@link ExtensionFileFilter} and makes it visible.<br>
189 * When the user has chosen a file, checks the file extension, and confirms overwrite if needed.
190 *
191 * @param title The dialog title
192 * @param filter The dialog file filter
193 * @return The output {@code File}
194 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
195 * @since 5456
196 */
197 public static File createAndOpenSaveFileChooser(String title, ExtensionFileFilter filter) {
198 AbstractFileChooser fc = createAndOpenFileChooser(false, false, title, filter, JFileChooser.FILES_ONLY, null);
199 return checkFileAndConfirmOverWrite(fc, filter.getDefaultExtension());
200 }
201
202 /**
203 * Creates a new "Save" dialog for a given file extension and makes it visible.<br>
204 * When the user has chosen a file, checks the file extension, and confirms overwrite if needed.
205 *
206 * @param title The dialog title
207 * @param extension The file extension
208 * @return The output {@code File}
209 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, String)
210 */
211 public static File createAndOpenSaveFileChooser(String title, String extension) {
212 AbstractFileChooser fc = createAndOpenFileChooser(false, false, title, extension);
213 return checkFileAndConfirmOverWrite(fc, extension);
214 }
215
216 /**
217 * Checks if selected filename has the given extension. If not, adds the extension and asks for overwrite if filename exists.
218 *
219 * @param fc FileChooser where file was already selected
220 * @param extension file extension
221 * @return the {@code File} or {@code null} if the user cancelled the dialog.
222 */
223 public static File checkFileAndConfirmOverWrite(AbstractFileChooser fc, String extension) {
224 if (fc == null)
225 return null;
226 File file = fc.getSelectedFile();
227
228 FileFilter ff = fc.getFileFilter();
229 if (!ff.accept(file)) {
230 // Extension of another filefilter given ?
231 for (FileFilter cff : fc.getChoosableFileFilters()) {
232 if (cff.accept(file)) {
233 fc.setFileFilter(cff);
234 return file;
235 }
236 }
237 // No filefilter accepts current filename, add default extension
238 String fn = file.getPath();
239 if (extension != null && ff.accept(new File(fn + '.' + extension))) {
240 fn += '.' + extension;
241 } else if (ff instanceof ExtensionFileFilter) {
242 fn += '.' + ((ExtensionFileFilter) ff).getDefaultExtension();
243 }
244 file = new File(fn);
245 if (!fc.getSelectedFile().exists() && !confirmOverwrite(file))
246 return null;
247 }
248 return file;
249 }
250
251 /**
252 * Asks user to confirm overwiting a file.
253 * @param file file to overwrite
254 * @return {@code true} if the file can be written
255 */
256 public static boolean confirmOverwrite(File file) {
257 if (file == null || file.exists()) {
258 return new ExtendedDialog(
259 MainApplication.getMainFrame(),
260 tr("Overwrite"),
261 tr("Overwrite"), tr("Cancel"))
262 .setContent(tr("File exists. Overwrite?"))
263 .setButtonIcons("save", "cancel")
264 .showDialog()
265 .getValue() == 1;
266 }
267 return true;
268 }
269
270 static void addToFileOpenHistory(File file) {
271 final String filepath;
272 try {
273 filepath = file.getCanonicalPath();
274 } catch (IOException ign) {
275 Logging.warn(ign);
276 return;
277 }
278
279 int maxsize = Math.max(0, Config.getPref().getInt("file-open.history.max-size", 15));
280 Collection<String> oldHistory = Config.getPref().getList("file-open.history");
281 List<String> history = new LinkedList<>(oldHistory);
282 history.remove(filepath);
283 history.add(0, filepath);
284 PreferencesUtils.putListBounded(Config.getPref(), "file-open.history", maxsize, history);
285 }
286
287 static void showAndLogException(Exception e) {
288 GuiHelper.runInEDT(() ->
289 JOptionPane.showMessageDialog(
290 MainApplication.getMainFrame(),
291 tr("<html>An error occurred while saving.<br>Error is:<br>{0}</html>",
292 Utils.escapeReservedCharactersHTML(e.getClass().getSimpleName() + " - " + e.getMessage())),
293 tr("Error"),
294 JOptionPane.ERROR_MESSAGE
295 ));
296
297 Logging.error(e);
298 }
299}
Note: See TracBrowser for help on using the repository browser.