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

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

fix #10086 - fix EDT violation causing freeze of Save/upload dialog for empty or conflicting layers

  • 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.io.FileExporter;
22import org.openstreetmap.josm.tools.Shortcut;
23
24public abstract class SaveActionBase extends DiskAccessAction {
25 private File file;
26
27 public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut) {
28 super(name, iconName, tooltip, shortcut);
29 }
30
31 @Override
32 public void actionPerformed(ActionEvent e) {
33 if (!isEnabled())
34 return;
35 boolean saved = doSave();
36 if (saved) {
37 addToFileOpenHistory();
38 }
39 }
40
41 public boolean doSave() {
42 if (Main.isDisplayingMapView()) {
43 Layer layer = Main.map.mapView.getActiveLayer();
44 if (layer != null && layer.isSavable()) {
45 return doSave(layer);
46 }
47 }
48 return false;
49 }
50
51 public boolean doSave(Layer layer) {
52 if(!layer.checkSaveConditions())
53 return false;
54 file = getFile(layer);
55 return doInternalSave(layer, file);
56 }
57
58 /**
59 * Saves a layer to a given file.
60 * @param layer The layer to save
61 * @param file The destination file
62 * @param checkSaveConditions if {@code true}, checks preconditions before saving. Set it to {@code false} to skip it
63 * if preconditions have already been checked (as this check can prompt UI dialog in EDT it may be best in some cases
64 * to do it earlier).
65 * @return {@code true} if the layer has been successfully saved, {@code false} otherwise
66 * @since 7204
67 */
68 public static boolean doSave(Layer layer, File file, boolean checkSaveConditions) {
69 if (checkSaveConditions && !layer.checkSaveConditions())
70 return false;
71 return doInternalSave(layer, file);
72 }
73
74 private static boolean doInternalSave(Layer layer, File file) {
75 if (file == null)
76 return false;
77
78 try {
79 boolean exported = false;
80 boolean canceled = false;
81 for (FileExporter exporter : ExtensionFileFilter.exporters) {
82 if (exporter.acceptFile(file, layer)) {
83 exporter.exportData(file, layer);
84 exported = true;
85 canceled = exporter.isCanceled();
86 break;
87 }
88 }
89 if (!exported) {
90 JOptionPane.showMessageDialog(Main.parent, tr("No Exporter found! Nothing saved."), tr("Warning"),
91 JOptionPane.WARNING_MESSAGE);
92 return false;
93 } else if (canceled) {
94 return false;
95 }
96 layer.setName(file.getName());
97 layer.setAssociatedFile(file);
98 if (layer instanceof OsmDataLayer) {
99 ((OsmDataLayer) layer).onPostSaveToFile();
100 }
101 Main.parent.repaint();
102 } catch (IOException e) {
103 Main.error(e);
104 return false;
105 }
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 * @since 5456
135 * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
136 */
137 public static File createAndOpenSaveFileChooser(String title, ExtensionFileFilter filter) {
138 JFileChooser 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 JFileChooser fc = createAndOpenFileChooser(false, false, title, extension);
153 return checkFileAndConfirmOverWrite(fc, extension);
154 }
155
156 private static File checkFileAndConfirmOverWrite(JFileChooser 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 (ff instanceof ExtensionFileFilter) {
172 fn += "." + ((ExtensionFileFilter)ff).getDefaultExtension();
173 } else if (extension != null) {
174 fn += "." + extension;
175 }
176 file = new File(fn);
177 if (!confirmOverwrite(file))
178 return null;
179 }
180 return file;
181 }
182
183 public static boolean confirmOverwrite(File file) {
184 if (file == null || (file.exists())) {
185 ExtendedDialog dialog = new ExtendedDialog(
186 Main.parent,
187 tr("Overwrite"),
188 new String[] {tr("Overwrite"), tr("Cancel")}
189 );
190 dialog.setContent(tr("File exists. Overwrite?"));
191 dialog.setButtonIcons(new String[] {"save_as.png", "cancel.png"});
192 dialog.showDialog();
193 return (dialog.getValue() == 1);
194 }
195 return true;
196 }
197
198 protected void addToFileOpenHistory() {
199 String filepath;
200 try {
201 filepath = file.getCanonicalPath();
202 } catch (IOException ign) {
203 return;
204 }
205
206 int maxsize = Math.max(0, Main.pref.getInteger("file-open.history.max-size", 15));
207 Collection<String> oldHistory = Main.pref.getCollection("file-open.history");
208 List<String> history = new LinkedList<>(oldHistory);
209 history.remove(filepath);
210 history.add(0, filepath);
211 Main.pref.putCollectionBounded("file-open.history", maxsize, history);
212 }
213}
Note: See TracBrowser for help on using the repository browser.