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

Last change on this file since 12671 was 12671, checked in by Don-vip, 4 months ago

see #15182 - move file importers/exporters from io package to gui.io.importexport package, as they rely heavily on GUI and are mainly used from Open/Save actions

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