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

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

javadoc, findbugs

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