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

Last change on this file since 1750 was 1750, checked in by Gubaer, 15 years ago

new: replaced global conflict list by conflict list per layer, similar to datasets

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