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

Last change on this file since 8332 was 8248, checked in by Don-vip, 9 years ago

fix #11362 - do not confirm overwrite for OSX native file dialogs which already ask for it

  • Property svn:eol-style set to native
File size: 7.8 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.util.Collection;
10import java.util.LinkedList;
11import java.util.List;
12
13import javax.swing.JFileChooser;
14import javax.swing.JOptionPane;
15import javax.swing.filechooser.FileFilter;
16
17import org.openstreetmap.josm.Main;
18import org.openstreetmap.josm.gui.ExtendedDialog;
19import org.openstreetmap.josm.gui.layer.Layer;
20import org.openstreetmap.josm.gui.layer.OsmDataLayer;
21import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
22import org.openstreetmap.josm.gui.widgets.FileChooserManager;
23import org.openstreetmap.josm.io.FileExporter;
24import org.openstreetmap.josm.tools.Shortcut;
25
26public abstract class SaveActionBase extends DiskAccessAction {
27 private File file;
28
29 public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut) {
30 super(name, iconName, tooltip, shortcut);
31 }
32
33 @Override
34 public void actionPerformed(ActionEvent e) {
35 if (!isEnabled())
36 return;
37 boolean saved = doSave();
38 if (saved) {
39 addToFileOpenHistory();
40 }
41 }
42
43 public boolean doSave() {
44 if (Main.isDisplayingMapView()) {
45 Layer layer = Main.map.mapView.getActiveLayer();
46 if (layer != null && layer.isSavable()) {
47 return doSave(layer);
48 }
49 }
50 return false;
51 }
52
53 public boolean doSave(Layer layer) {
54 if(!layer.checkSaveConditions())
55 return false;
56 file = getFile(layer);
57 return doInternalSave(layer, file);
58 }
59
60 /**
61 * Saves a layer to a given file.
62 * @param layer The layer to save
63 * @param file The destination file
64 * @param checkSaveConditions if {@code true}, checks preconditions before saving. Set it to {@code false} to skip it
65 * if preconditions have already been checked (as this check can prompt UI dialog in EDT it may be best in some cases
66 * to do it earlier).
67 * @return {@code true} if the layer has been successfully saved, {@code false} otherwise
68 * @since 7204
69 */
70 public static boolean doSave(Layer layer, File file, boolean checkSaveConditions) {
71 if (checkSaveConditions && !layer.checkSaveConditions())
72 return false;
73 return doInternalSave(layer, file);
74 }
75
76 private static boolean doInternalSave(Layer layer, File file) {
77 if (file == null)
78 return false;
79
80 try {
81 boolean exported = false;
82 boolean canceled = false;
83 for (FileExporter exporter : ExtensionFileFilter.exporters) {
84 if (exporter.acceptFile(file, layer)) {
85 exporter.exportData(file, layer);
86 exported = true;
87 canceled = exporter.isCanceled();
88 break;
89 }
90 }
91 if (!exported) {
92 JOptionPane.showMessageDialog(Main.parent, tr("No Exporter found! Nothing saved."), tr("Warning"),
93 JOptionPane.WARNING_MESSAGE);
94 return false;
95 } else if (canceled) {
96 return false;
97 }
98 layer.setName(file.getName());
99 layer.setAssociatedFile(file);
100 if (layer instanceof OsmDataLayer) {
101 ((OsmDataLayer) layer).onPostSaveToFile();
102 }
103 Main.parent.repaint();
104 } catch (IOException e) {
105 Main.error(e);
106 return false;
107 }
108 return true;
109 }
110
111 protected abstract File getFile(Layer layer);
112
113 /**
114 * Refreshes the enabled state
115 *
116 */
117 @Override
118 protected void updateEnabledState() {
119 boolean check = Main.isDisplayingMapView()
120 && Main.map.mapView.getActiveLayer() != null;
121 if(!check) {
122 setEnabled(false);
123 return;
124 }
125 Layer layer = Main.map.mapView.getActiveLayer();
126 setEnabled(layer != null && layer.isSavable());
127 }
128
129 /**
130 * Creates a new "Save" dialog for a single {@link ExtensionFileFilter} and makes it visible.<br>
131 * When the user has chosen a file, checks the file extension, and confirms overwrite if needed.
132 *
133 * @param title The dialog title
134 * @param filter The dialog file filter
135 * @return The output {@code File}
136 * @since 5456
137 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
138 */
139 public static File createAndOpenSaveFileChooser(String title, ExtensionFileFilter filter) {
140 AbstractFileChooser fc = createAndOpenFileChooser(false, false, title, filter, JFileChooser.FILES_ONLY, null);
141 return checkFileAndConfirmOverWrite(fc, filter.getDefaultExtension());
142 }
143
144 /**
145 * Creates a new "Save" dialog for a given file extension and makes it visible.<br>
146 * When the user has chosen a file, checks the file extension, and confirms overwrite if needed.
147 *
148 * @param title The dialog title
149 * @param extension The file extension
150 * @return The output {@code File}
151 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, String)
152 */
153 public static File createAndOpenSaveFileChooser(String title, String extension) {
154 AbstractFileChooser fc = createAndOpenFileChooser(false, false, title, extension);
155 return checkFileAndConfirmOverWrite(fc, extension);
156 }
157
158 private static File checkFileAndConfirmOverWrite(AbstractFileChooser fc, String extension) {
159 if (fc == null) return null;
160 File file = fc.getSelectedFile();
161
162 FileFilter ff = fc.getFileFilter();
163 if (!ff.accept(file)) {
164 // Extension of another filefilter given ?
165 for (FileFilter cff : fc.getChoosableFileFilters()) {
166 if (cff.accept(file)) {
167 fc.setFileFilter(cff);
168 return file;
169 }
170 }
171 // No filefilter accepts current filename, add default extension
172 String fn = file.getPath();
173 if (ff instanceof ExtensionFileFilter) {
174 fn += "." + ((ExtensionFileFilter)ff).getDefaultExtension();
175 } else if (extension != null) {
176 fn += "." + extension;
177 }
178 file = new File(fn);
179 // Confirm overwrite, except for OSX native file dialogs which already ask for confirmation (see #11362)
180 if (!(Main.isPlatformOsx() && FileChooserManager.PROP_USE_NATIVE_FILE_DIALOG.get()) && !confirmOverwrite(file))
181 return null;
182 }
183 return file;
184 }
185
186 public static boolean confirmOverwrite(File file) {
187 if (file == null || (file.exists())) {
188 ExtendedDialog dialog = new ExtendedDialog(
189 Main.parent,
190 tr("Overwrite"),
191 new String[] {tr("Overwrite"), tr("Cancel")}
192 );
193 dialog.setContent(tr("File exists. Overwrite?"));
194 dialog.setButtonIcons(new String[] {"save_as", "cancel"});
195 dialog.showDialog();
196 return (dialog.getValue() == 1);
197 }
198 return true;
199 }
200
201 protected void addToFileOpenHistory() {
202 String filepath;
203 try {
204 filepath = file.getCanonicalPath();
205 } catch (IOException ign) {
206 return;
207 }
208
209 int maxsize = Math.max(0, Main.pref.getInteger("file-open.history.max-size", 15));
210 Collection<String> oldHistory = Main.pref.getCollection("file-open.history");
211 List<String> history = new LinkedList<>(oldHistory);
212 history.remove(filepath);
213 history.add(0, filepath);
214 Main.pref.putCollectionBounded("file-open.history", maxsize, history);
215 }
216}
Note: See TracBrowser for help on using the repository browser.