001//License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.actions; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.event.ActionEvent; 007import java.io.File; 008import java.io.IOException; 009import java.util.Collection; 010import java.util.LinkedList; 011import java.util.List; 012 013import javax.swing.JFileChooser; 014import javax.swing.JOptionPane; 015import javax.swing.filechooser.FileFilter; 016 017import org.openstreetmap.josm.Main; 018import org.openstreetmap.josm.gui.ExtendedDialog; 019import org.openstreetmap.josm.gui.layer.Layer; 020import org.openstreetmap.josm.gui.layer.OsmDataLayer; 021import org.openstreetmap.josm.io.FileExporter; 022import org.openstreetmap.josm.tools.Shortcut; 023 024public 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 150 FileFilter ff = fc.getFileFilter(); 151 if (!ff.accept(file)) { 152 // Extension of another filefilter given ? 153 for (FileFilter cff : fc.getChoosableFileFilters()) { 154 if (cff.accept(file)) { 155 fc.setFileFilter(cff); 156 return file; 157 } 158 } 159 // No filefilter accepts current filename, add default extension 160 String fn = file.getPath(); 161 if (ff instanceof ExtensionFileFilter) { 162 fn += "." + ((ExtensionFileFilter)ff).getDefaultExtension(); 163 } else if (extension != null) { 164 fn += "." + extension; 165 } 166 file = new File(fn); 167 if (!confirmOverwrite(file)) 168 return null; 169 } 170 return file; 171 } 172 173 public static boolean confirmOverwrite(File file) { 174 if (file == null || (file.exists())) { 175 ExtendedDialog dialog = new ExtendedDialog( 176 Main.parent, 177 tr("Overwrite"), 178 new String[] {tr("Overwrite"), tr("Cancel")} 179 ); 180 dialog.setContent(tr("File exists. Overwrite?")); 181 dialog.setButtonIcons(new String[] {"save_as.png", "cancel.png"}); 182 dialog.showDialog(); 183 return (dialog.getValue() == 1); 184 } 185 return true; 186 } 187 188 protected void addToFileOpenHistory() { 189 String filepath; 190 try { 191 filepath = file.getCanonicalPath(); 192 } catch (IOException ign) { 193 return; 194 } 195 196 int maxsize = Math.max(0, Main.pref.getInteger("file-open.history.max-size", 15)); 197 Collection<String> oldHistory = Main.pref.getCollection("file-open.history"); 198 List<String> history = new LinkedList<String>(oldHistory); 199 history.remove(filepath); 200 history.add(0, filepath); 201 Main.pref.putCollectionBounded("file-open.history", maxsize, history); 202 } 203}