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

Last change on this file since 12894 was 12894, checked in by bastiK, 18 months ago

see #15229 - update method name and signature for consistency

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