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

Last change on this file since 872 was 872, checked in by ramack, 16 years ago

GpxWriter does not close the stream it writes to after it has finished, to allow writing to a network stream

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