001    //License: GPL. Copyright 2007 by Immanuel Scholz and others
002    package org.openstreetmap.josm.actions;
003    
004    import static org.openstreetmap.josm.tools.I18n.tr;
005    
006    import java.awt.event.ActionEvent;
007    import java.io.File;
008    import java.io.IOException;
009    import java.util.Collection;
010    import java.util.LinkedList;
011    import java.util.List;
012    
013    import javax.swing.JFileChooser;
014    import javax.swing.JOptionPane;
015    import javax.swing.filechooser.FileFilter;
016    
017    import org.openstreetmap.josm.Main;
018    import org.openstreetmap.josm.gui.ExtendedDialog;
019    import org.openstreetmap.josm.gui.layer.Layer;
020    import org.openstreetmap.josm.gui.layer.OsmDataLayer;
021    import org.openstreetmap.josm.io.FileExporter;
022    import org.openstreetmap.josm.tools.Shortcut;
023    
024    public abstract class SaveActionBase extends DiskAccessAction {
025        private File file;
026    
027        public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut) {
028            super(name, iconName, tooltip, shortcut);
029        }
030    
031        @Override
032        public void actionPerformed(ActionEvent e) {
033            if (!isEnabled())
034                return;
035            boolean saved = doSave();
036            if (saved) {
037                addToFileOpenHistory();
038            }
039        }
040    
041        public boolean doSave() {
042            if (Main.isDisplayingMapView()) {
043                Layer layer = Main.map.mapView.getActiveLayer();
044                if (layer != null && layer.isSavable()) {
045                    return doSave(layer);
046                }
047            }
048            return false;
049        }
050    
051        public boolean doSave(Layer layer) {
052            if(!layer.checkSaveConditions())
053                return false;
054            file = getFile(layer);
055            return doInternalSave(layer, file);
056        }
057    
058        public static boolean doSave(Layer layer, File file) {
059            if(!layer.checkSaveConditions())
060                return false;
061            return doInternalSave(layer, file);
062        }
063    
064        private static boolean doInternalSave(Layer layer, File file) {
065            if (file == null)
066                return false;
067    
068            try {
069                boolean exported = false;
070                for (FileExporter exporter : ExtensionFileFilter.exporters) {
071                    if (exporter.acceptFile(file, layer)) {
072                        exporter.exportData(file, layer);
073                        exported = true;
074                        break;
075                    }
076                }
077                if (!exported) {
078                    JOptionPane.showMessageDialog(Main.parent, tr("No Exporter found! Nothing saved."), tr("Warning"),
079                            JOptionPane.WARNING_MESSAGE);
080                    return false;
081                }
082                layer.setName(file.getName());
083                layer.setAssociatedFile(file);
084                if (layer instanceof OsmDataLayer) {
085                    ((OsmDataLayer) layer).onPostSaveToFile();
086                }
087                Main.parent.repaint();
088            } catch (IOException e) {
089                e.printStackTrace();
090                return false;
091            }
092            return true;
093        }
094    
095        protected abstract File getFile(Layer layer);
096    
097        /**
098         * Refreshes the enabled state
099         *
100         */
101        @Override
102        protected void updateEnabledState() {
103            if (Main.applet) {
104                setEnabled(false);
105                return;
106            }
107            boolean check = Main.isDisplayingMapView()
108            && Main.map.mapView.getActiveLayer() != null;
109            if(!check) {
110                setEnabled(false);
111                return;
112            }
113            Layer layer = Main.map.mapView.getActiveLayer();
114            setEnabled(layer != null && layer.isSavable());
115        }
116    
117        /**
118         * Creates a new "Save" dialog for a single {@link ExtensionFileFilter} and makes it visible.<br/>
119         * When the user has chosen a file, checks the file extension, and confirms overwrite if needed.
120         * 
121         * @param title The dialog title
122         * @param filter The dialog file filter
123         * @return The output {@code File}
124         * @since 5456
125         * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, FileFilter, int, String)
126         */
127        public static File createAndOpenSaveFileChooser(String title, ExtensionFileFilter filter) {
128            JFileChooser fc = createAndOpenFileChooser(false, false, title, filter, JFileChooser.FILES_ONLY, null);
129            return checkFileAndConfirmOverWrite(fc, filter.getDefaultExtension());
130        }
131    
132        /**
133         * Creates a new "Save" dialog for a given file extension and makes it visible.<br/>
134         * When the user has chosen a file, checks the file extension, and confirms overwrite if needed.
135         * 
136         * @param title The dialog title
137         * @param extension The file extension
138         * @return The output {@code File}
139         * @see DiskAccessAction#createAndOpenFileChooser(boolean, boolean, String, String)
140         */
141        public static File createAndOpenSaveFileChooser(String title, String extension) {
142            JFileChooser fc = createAndOpenFileChooser(false, false, title, extension);
143            return checkFileAndConfirmOverWrite(fc, extension);
144        }
145        
146        private static File checkFileAndConfirmOverWrite(JFileChooser fc, String extension) {
147            if (fc == null) return null;
148            File file = fc.getSelectedFile();
149            String fn = file.getPath();
150            if (fn.indexOf('.') == -1)
151            {
152                FileFilter ff = fc.getFileFilter();
153                if (ff instanceof ExtensionFileFilter) {
154                    fn += "." + ((ExtensionFileFilter)ff).getDefaultExtension();
155                } else if (extension != null) {
156                    fn += "." + extension;
157                }
158                file = new File(fn);
159                if (!confirmOverwrite(file))
160                    return null;
161            }
162            return file;
163        }
164    
165        public static boolean confirmOverwrite(File file) {
166            if (file == null || (file.exists())) {
167                ExtendedDialog dialog = new ExtendedDialog(
168                        Main.parent,
169                        tr("Overwrite"),
170                        new String[] {tr("Overwrite"), tr("Cancel")}
171                );
172                dialog.setContent(tr("File exists. Overwrite?"));
173                dialog.setButtonIcons(new String[] {"save_as.png", "cancel.png"});
174                dialog.showDialog();
175                return (dialog.getValue() == 1);
176            }
177            return true;
178        }
179    
180        protected void addToFileOpenHistory() {
181            String filepath;
182            try {
183                filepath = file.getCanonicalPath();
184            } catch (IOException ign) {
185                return;
186            }
187    
188            int maxsize = Math.max(0, Main.pref.getInteger("file-open.history.max-size", 15));
189            Collection<String> oldHistory = Main.pref.getCollection("file-open.history");
190            List<String> history = new LinkedList<String>(oldHistory);
191            history.remove(filepath);
192            history.add(0, filepath);
193            Main.pref.putCollectionBounded("file-open.history", maxsize, history);
194        }
195    }