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

Last change on this file since 9466 was 9466, checked in by bastiK, 8 years ago

see #12370, see #12369 - fix problems with default file extension (patch by kolesar)
[patch] adapted osm file filter to other file types

  • 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 doSave();
38 }
39
40 public boolean doSave() {
41 if (Main.isDisplayingMapView()) {
42 Layer layer = Main.map.mapView.getActiveLayer();
43 if (layer != null && layer.isSavable()) {
44 return doSave(layer);
45 }
46 }
47 return false;
48 }
49
50 public boolean doSave(Layer layer) {
51 if (!layer.checkSaveConditions())
52 return false;
53 file = getFile(layer);
54 return doInternalSave(layer, file);
55 }
56
57 /**
58 * Saves a layer to a given file.
59 * @param layer The layer to save
60 * @param file The destination file
61 * @param checkSaveConditions if {@code true}, checks preconditions before saving. Set it to {@code false} to skip it
62 * if preconditions have already been checked (as this check can prompt UI dialog in EDT it may be best in some cases
63 * to do it earlier).
64 * @return {@code true} if the layer has been successfully saved, {@code false} otherwise
65 * @since 7204
66 */
67 public static boolean doSave(Layer layer, File file, boolean checkSaveConditions) {
68 if (checkSaveConditions && !layer.checkSaveConditions())
69 return false;
70 return doInternalSave(layer, file);
71 }
72
73 private static boolean doInternalSave(Layer layer, File file) {
74 if (file == null)
75 return false;
76
77 try {
78 boolean exported = false;
79 boolean canceled = false;
80 for (FileExporter exporter : ExtensionFileFilter.exporters) {
81 if (exporter.acceptFile(file, layer)) {
82 exporter.exportData(file, layer);
83 exported = true;
84 canceled = exporter.isCanceled();
85 break;
86 }
87 }
88 if (!exported) {
89 JOptionPane.showMessageDialog(Main.parent, tr("No Exporter found! Nothing saved."), tr("Warning"),
90 JOptionPane.WARNING_MESSAGE);
91 return false;
92 } else if (canceled) {
93 return false;
94 }
95 layer.setName(file.getName());
96 layer.setAssociatedFile(file);
97 if (layer instanceof OsmDataLayer) {
98 ((OsmDataLayer) layer).onPostSaveToFile();
99 }
100 Main.parent.repaint();
101 } catch (IOException e) {
102 Main.error(e);
103 return false;
104 }
105 addToFileOpenHistory(file);
106 return true;
107 }
108
109 protected abstract File getFile(Layer layer);
110
111 /**
112 * Refreshes the enabled state
113 *
114 */
115 @Override
116 protected void updateEnabledState() {
117 boolean check = Main.isDisplayingMapView()
118 && Main.map.mapView.getActiveLayer() != null;
119 if (!check) {
120 setEnabled(false);
121 return;
122 }
123 Layer layer = Main.map.mapView.getActiveLayer();
124 setEnabled(layer != null && layer.isSavable());
125 }
126
127 /**
128 * Creates a new "Save" dialog for a single {@link ExtensionFileFilter} and makes it visible.<br>
129 * When the user has chosen a file, checks the file extension, and confirms overwrite if needed.
130 *
131 * @param title The dialog title
132 * @param filter The dialog file filter
133 * @return The output {@code File}
134 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
135 * @since 5456
136 */
137 public static File createAndOpenSaveFileChooser(String title, ExtensionFileFilter filter) {
138 AbstractFileChooser fc = createAndOpenFileChooser(false, false, title, filter, JFileChooser.FILES_ONLY, null);
139 return checkFileAndConfirmOverWrite(fc, filter.getDefaultExtension());
140 }
141
142 /**
143 * Creates a new "Save" dialog for a given file extension and makes it visible.<br>
144 * When the user has chosen a file, checks the file extension, and confirms overwrite if needed.
145 *
146 * @param title The dialog title
147 * @param extension The file extension
148 * @return The output {@code File}
149 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, String)
150 */
151 public static File createAndOpenSaveFileChooser(String title, String extension) {
152 AbstractFileChooser fc = createAndOpenFileChooser(false, false, title, extension);
153 return checkFileAndConfirmOverWrite(fc, extension);
154 }
155
156 private static File checkFileAndConfirmOverWrite(AbstractFileChooser fc, String extension) {
157 if (fc == null) return null;
158 File file = fc.getSelectedFile();
159
160 FileFilter ff = fc.getFileFilter();
161 if (!ff.accept(file)) {
162 // Extension of another filefilter given ?
163 for (FileFilter cff : fc.getChoosableFileFilters()) {
164 if (cff.accept(file)) {
165 fc.setFileFilter(cff);
166 return file;
167 }
168 }
169 // No filefilter accepts current filename, add default extension
170 String fn = file.getPath();
171 if (extension != null) {
172 fn += '.' + extension;
173 } else if (ff instanceof ExtensionFileFilter) {
174 fn += '.' + ((ExtensionFileFilter) ff).getDefaultExtension();
175 }
176 file = new File(fn);
177 // Confirm overwrite, except for OSX native file dialogs which already ask for confirmation (see #11362)
178 if (!(Main.isPlatformOsx() && FileChooserManager.PROP_USE_NATIVE_FILE_DIALOG.get()) && !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", "cancel"});
193 dialog.showDialog();
194 return dialog.getValue() == 1;
195 }
196 return true;
197 }
198
199 static void addToFileOpenHistory(File file) {
200 final 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.