[319] | 1 | //License: GPL. Copyright 2007 by Immanuel Scholz and others
|
---|
[290] | 2 | package org.openstreetmap.josm.actions;
|
---|
| 3 |
|
---|
| 4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
| 5 |
|
---|
| 6 | import java.awt.event.ActionEvent;
|
---|
| 7 | import java.io.File;
|
---|
| 8 | import java.io.IOException;
|
---|
[4371] | 9 | import java.util.Collection;
|
---|
| 10 | import java.util.LinkedList;
|
---|
| 11 | import java.util.List;
|
---|
[1949] | 12 | import javax.swing.JFileChooser;
|
---|
[290] | 13 | import javax.swing.JOptionPane;
|
---|
[1949] | 14 | import javax.swing.filechooser.FileFilter;
|
---|
[290] | 15 |
|
---|
| 16 | import org.openstreetmap.josm.Main;
|
---|
[1750] | 17 | import org.openstreetmap.josm.data.conflict.ConflictCollection;
|
---|
[290] | 18 | import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
---|
[1397] | 19 | import org.openstreetmap.josm.gui.ExtendedDialog;
|
---|
[1523] | 20 | import org.openstreetmap.josm.gui.layer.GpxLayer;
|
---|
| 21 | import org.openstreetmap.josm.gui.layer.Layer;
|
---|
[290] | 22 | import org.openstreetmap.josm.gui.layer.OsmDataLayer;
|
---|
[1949] | 23 | import org.openstreetmap.josm.io.FileExporter;
|
---|
[1084] | 24 | import org.openstreetmap.josm.tools.Shortcut;
|
---|
[290] | 25 |
|
---|
[1820] | 26 | public abstract class SaveActionBase extends DiskAccessAction {
|
---|
[4371] | 27 | private File file;
|
---|
[290] | 28 |
|
---|
[1808] | 29 | public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut) {
|
---|
[1169] | 30 | super(name, iconName, tooltip, shortcut);
|
---|
| 31 | }
|
---|
[1023] | 32 |
|
---|
[4371] | 33 | @Override
|
---|
[1169] | 34 | public void actionPerformed(ActionEvent e) {
|
---|
[4371] | 35 | if (!isEnabled()) {
|
---|
[1808] | 36 | return;
|
---|
[4371] | 37 | }
|
---|
| 38 | boolean saved = doSave();
|
---|
| 39 | if (saved) {
|
---|
| 40 | addToFileOpenHistory();
|
---|
| 41 | }
|
---|
[1373] | 42 | }
|
---|
| 43 |
|
---|
[1808] | 44 | public boolean doSave() {
|
---|
| 45 | Layer layer = null;
|
---|
[2343] | 46 | if (Main.isDisplayingMapView() && (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer
|
---|
[1750] | 47 | || Main.map.mapView.getActiveLayer() instanceof GpxLayer)) {
|
---|
[1169] | 48 | layer = Main.map.mapView.getActiveLayer();
|
---|
[1750] | 49 | }
|
---|
[1808] | 50 | if (layer == null)
|
---|
| 51 | return false;
|
---|
| 52 | return doSave(layer);
|
---|
| 53 | }
|
---|
[290] | 54 |
|
---|
[1808] | 55 | public boolean doSave(Layer layer) {
|
---|
[4114] | 56 | if(!checkSaveConditions(layer))
|
---|
[1808] | 57 | return false;
|
---|
[4371] | 58 | file = getFile(layer);
|
---|
| 59 | return doInternalSave(layer, file);
|
---|
[4114] | 60 | }
|
---|
| 61 |
|
---|
| 62 | public boolean doSave(Layer layer, File file) {
|
---|
| 63 | if(!checkSaveConditions(layer))
|
---|
[1808] | 64 | return false;
|
---|
[4114] | 65 | return doInternalSave(layer, file);
|
---|
| 66 | }
|
---|
[290] | 67 |
|
---|
[4114] | 68 | private boolean doInternalSave(Layer layer, File file) {
|
---|
[1169] | 69 | if (file == null)
|
---|
[1373] | 70 | return false;
|
---|
[290] | 71 |
|
---|
[1949] | 72 | try {
|
---|
| 73 | boolean exported = false;
|
---|
| 74 | for (FileExporter exporter : ExtensionFileFilter.exporters) {
|
---|
| 75 | if (exporter.acceptFile(file, layer)) {
|
---|
| 76 | exporter.exportData(file, layer);
|
---|
| 77 | exported = true;
|
---|
| 78 | }
|
---|
| 79 | }
|
---|
| 80 | if (!exported) {
|
---|
[2017] | 81 | JOptionPane.showMessageDialog(Main.parent, tr("No Exporter found! Nothing saved."), tr("Warning"),
|
---|
[1949] | 82 | JOptionPane.WARNING_MESSAGE);
|
---|
| 83 | return false;
|
---|
| 84 | }
|
---|
| 85 | layer.setName(file.getName());
|
---|
| 86 | layer.setAssociatedFile(file);
|
---|
[2025] | 87 | if (layer instanceof OsmDataLayer) {
|
---|
| 88 | ((OsmDataLayer) layer).onPostSaveToFile();
|
---|
| 89 | }
|
---|
[1949] | 90 | Main.parent.repaint();
|
---|
| 91 | } catch (IOException e) {
|
---|
| 92 | e.printStackTrace();
|
---|
| 93 | return false;
|
---|
| 94 | }
|
---|
[1373] | 95 | return true;
|
---|
[1169] | 96 | }
|
---|
[319] | 97 |
|
---|
[1169] | 98 | protected abstract File getFile(Layer layer);
|
---|
[290] | 99 |
|
---|
[1169] | 100 | /**
|
---|
| 101 | * Checks whether it is ok to launch a save (whether we have data,
|
---|
| 102 | * there is no conflict etc.)
|
---|
| 103 | * @return <code>true</code>, if it is safe to save.
|
---|
| 104 | */
|
---|
| 105 | public boolean checkSaveConditions(Layer layer) {
|
---|
[4114] | 106 | if (layer instanceof GpxLayer)
|
---|
| 107 | return ((GpxLayer)layer).data != null;
|
---|
| 108 | else if (layer instanceof OsmDataLayer) {
|
---|
| 109 | if (isDataSetEmpty((OsmDataLayer)layer)) {
|
---|
| 110 | ExtendedDialog dialog = new ExtendedDialog(
|
---|
| 111 | Main.parent,
|
---|
| 112 | tr("Empty document"),
|
---|
| 113 | new String[] {tr("Save anyway"), tr("Cancel")}
|
---|
| 114 | );
|
---|
| 115 | dialog.setContent(tr("The document contains no data."));
|
---|
| 116 | dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
|
---|
| 117 | dialog.showDialog();
|
---|
| 118 | if (dialog.getValue() != 1) return false;
|
---|
| 119 | }
|
---|
[2070] | 120 |
|
---|
[1750] | 121 | ConflictCollection conflicts = ((OsmDataLayer)layer).getConflicts();
|
---|
| 122 | if (conflicts != null && !conflicts.isEmpty()) {
|
---|
[2070] | 123 | ExtendedDialog dialog = new ExtendedDialog(
|
---|
| 124 | Main.parent,
|
---|
[4045] | 125 | /* I18N: Display title of the window showing conflicts */
|
---|
[1750] | 126 | tr("Conflicts"),
|
---|
[2070] | 127 | new String[] {tr("Reject Conflicts and Save"), tr("Cancel")}
|
---|
| 128 | );
|
---|
| 129 | dialog.setContent(tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"));
|
---|
| 130 | dialog.setButtonIcons(new String[] {"save.png", "cancel.png"});
|
---|
| 131 | dialog.showDialog();
|
---|
| 132 | if (dialog.getValue() != 1) return false;
|
---|
[1750] | 133 | }
|
---|
[4114] | 134 | return true;
|
---|
[1169] | 135 | }
|
---|
[4114] | 136 | return false;
|
---|
[1169] | 137 | }
|
---|
[290] | 138 |
|
---|
[1169] | 139 | public static File openFileDialog(Layer layer) {
|
---|
[1646] | 140 | if (layer instanceof OsmDataLayer)
|
---|
[2029] | 141 | return createAndOpenSaveFileChooser(tr("Save OSM file"), "osm");
|
---|
[1646] | 142 | else if (layer instanceof GpxLayer)
|
---|
[2029] | 143 | return createAndOpenSaveFileChooser(tr("Save GPX file"), "gpx");
|
---|
| 144 | return createAndOpenSaveFileChooser(tr("Save Layer"), "lay");
|
---|
[1169] | 145 | }
|
---|
[319] | 146 |
|
---|
[1169] | 147 | /**
|
---|
| 148 | * Check the data set if it would be empty on save. It is empty, if it contains
|
---|
| 149 | * no objects (after all objects that are created and deleted without being
|
---|
[1676] | 150 | * transferred to the server have been removed).
|
---|
[1169] | 151 | *
|
---|
| 152 | * @return <code>true</code>, if a save result in an empty data set.
|
---|
| 153 | */
|
---|
| 154 | private boolean isDataSetEmpty(OsmDataLayer layer) {
|
---|
| 155 | for (OsmPrimitive osm : layer.data.allNonDeletedPrimitives())
|
---|
[3336] | 156 | if (!osm.isDeleted() || !osm.isNewOrUndeleted())
|
---|
[1169] | 157 | return false;
|
---|
| 158 | return true;
|
---|
| 159 | }
|
---|
[1808] | 160 |
|
---|
| 161 | /**
|
---|
| 162 | * Refreshes the enabled state
|
---|
[1949] | 163 | *
|
---|
[1808] | 164 | */
|
---|
[1820] | 165 | @Override
|
---|
| 166 | protected void updateEnabledState() {
|
---|
[1879] | 167 | if (Main.applet) {
|
---|
| 168 | setEnabled(false);
|
---|
| 169 | return;
|
---|
| 170 | }
|
---|
[1820] | 171 | boolean check = Main.map != null
|
---|
[1808] | 172 | && Main.map.mapView !=null
|
---|
| 173 | && Main.map.mapView.getActiveLayer() != null;
|
---|
| 174 | if(!check) {
|
---|
| 175 | setEnabled(false);
|
---|
| 176 | return;
|
---|
| 177 | }
|
---|
| 178 | Layer layer = Main.map.mapView.getActiveLayer();
|
---|
| 179 | setEnabled(layer instanceof OsmDataLayer || layer instanceof GpxLayer);
|
---|
| 180 | }
|
---|
[1949] | 181 |
|
---|
| 182 | public static File createAndOpenSaveFileChooser(String title, String extension) {
|
---|
| 183 | String curDir = Main.pref.get("lastDirectory");
|
---|
| 184 | if (curDir.equals("")) {
|
---|
| 185 | curDir = ".";
|
---|
| 186 | }
|
---|
| 187 | JFileChooser fc = new JFileChooser(new File(curDir));
|
---|
| 188 | if (title != null) {
|
---|
| 189 | fc.setDialogTitle(title);
|
---|
| 190 | }
|
---|
| 191 |
|
---|
| 192 | fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
---|
| 193 | fc.setMultiSelectionEnabled(false);
|
---|
| 194 | fc.setAcceptAllFileFilterUsed(false);
|
---|
[2029] | 195 | ExtensionFileFilter.applyChoosableExportFileFilters(fc, extension);
|
---|
[1949] | 196 | int answer = fc.showSaveDialog(Main.parent);
|
---|
| 197 | if (answer != JFileChooser.APPROVE_OPTION)
|
---|
| 198 | return null;
|
---|
| 199 |
|
---|
| 200 | if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) {
|
---|
| 201 | Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
|
---|
| 202 | }
|
---|
| 203 |
|
---|
| 204 | File file = fc.getSelectedFile();
|
---|
[3570] | 205 | String fn = file.getPath();
|
---|
| 206 | if(fn.indexOf('.') == -1)
|
---|
| 207 | {
|
---|
| 208 | FileFilter ff = fc.getFileFilter();
|
---|
| 209 | if (ff instanceof ExtensionFileFilter) {
|
---|
| 210 | fn += "." + ((ExtensionFileFilter)ff).getDefaultExtension();
|
---|
| 211 | } else if(extension != null) {
|
---|
| 212 | fn += "." + extension;
|
---|
[1949] | 213 | }
|
---|
[3570] | 214 | file = new File(fn);
|
---|
[1949] | 215 | }
|
---|
[3863] | 216 | if (!confirmOverride(file))
|
---|
| 217 | return null;
|
---|
| 218 | return file;
|
---|
| 219 | }
|
---|
| 220 |
|
---|
| 221 | public static boolean confirmOverride(File file) {
|
---|
| 222 | if (file == null || (file.exists())) {
|
---|
[2070] | 223 | ExtendedDialog dialog = new ExtendedDialog(
|
---|
| 224 | Main.parent,
|
---|
| 225 | tr("Overwrite"),
|
---|
| 226 | new String[] {tr("Overwrite"), tr("Cancel")}
|
---|
| 227 | );
|
---|
| 228 | dialog.setContent(tr("File exists. Overwrite?"));
|
---|
| 229 | dialog.setButtonIcons(new String[] {"save_as.png", "cancel.png"});
|
---|
| 230 | dialog.showDialog();
|
---|
[3863] | 231 | return (dialog.getValue() == 1);
|
---|
[2070] | 232 | }
|
---|
[3863] | 233 | return true;
|
---|
[1949] | 234 | }
|
---|
[4371] | 235 |
|
---|
| 236 | protected void addToFileOpenHistory() {
|
---|
| 237 | String filepath;
|
---|
| 238 | try {
|
---|
| 239 | filepath = file.getCanonicalPath();
|
---|
| 240 | } catch (IOException ign) {
|
---|
| 241 | return;
|
---|
| 242 | }
|
---|
| 243 |
|
---|
| 244 | int maxsize = Math.max(0, Main.pref.getInteger("file-open.history.max-size", 15));
|
---|
| 245 | Collection<String> oldHistory = Main.pref.getCollection("file-open.history");
|
---|
| 246 | List<String> history = new LinkedList<String>(oldHistory);
|
---|
[4374] | 247 | history.remove(filepath);
|
---|
[4371] | 248 | history.add(0, filepath);
|
---|
| 249 | Main.pref.putCollectionBounded("file-open.history", maxsize, history);
|
---|
| 250 | }
|
---|
[290] | 251 | }
|
---|