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

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

replaced calls to JOptionPane.* by calls to OptionPaneUtil.*

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