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

Last change on this file since 7748 was 7578, checked in by Don-vip, 10 years ago

fix #10024 - Add an option in Preferences/Look-and-Feel to use native file-choosing dialogs.
They look nicer but they do not support file filters, so we cannot use them (yet) as default.
Based on patch by Lesath and code review by simon04.
The native dialogs are not used if selection mode is not supported ("files and directories" on all platforms, "directories" on systems other than OS X)

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