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

Last change on this file since 1397 was 1397, checked in by stoecker, 15 years ago

apply patches from xeen for #1977.

  • Property svn:eol-style set to native
File size: 9.1 KB
Line 
1//License: GPL. Copyright 2007 by Immanuel Scholz and others
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.FileOutputStream;
9import java.io.FileInputStream;
10import java.io.FileNotFoundException;
11import java.io.IOException;
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.osm.OsmPrimitive;
19import org.openstreetmap.josm.gui.ExtendedDialog;
20import org.openstreetmap.josm.gui.layer.OsmDataLayer;
21import org.openstreetmap.josm.gui.layer.Layer;
22import org.openstreetmap.josm.gui.layer.GpxLayer;
23import org.openstreetmap.josm.io.OsmWriter;
24import org.openstreetmap.josm.io.GpxWriter;
25import org.openstreetmap.josm.tools.Shortcut;
26
27public abstract class SaveActionBase extends DiskAccessAction {
28
29 private Layer layer;
30
31 public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut, Layer layer) {
32 super(name, iconName, tooltip, shortcut);
33 this.layer = layer;
34 }
35
36 public void actionPerformed(ActionEvent e) {
37 doSave();
38 }
39
40 public Boolean doSave() {
41 Layer layer = this.layer;
42 if (layer == null && Main.map != null && (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer
43 || Main.map.mapView.getActiveLayer() instanceof GpxLayer))
44 layer = Main.map.mapView.getActiveLayer();
45 if (layer == null)
46 layer = Main.main.editLayer();
47
48 if (!checkSaveConditions(layer))
49 return false;
50
51
52 File file = getFile(layer);
53 if (file == null)
54 return false;
55
56 save(file, layer);
57
58 layer.name = file.getName();
59 layer.associatedFile = file;
60 Main.parent.repaint();
61 return true;
62 }
63
64 protected abstract File getFile(Layer layer);
65
66 /**
67 * Checks whether it is ok to launch a save (whether we have data,
68 * there is no conflict etc.)
69 * @return <code>true</code>, if it is safe to save.
70 */
71 public boolean checkSaveConditions(Layer layer) {
72 if (layer == null) {
73 JOptionPane.showMessageDialog(Main.parent, tr("Internal Error: cannot check conditions for no layer. Please report this as a bug."));
74 return false;
75 }
76 if (Main.map == null) {
77 JOptionPane.showMessageDialog(Main.parent, tr("No document open so nothing to save."));
78 return false;
79 }
80
81 if (layer instanceof OsmDataLayer && isDataSetEmpty((OsmDataLayer)layer) && 1 != new ExtendedDialog(Main.parent, tr("Empty document"), tr("The document contains no data."), new String[] {tr("Save anyway"), tr("Cancel")}, new String[] {"save.png", "cancel.png"}).getValue()) {
82 return false;
83 }
84 if (layer instanceof GpxLayer && ((GpxLayer)layer).data == null) {
85 return false;
86 }
87 if (!Main.map.conflictDialog.conflicts.isEmpty()) {
88 int answer = new ExtendedDialog(Main.parent,
89 tr("Conflicts"),
90 tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"),
91 new String[] {tr("Reject Conflicts and Save"), tr("Cancel")},
92 new String[] {"save.png", "cancel.png"}).getValue();
93
94 if (answer != 1) return false;
95 }
96 return true;
97 }
98
99 public static File openFileDialog(Layer layer) {
100 JFileChooser fc = createAndOpenFileChooser(false, false, layer instanceof GpxLayer ? tr("Save GPX file") : tr("Save OSM file"));
101 if (fc == null)
102 return null;
103
104 File file = fc.getSelectedFile();
105
106 String fn = file.getPath();
107 if (fn.indexOf('.') == -1) {
108 FileFilter ff = fc.getFileFilter();
109 if (ff instanceof ExtensionFileFilter)
110 fn += "." + ((ExtensionFileFilter)ff).defaultExtension;
111 else if (layer instanceof GpxLayer)
112 fn += ".gpx";
113 else
114 fn += ".osm";
115 file = new File(fn);
116 }
117 return file;
118 }
119
120 private static void copy(File src, File dst) throws IOException {
121 FileInputStream srcStream;
122 FileOutputStream dstStream;
123 try {
124 srcStream = new FileInputStream(src);
125 dstStream = new FileOutputStream(dst);
126 } catch (FileNotFoundException e) {
127 JOptionPane.showMessageDialog(Main.parent, tr("Could not back up file.")+"\n"+e.getMessage());
128 return;
129 }
130 byte buf[] = new byte[1<<16];
131 int len;
132 while ((len = srcStream.read(buf)) != -1) {
133 dstStream.write(buf, 0, len);
134 }
135 srcStream.close();
136 dstStream.close();
137 }
138
139 public static void save(File file, Layer layer) {
140 if (layer instanceof GpxLayer) {
141 save(file, (GpxLayer)layer);
142 ((GpxLayer)layer).data.storageFile = file;
143 } else if (layer instanceof OsmDataLayer) {
144 save(file, (OsmDataLayer)layer);
145 }
146 }
147
148 public static void save(File file, OsmDataLayer layer) {
149 File tmpFile = null;
150 try {
151 if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) {
152 GpxExportAction.exportGpx(file, layer);
153 } else if (ExtensionFileFilter.filters[ExtensionFileFilter.OSM].acceptName(file.getPath())) {
154 // use a tmp file because if something errors out in the
155 // process of writing the file, we might just end up with
156 // a truncated file. That can destroy lots of work.
157 if (file.exists()) {
158 tmpFile = new File(file.getPath() + "~");
159 copy(file, tmpFile);
160 }
161 OsmWriter.output(new FileOutputStream(file), new OsmWriter.All(layer.data, false));
162 if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null))
163 tmpFile.delete();
164 } else {
165 JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
166 return;
167 }
168 layer.cleanData(null, false);
169 } catch (IOException e) {
170 e.printStackTrace();
171 JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
172
173 try {
174 // if the file save failed, then the tempfile will not
175 // be deleted. So, restore the backup if we made one.
176 if (tmpFile != null && tmpFile.exists()) {
177 copy(tmpFile, file);
178 }
179 } catch (IOException e2) {
180 e2.printStackTrace();
181 JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e2.getMessage());
182 }
183 }
184 }
185
186 public static void save(File file, GpxLayer layer) {
187 File tmpFile = null;
188 try {
189 if (ExtensionFileFilter.filters[ExtensionFileFilter.GPX].acceptName(file.getPath())) {
190
191 // use a tmp file because if something errors out in the
192 // process of writing the file, we might just end up with
193 // a truncated file. That can destroy lots of work.
194 if (file.exists()) {
195 tmpFile = new File(file.getPath() + "~");
196 copy(file, tmpFile);
197 }
198 FileOutputStream fo = new FileOutputStream(file);
199 new GpxWriter(fo).write(layer.data);
200 fo.flush();
201 fo.close();
202
203 if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
204 tmpFile.delete();
205 }
206 } else {
207 JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
208 return;
209 }
210 } catch (IOException e) {
211 e.printStackTrace();
212 JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
213 }
214 try {
215 // if the file save failed, then the tempfile will not
216 // be deleted. So, restore the backup if we made one.
217 if (tmpFile != null && tmpFile.exists()) {
218 copy(tmpFile, file);
219 }
220 } catch (IOException e) {
221 e.printStackTrace();
222 JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e.getMessage());
223 }
224 }
225
226 /**
227 * Check the data set if it would be empty on save. It is empty, if it contains
228 * no objects (after all objects that are created and deleted without being
229 * transfered to the server have been removed).
230 *
231 * @return <code>true</code>, if a save result in an empty data set.
232 */
233 private boolean isDataSetEmpty(OsmDataLayer layer) {
234 for (OsmPrimitive osm : layer.data.allNonDeletedPrimitives())
235 if (!osm.deleted || osm.id > 0)
236 return false;
237 return true;
238 }
239}
Note: See TracBrowser for help on using the repository browser.