Ticket #1647: exporter.txt

File exporter.txt, 49.0 KB (added by dmuecke, 17 years ago)
Line 
1Index: src/org/openstreetmap/josm/actions/DiskAccessAction.java
2===================================================================
3--- src/org/openstreetmap/josm/actions/DiskAccessAction.java (revision 1713)
4+++ src/org/openstreetmap/josm/actions/DiskAccessAction.java (working copy)
5@@ -5,7 +5,6 @@
6
7 import java.io.File;
8 import javax.swing.JFileChooser;
9-import javax.swing.filechooser.FileFilter;
10 import org.openstreetmap.josm.Main;
11 import org.openstreetmap.josm.gui.ExtendedDialog;
12 import org.openstreetmap.josm.tools.Shortcut;
13@@ -56,50 +55,4 @@
14 return fc;
15 }
16
17- public static File createAndOpenSaveFileChooser(String title,
18- String extension)
19- {
20- String curDir = Main.pref.get("lastDirectory");
21- if (curDir.equals(""))
22- curDir = ".";
23- JFileChooser fc = new JFileChooser(new File(curDir));
24- if (title != null)
25- fc.setDialogTitle(title);
26-
27- fc.setMultiSelectionEnabled(false);
28- for (FileImporter imExporter: ExtensionFileFilter.importers) {
29- fc.addChoosableFileFilter(imExporter.filter);
30- }
31-
32- fc.setAcceptAllFileFilterUsed(true);
33-
34- int answer = fc.showSaveDialog(Main.parent);
35- if (answer != JFileChooser.APPROVE_OPTION)
36- return null;
37-
38- if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir))
39- Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
40-
41- File file = fc.getSelectedFile();
42- if(extension != null)
43- {
44- String fn = file.getPath();
45- if(fn.indexOf('.') == -1)
46- {
47- FileFilter ff = fc.getFileFilter();
48- if (ff instanceof ExtensionFileFilter)
49- fn += "." + ((ExtensionFileFilter)ff).defaultExtension;
50- else
51- fn += extension;
52- file = new File(fn);
53- }
54- }
55- if(file == null || (file.exists() && 1 != new ExtendedDialog(Main.parent,
56- tr("Overwrite"), tr("File exists. Overwrite?"),
57- new String[] {tr("Overwrite"), tr("Cancel")},
58- new String[] {"save_as.png", "cancel.png"}).getValue()))
59- return null;
60- return file;
61- }
62-
63 }
64Index: src/org/openstreetmap/josm/actions/ExtensionFileFilter.java
65===================================================================
66--- src/org/openstreetmap/josm/actions/ExtensionFileFilter.java (revision 1713)
67+++ src/org/openstreetmap/josm/actions/ExtensionFileFilter.java (working copy)
68@@ -1,6 +1,7 @@
69 // License: GPL. Copyright 2007 by Immanuel Scholz and others
70 package org.openstreetmap.josm.actions;
71
72+import static org.openstreetmap.josm.tools.I18n.tr;
73 import java.io.File;
74 import java.util.ArrayList;
75 import java.util.Arrays;
76@@ -8,12 +9,18 @@
77 import javax.swing.filechooser.FileFilter;
78
79 import org.openstreetmap.josm.io.FileImporter;
80+import org.openstreetmap.josm.io.GpxExporter;
81 import org.openstreetmap.josm.io.GpxImporter;
82 import org.openstreetmap.josm.io.NMEAImporter;
83+import org.openstreetmap.josm.io.OsmBzip2Exporter;
84 import org.openstreetmap.josm.io.OsmBzip2Importer;
85+import org.openstreetmap.josm.io.OsmExporter;
86+import org.openstreetmap.josm.io.OsmGzipExporter;
87 import org.openstreetmap.josm.io.OsmGzipImporter;
88 import org.openstreetmap.josm.io.OsmImporter;
89
90+import org.openstreetmap.josm.io.FileExporter;
91+
92 /**
93 * A file filter that filters after the extension. Also includes a list of file
94 * filters used in JOSM.
95@@ -28,6 +35,10 @@
96 public static ArrayList<FileImporter> importers = new ArrayList<FileImporter>(Arrays.asList(new OsmImporter(),
97 new OsmGzipImporter(), new OsmBzip2Importer(), new GpxImporter(), new NMEAImporter()));
98
99+ // list of supported export formats
100+ public static ArrayList<FileExporter> exporters = new ArrayList<FileExporter>(Arrays.asList(new GpxExporter(),
101+ new OsmExporter(), new OsmGzipExporter(), new OsmBzip2Exporter()));
102+
103 /**
104 * Construct an extension file filter by giving the extension to check after.
105 *
106Index: src/org/openstreetmap/josm/actions/GpxExportAction.java
107===================================================================
108--- src/org/openstreetmap/josm/actions/GpxExportAction.java (revision 1713)
109+++ src/org/openstreetmap/josm/actions/GpxExportAction.java (working copy)
110@@ -3,263 +3,58 @@
111
112 import static org.openstreetmap.josm.tools.I18n.tr;
113
114-import java.awt.GridBagLayout;
115 import java.awt.event.ActionEvent;
116-import java.awt.event.ActionListener;
117-import java.awt.event.KeyAdapter;
118 import java.awt.event.KeyEvent;
119 import java.io.File;
120-import java.io.FileOutputStream;
121 import java.io.IOException;
122-import java.util.Calendar;
123
124-import javax.swing.JButton;
125-import javax.swing.JCheckBox;
126-import javax.swing.JFileChooser;
127-import javax.swing.JLabel;
128-import javax.swing.JList;
129 import javax.swing.JOptionPane;
130-import javax.swing.JPanel;
131-import javax.swing.JScrollPane;
132-import javax.swing.JTextArea;
133-import javax.swing.JTextField;
134-import javax.swing.ListSelectionModel;
135
136 import org.openstreetmap.josm.Main;
137-import org.openstreetmap.josm.data.gpx.GpxData;
138 import org.openstreetmap.josm.gui.ExtendedDialog;
139 import org.openstreetmap.josm.gui.layer.GpxLayer;
140 import org.openstreetmap.josm.gui.layer.Layer;
141-import org.openstreetmap.josm.gui.layer.OsmDataLayer;
142-import org.openstreetmap.josm.io.GpxWriter;
143-import org.openstreetmap.josm.tools.GBC;
144+import org.openstreetmap.josm.io.FileExporter;
145+import org.openstreetmap.josm.io.GpxExporter;
146 import org.openstreetmap.josm.tools.Shortcut;
147
148 /**
149 * Exports data to gpx.
150 */
151-public class GpxExportAction extends DiskAccessAction {
152-
153- private final static String warningGpl = "<html><font color='red' size='-2'>"+tr("Note: GPL is not compatible with the OSM license. Do not upload GPL licensed tracks.")+"</html>";
154+public class GpxExportAction extends SaveActionBase {
155
156- private final Layer layer;
157+ public final static String warningGpl = "<html><font color='red' size='-2'>"+tr("Note: GPL is not compatible with the OSM license. Do not upload GPL licensed tracks.")+"</html>";
158
159 public GpxExportAction(Layer layer) {
160 super(tr("Export to GPX..."), "exportgpx", tr("Export the data to GPX file."),
161- Shortcut.registerShortcut("file:exportgpx", tr("Export to GPX..."), KeyEvent.VK_E, Shortcut.GROUP_MENU));
162- this.layer = layer;
163+ Shortcut.registerShortcut("file:exportgpx", tr("Export to GPX..."), KeyEvent.VK_E, Shortcut.GROUP_MENU),
164+ layer);
165 }
166
167+ @Override
168 public void actionPerformed(ActionEvent e) {
169 if (layer == null && Main.map == null) {
170 JOptionPane.showMessageDialog(Main.parent, tr("Nothing to export. Get some data first."));
171 return;
172 }
173
174- JFileChooser fc = createAndOpenFileChooser(false, false, null);
175- if (fc == null)
176- return;
177- File file = fc.getSelectedFile();
178+ File file = createAndOpenSaveFileChooser(tr("Export GPX file"),".gpx");
179 if (file == null)
180 return;
181
182- exportGpx(file, this.layer == null ? Main.main.editLayer() : this.layer);
183- }
184-
185- public static void exportGpx(File file, Layer layer) {
186- String fn = file.getPath();
187- if (fn.indexOf('.') == -1) {
188- fn += ".gpx";
189- file = new File(fn);
190- }
191-
192- // open the dialog asking for options
193- JPanel p = new JPanel(new GridBagLayout());
194-
195- p.add(new JLabel(tr("gps track description")), GBC.eol());
196- JTextArea desc = new JTextArea(3,40);
197- desc.setWrapStyleWord(true);
198- desc.setLineWrap(true);
199- p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
200-
201- JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true));
202- author.setSelected(true);
203- p.add(author, GBC.eol());
204- JLabel nameLabel = new JLabel(tr("Real name"));
205- p.add(nameLabel, GBC.std().insets(10,0,5,0));
206- JTextField authorName = new JTextField(Main.pref.get("lastAuthorName"));
207- p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
208- JLabel emailLabel = new JLabel(tr("E-Mail"));
209- p.add(emailLabel, GBC.std().insets(10,0,5,0));
210- JTextField email = new JTextField(Main.pref.get("osm-server.username"));
211- p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
212- JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
213- p.add(copyrightLabel, GBC.std().insets(10,0,5,0));
214- JTextField copyright = new JTextField();
215- p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
216- JButton predefined = new JButton(tr("Predefined"));
217- p.add(predefined, GBC.eol().insets(5,0,0,0));
218- JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
219- p.add(copyrightYearLabel, GBC.std().insets(10,0,5,5));
220- JTextField copyrightYear = new JTextField("");
221- p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
222- JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
223- p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15,0,0,0));
224- addDependencies(author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel, copyrightLabel, copyrightYearLabel, warning);
225-
226- // if the user name is not the email address, but the osm user name
227- // move it from the email textfield to the author textfield
228- if(!email.getText().contains("@")) {
229- authorName.setText(email.getText());
230- email.setText("");
231- }
232-
233- p.add(new JLabel(tr("Keywords")), GBC.eol());
234- JTextField keywords = new JTextField();
235- p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
236-
237- int answer = new ExtendedDialog(Main.parent,
238- tr("Export options"),
239- p,
240- new String[] {tr("Export and Save"), tr("Cancel")},
241- new String[] {"exportgpx.png", "cancel.png"}).getValue();
242- if (answer != 1)
243- return;
244-
245- Main.pref.put("lastAddAuthor", author.isSelected());
246- if (authorName.getText().length() != 0)
247- Main.pref.put("lastAuthorName", authorName.getText());
248- if (copyright.getText().length() != 0)
249- Main.pref.put("lastCopyright", copyright.getText());
250-
251- GpxData gpxData;
252- if (layer instanceof OsmDataLayer)
253- gpxData = ((OsmDataLayer)layer).toGpxData();
254- else if (layer instanceof GpxLayer)
255- gpxData = ((GpxLayer)layer).data;
256- else
257- gpxData = OsmDataLayer.toGpxData(Main.ds, file);
258-
259- // add author and copyright details to the gpx data
260- if(author.isSelected()) {
261- if(authorName.getText().length() > 0) {
262- gpxData.attr.put(GpxData.META_AUTHOR_NAME, authorName.getText());
263- gpxData.attr.put(GpxData.META_COPYRIGHT_AUTHOR, authorName.getText());
264- }
265- if(email.getText().length() > 0) gpxData.attr.put(GpxData.META_AUTHOR_EMAIL, email.getText());
266- if(copyright.getText().length() > 0) gpxData.attr.put(GpxData.META_COPYRIGHT_LICENSE, copyright.getText());
267- if(copyrightYear.getText().length() > 0) gpxData.attr.put(GpxData.META_COPYRIGHT_YEAR, copyrightYear.getText());
268- }
269-
270- // add the description to the gpx data
271- if(desc.getText().length() > 0) gpxData.attr.put(GpxData.META_DESC, desc.getText());
272-
273- // add keywords to the gpx data
274- if(keywords.getText().length() > 0) gpxData.attr.put(GpxData.META_KEYWORDS, keywords.getText());
275-
276- try {
277- FileOutputStream fo = new FileOutputStream(file);
278- new GpxWriter(fo).write(gpxData);
279- fo.flush();
280- fo.close();
281- } catch (IOException x) {
282- x.printStackTrace();
283- JOptionPane.showMessageDialog(Main.parent, tr("Error while exporting {0}:\n{1}", fn,x.getMessage()), tr("Error"), JOptionPane.ERROR_MESSAGE);
284- }
285- }
286-
287- /**
288- * Add all those listeners to handle the enable state of the fields.
289- * @param copyrightYearLabel
290- * @param copyrightLabel
291- * @param emailLabel
292- * @param nameLabel
293- * @param warning
294- */
295- private static void addDependencies(
296- final JCheckBox author,
297- final JTextField authorName,
298- final JTextField email,
299- final JTextField copyright,
300- final JButton predefined,
301- final JTextField copyrightYear,
302- final JLabel nameLabel,
303- final JLabel emailLabel,
304- final JLabel copyrightLabel,
305- final JLabel copyrightYearLabel,
306- final JLabel warning) {
307-
308- ActionListener authorActionListener = new ActionListener(){
309- public void actionPerformed(ActionEvent e) {
310- boolean b = author.isSelected();
311- authorName.setEnabled(b);
312- email.setEnabled(b);
313- nameLabel.setEnabled(b);
314- emailLabel.setEnabled(b);
315- authorName.setText(b ? Main.pref.get("lastAuthorName") : "");
316- email.setText(b ? Main.pref.get("osm-server.username") : "");
317-
318- boolean authorSet = authorName.getText().length() != 0;
319- enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && authorSet);
320- }
321- };
322- author.addActionListener(authorActionListener);
323-
324- KeyAdapter authorNameListener = new KeyAdapter(){
325- @Override public void keyReleased(KeyEvent e) {
326- boolean b = authorName.getText().length()!=0 && author.isSelected();
327- enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
328- }
329- };
330- authorName.addKeyListener(authorNameListener);
331-
332- predefined.addActionListener(new ActionListener(){
333- public void actionPerformed(ActionEvent e) {
334- JList l = new JList(new String[]{"Creative Commons By-SA", "public domain", "GNU Lesser Public License (LGPL)", "BSD License (MIT/X11)"});
335- l.setVisibleRowCount(4);
336- l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
337- int answer = JOptionPane.showConfirmDialog(Main.parent, new JScrollPane(l),tr("Choose a predefined license"), JOptionPane.OK_CANCEL_OPTION);
338- if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
339- return;
340- final String[] urls = {
341- "http://creativecommons.org/licenses/by-sa/2.5",
342- "public domain",
343- "http://www.gnu.org/copyleft/lesser.html",
344- "http://www.opensource.org/licenses/bsd-license.php"};
345- String license = "";
346- for (int i : l.getSelectedIndices()) {
347- if (i == 1) {
348- license = "public domain";
349- break;
350- }
351- license += license.length()==0 ? urls[i] : ", "+urls[i];
352+ for (FileExporter exporter : ExtensionFileFilter.exporters) {
353+ if(exporter instanceof GpxExporter) {
354+ try {
355+ exporter.exportData(file, this.layer == null ? Main.main.editLayer() : this.layer);
356+ } catch (IOException e1) {
357+ e1.printStackTrace();
358 }
359- copyright.setText(license);
360- copyright.setCaretPosition(0);
361 }
362- });
363-
364- authorActionListener.actionPerformed(null);
365- authorNameListener.keyReleased(null);
366+ }
367 }
368
369- private static void enableCopyright(final JTextField copyright, final JButton predefined, final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel, final JLabel warning, boolean enable) {
370- copyright.setEnabled(enable);
371- predefined.setEnabled(enable);
372- copyrightYear.setEnabled(enable);
373- copyrightLabel.setEnabled(enable);
374- copyrightYearLabel.setEnabled(enable);
375- warning.setText(enable ? warningGpl : "<html><font size='-2'>&nbsp;</html");
376-
377- if (enable && copyrightYear.getText().length()==0) {
378- copyrightYear.setText(enable ? Integer.toString(Calendar.getInstance().get(Calendar.YEAR)) : "");
379- } else if (!enable)
380- copyrightYear.setText("");
381-
382- if (enable && copyright.getText().length()==0) {
383- copyright.setText(enable ? Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5") : "");
384- copyright.setCaretPosition(0);
385- } else if (!enable)
386- copyright.setText("");
387+ //Function not used here
388+ @Override public File getFile(Layer layer) {
389+ return null;
390 }
391 }
392Index: src/org/openstreetmap/josm/actions/SaveActionBase.java
393===================================================================
394--- src/org/openstreetmap/josm/actions/SaveActionBase.java (revision 1713)
395+++ src/org/openstreetmap/josm/actions/SaveActionBase.java (working copy)
396@@ -9,32 +9,24 @@
397 import java.io.FileNotFoundException;
398 import java.io.FileOutputStream;
399 import java.io.IOException;
400-import java.io.OutputStream;
401-import java.io.OutputStreamWriter;
402-import java.io.PrintWriter;
403-import java.io.Writer;
404-import java.util.zip.GZIPOutputStream;
405
406+import javax.swing.JFileChooser;
407 import javax.swing.JOptionPane;
408+import javax.swing.filechooser.FileFilter;
409
410-import org.apache.tools.bzip2.CBZip2OutputStream;
411 import org.openstreetmap.josm.Main;
412 import org.openstreetmap.josm.data.osm.OsmPrimitive;
413 import org.openstreetmap.josm.gui.ExtendedDialog;
414 import org.openstreetmap.josm.gui.layer.GpxLayer;
415 import org.openstreetmap.josm.gui.layer.Layer;
416 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
417-import org.openstreetmap.josm.io.GpxImporter;
418-import org.openstreetmap.josm.io.GpxWriter;
419-import org.openstreetmap.josm.io.OsmBzip2Importer;
420-import org.openstreetmap.josm.io.OsmGzipImporter;
421-import org.openstreetmap.josm.io.OsmImporter;
422-import org.openstreetmap.josm.io.OsmWriter;
423+import org.openstreetmap.josm.io.FileExporter;
424+import org.openstreetmap.josm.io.FileImporter;
425 import org.openstreetmap.josm.tools.Shortcut;
426
427 public abstract class SaveActionBase extends DiskAccessAction {
428
429- private Layer layer;
430+ protected Layer layer;
431
432 public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut, Layer layer) {
433 super(name, iconName, tooltip, shortcut);
434@@ -48,10 +40,12 @@
435 public Boolean doSave() {
436 Layer layer = this.layer;
437 if (layer == null && Main.map != null && (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer
438- || Main.map.mapView.getActiveLayer() instanceof GpxLayer))
439+ || Main.map.mapView.getActiveLayer() instanceof GpxLayer)) {
440 layer = Main.map.mapView.getActiveLayer();
441- if (layer == null)
442+ }
443+ if (layer == null) {
444 layer = Main.main.editLayer();
445+ }
446
447 if (!checkSaveConditions(layer))
448 return false;
449@@ -61,11 +55,21 @@
450 if (file == null)
451 return false;
452
453- save(file, layer);
454+ try {
455+ for (FileExporter exporter : ExtensionFileFilter.exporters) {
456+ if(exporter.acceptFile(file)) {
457+ exporter.exportData(file, layer);
458+ }
459+ }
460+
461+ layer.name = file.getName();
462+ layer.setAssociatedFile(file);
463+ Main.parent.repaint();
464
465- layer.name = file.getName();
466- layer.setAssociatedFile(file);
467- Main.parent.repaint();
468+ } catch (IOException e) {
469+ e.printStackTrace();
470+ return false;
471+ }
472 return true;
473 }
474
475@@ -86,18 +90,16 @@
476 return false;
477 }
478
479- 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()) {
480+ 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())
481 return false;
482- }
483- if (layer instanceof GpxLayer && ((GpxLayer)layer).data == null) {
484+ if (layer instanceof GpxLayer && ((GpxLayer)layer).data == null)
485 return false;
486- }
487 if (!Main.map.conflictDialog.conflicts.isEmpty()) {
488 int answer = new ExtendedDialog(Main.parent,
489- tr("Conflicts"),
490- tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"),
491- new String[] {tr("Reject Conflicts and Save"), tr("Cancel")},
492- new String[] {"save.png", "cancel.png"}).getValue();
493+ tr("Conflicts"),
494+ tr("There are unresolved conflicts. Conflicts will not be saved and handled as if you rejected all. Continue?"),
495+ new String[] {tr("Reject Conflicts and Save"), tr("Cancel")},
496+ new String[] {"save.png", "cancel.png"}).getValue();
497
498 if (answer != 1) return false;
499 }
500@@ -106,13 +108,13 @@
501
502 public static File openFileDialog(Layer layer) {
503 if (layer instanceof OsmDataLayer)
504- return createAndOpenSaveFileChooser(tr("Save OSM file"), ".osm");
505+ return SaveActionBase.createAndOpenSaveFileChooser(tr("Save OSM file"), ".osm");
506 else if (layer instanceof GpxLayer)
507- return createAndOpenSaveFileChooser(tr("Save GPX file"), ".gpx");
508- return createAndOpenSaveFileChooser(tr("Save Layer"), ".lay");
509+ return SaveActionBase.createAndOpenSaveFileChooser(tr("Save GPX file"), ".gpx");
510+ return SaveActionBase.createAndOpenSaveFileChooser(tr("Save Layer"), ".lay");
511 }
512
513- private static void copy(File src, File dst) throws IOException {
514+ public static void copy(File src, File dst) throws IOException {
515 FileInputStream srcStream;
516 FileOutputStream dstStream;
517 try {
518@@ -131,119 +133,6 @@
519 dstStream.close();
520 }
521
522- public static void save(File file, Layer layer) {
523- if (layer instanceof GpxLayer) {
524- save(file, (GpxLayer)layer);
525- ((GpxLayer)layer).data.storageFile = file;
526- } else if (layer instanceof OsmDataLayer) {
527- save(file, (OsmDataLayer)layer);
528- }
529- }
530-
531- public static void save(File file, OsmDataLayer layer) {
532- File tmpFile = null;
533- try {
534- GpxImporter gpxImExporter = new GpxImporter();
535- OsmImporter osmImExporter = new OsmImporter();
536- OsmGzipImporter osmGzipImporter = new OsmGzipImporter();
537- OsmBzip2Importer osmBzip2Importer = new OsmBzip2Importer();
538- if (gpxImExporter.acceptFile(file))
539- GpxExportAction.exportGpx(file, layer);
540- else if (osmImExporter.acceptFile(file)
541- || osmGzipImporter.acceptFile(file)
542- || osmBzip2Importer.acceptFile(file))
543- {
544- // use a tmp file because if something errors out in the
545- // process of writing the file, we might just end up with
546- // a truncated file. That can destroy lots of work.
547- if (file.exists()) {
548- tmpFile = new File(file.getPath() + "~");
549- copy(file, tmpFile);
550- }
551-
552- // create outputstream and wrap it with gzip or bzip, if necessary
553- OutputStream out = new FileOutputStream(file);
554- if(osmGzipImporter.acceptFile(file)) {
555- out = new GZIPOutputStream(out);
556- } else if(osmBzip2Importer.acceptFile(file)) {
557- out.write('B');
558- out.write('Z');
559- out = new CBZip2OutputStream(out);
560- }
561- Writer writer = new OutputStreamWriter(out, "UTF-8");
562-
563- OsmWriter w = new OsmWriter(new PrintWriter(writer), false, layer.data.version);
564- w.header();
565- w.writeDataSources(layer.data);
566- w.writeContent(layer.data);
567- w.footer();
568- w.close();
569- // FIXME - how to close?
570- if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null))
571- tmpFile.delete();
572- } else {
573- JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
574- return;
575- }
576- layer.cleanData(null, false);
577- } catch (IOException e) {
578- e.printStackTrace();
579- JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
580-
581- try {
582- // if the file save failed, then the tempfile will not
583- // be deleted. So, restore the backup if we made one.
584- if (tmpFile != null && tmpFile.exists()) {
585- copy(tmpFile, file);
586- }
587- } catch (IOException e2) {
588- e2.printStackTrace();
589- JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e2.getMessage());
590- }
591- }
592- }
593-
594- public static void save(File file, GpxLayer layer) {
595- File tmpFile = null;
596- try {
597- GpxImporter gpxImExporter = new GpxImporter();
598- if (gpxImExporter.acceptFile(file)) {
599-
600- // use a tmp file because if something errors out in the
601- // process of writing the file, we might just end up with
602- // a truncated file. That can destroy lots of work.
603- if (file.exists()) {
604- tmpFile = new File(file.getPath() + "~");
605- copy(file, tmpFile);
606- }
607- FileOutputStream fo = new FileOutputStream(file);
608- new GpxWriter(fo).write(layer.data);
609- fo.flush();
610- fo.close();
611-
612- if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
613- tmpFile.delete();
614- }
615- } else {
616- JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
617- return;
618- }
619- } catch (IOException e) {
620- e.printStackTrace();
621- JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
622- }
623- try {
624- // if the file save failed, then the tempfile will not
625- // be deleted. So, restore the backup if we made one.
626- if (tmpFile != null && tmpFile.exists()) {
627- copy(tmpFile, file);
628- }
629- } catch (IOException e) {
630- e.printStackTrace();
631- JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e.getMessage());
632- }
633- }
634-
635 /**
636 * Check the data set if it would be empty on save. It is empty, if it contains
637 * no objects (after all objects that are created and deleted without being
638@@ -257,4 +146,54 @@
639 return false;
640 return true;
641 }
642+
643+ public static File createAndOpenSaveFileChooser(String title,
644+ String extension)
645+ {
646+ String curDir = Main.pref.get("lastDirectory");
647+ if (curDir.equals("")) {
648+ curDir = ".";
649+ }
650+ JFileChooser fc = new JFileChooser(new File(curDir));
651+ if (title != null) {
652+ fc.setDialogTitle(title);
653+ }
654+
655+ fc.setMultiSelectionEnabled(false);
656+ for (FileExporter exporter: ExtensionFileFilter.exporters) {
657+ fc.addChoosableFileFilter(exporter.filter);
658+ }
659+
660+ fc.setAcceptAllFileFilterUsed(true);
661+
662+ int answer = fc.showSaveDialog(Main.parent);
663+ if (answer != JFileChooser.APPROVE_OPTION)
664+ return null;
665+
666+ if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) {
667+ Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
668+ }
669+
670+ File file = fc.getSelectedFile();
671+ if(extension != null)
672+ {
673+ String fn = file.getPath();
674+ if(fn.indexOf('.') == -1)
675+ {
676+ FileFilter ff = fc.getFileFilter();
677+ if (ff instanceof ExtensionFileFilter) {
678+ fn += "." + ((ExtensionFileFilter)ff).defaultExtension;
679+ } else {
680+ fn += extension;
681+ }
682+ file = new File(fn);
683+ }
684+ }
685+ if(file == null || (file.exists() && 1 != new ExtendedDialog(Main.parent,
686+ tr("Overwrite"), tr("File exists. Overwrite?"),
687+ new String[] {tr("Overwrite"), tr("Cancel")},
688+ new String[] {"save_as.png", "cancel.png"}).getValue()))
689+ return null;
690+ return file;
691+ }
692 }
693Index: src/org/openstreetmap/josm/io/FileExporter.java
694===================================================================
695--- src/org/openstreetmap/josm/io/FileExporter.java (revision 0)
696+++ src/org/openstreetmap/josm/io/FileExporter.java (revision 0)
697@@ -0,0 +1,26 @@
698+// License: GPL. For details, see LICENSE file.
699+package org.openstreetmap.josm.io;
700+
701+import static org.openstreetmap.josm.tools.I18n.tr;
702+
703+import java.io.File;
704+import java.io.IOException;
705+
706+import org.openstreetmap.josm.actions.ExtensionFileFilter;
707+import org.openstreetmap.josm.gui.layer.Layer;
708+
709+public abstract class FileExporter {
710+ public ExtensionFileFilter filter;
711+
712+ public FileExporter(ExtensionFileFilter filter) {
713+ this.filter=filter;
714+ }
715+
716+ public boolean acceptFile(File pathname) {
717+ return filter.acceptName(pathname.getName());
718+ }
719+
720+ public void exportData(File file,Layer layer) throws IOException {
721+ throw new IOException(tr("Could not export \"{0}\"", file.getName()));
722+ }
723+}
724Index: src/org/openstreetmap/josm/io/GpxExporter.java
725===================================================================
726--- src/org/openstreetmap/josm/io/GpxExporter.java (revision 0)
727+++ src/org/openstreetmap/josm/io/GpxExporter.java (revision 0)
728@@ -0,0 +1,256 @@
729+// License: GPL. For details, see LICENSE file.
730+package org.openstreetmap.josm.io;
731+
732+import static org.openstreetmap.josm.tools.I18n.tr;
733+
734+import java.awt.GridBagLayout;
735+import java.awt.event.ActionEvent;
736+import java.awt.event.ActionListener;
737+import java.awt.event.KeyAdapter;
738+import java.awt.event.KeyEvent;
739+import java.io.File;
740+import java.io.FileOutputStream;
741+import java.io.IOException;
742+import java.util.Calendar;
743+
744+import javax.swing.JButton;
745+import javax.swing.JCheckBox;
746+import javax.swing.JLabel;
747+import javax.swing.JList;
748+import javax.swing.JOptionPane;
749+import javax.swing.JPanel;
750+import javax.swing.JScrollPane;
751+import javax.swing.JTextArea;
752+import javax.swing.JTextField;
753+import javax.swing.ListSelectionModel;
754+
755+import org.openstreetmap.josm.Main;
756+import org.openstreetmap.josm.actions.ExtensionFileFilter;
757+import org.openstreetmap.josm.actions.GpxExportAction;
758+import org.openstreetmap.josm.data.gpx.GpxData;
759+import org.openstreetmap.josm.gui.ExtendedDialog;
760+import org.openstreetmap.josm.gui.layer.GpxLayer;
761+import org.openstreetmap.josm.gui.layer.Layer;
762+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
763+import org.openstreetmap.josm.tools.GBC;
764+
765+public class GpxExporter extends FileExporter{
766+
767+ public GpxExporter() {
768+ super(new ExtensionFileFilter("gpx,gpx.gz", "gpx", tr("GPX Files") + " (*.gpx *.gpx.gz)"));
769+ }
770+
771+
772+ private static void enableCopyright(final JTextField copyright, final JButton predefined, final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel, final JLabel warning, boolean enable) {
773+ copyright.setEnabled(enable);
774+ predefined.setEnabled(enable);
775+ copyrightYear.setEnabled(enable);
776+ copyrightLabel.setEnabled(enable);
777+ copyrightYearLabel.setEnabled(enable);
778+ warning.setText(enable ? GpxExportAction.warningGpl : "<html><font size='-2'>&nbsp;</html");
779+
780+ if (enable && copyrightYear.getText().length()==0) {
781+ copyrightYear.setText(enable ? Integer.toString(Calendar.getInstance().get(Calendar.YEAR)) : "");
782+ } else if (!enable) {
783+ copyrightYear.setText("");
784+ }
785+
786+ if (enable && copyright.getText().length()==0) {
787+ copyright.setText(enable ? Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5") : "");
788+ copyright.setCaretPosition(0);
789+ } else if (!enable) {
790+ copyright.setText("");
791+ }
792+ }
793+
794+ /**
795+ * Add all those listeners to handle the enable state of the fields.
796+ * @param copyrightYearLabel
797+ * @param copyrightLabel
798+ * @param emailLabel
799+ * @param nameLabel
800+ * @param warning
801+ */
802+ private static void addDependencies(
803+ final JCheckBox author,
804+ final JTextField authorName,
805+ final JTextField email,
806+ final JTextField copyright,
807+ final JButton predefined,
808+ final JTextField copyrightYear,
809+ final JLabel nameLabel,
810+ final JLabel emailLabel,
811+ final JLabel copyrightLabel,
812+ final JLabel copyrightYearLabel,
813+ final JLabel warning) {
814+
815+ ActionListener authorActionListener = new ActionListener(){
816+ public void actionPerformed(ActionEvent e) {
817+ boolean b = author.isSelected();
818+ authorName.setEnabled(b);
819+ email.setEnabled(b);
820+ nameLabel.setEnabled(b);
821+ emailLabel.setEnabled(b);
822+ authorName.setText(b ? Main.pref.get("lastAuthorName") : "");
823+ email.setText(b ? Main.pref.get("osm-server.username") : "");
824+
825+ boolean authorSet = authorName.getText().length() != 0;
826+ enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && authorSet);
827+ }
828+ };
829+ author.addActionListener(authorActionListener);
830+
831+ KeyAdapter authorNameListener = new KeyAdapter(){
832+ @Override public void keyReleased(KeyEvent e) {
833+ boolean b = authorName.getText().length()!=0 && author.isSelected();
834+ enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
835+ }
836+ };
837+ authorName.addKeyListener(authorNameListener);
838+
839+ predefined.addActionListener(new ActionListener(){
840+ public void actionPerformed(ActionEvent e) {
841+ JList l = new JList(new String[]{"Creative Commons By-SA", "public domain", "GNU Lesser Public License (LGPL)", "BSD License (MIT/X11)"});
842+ l.setVisibleRowCount(4);
843+ l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
844+ int answer = JOptionPane.showConfirmDialog(Main.parent, new JScrollPane(l),tr("Choose a predefined license"), JOptionPane.OK_CANCEL_OPTION);
845+ if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
846+ return;
847+ final String[] urls = {
848+ "http://creativecommons.org/licenses/by-sa/2.5",
849+ "public domain",
850+ "http://www.gnu.org/copyleft/lesser.html",
851+ "http://www.opensource.org/licenses/bsd-license.php"};
852+ String license = "";
853+ for (int i : l.getSelectedIndices()) {
854+ if (i == 1) {
855+ license = "public domain";
856+ break;
857+ }
858+ license += license.length()==0 ? urls[i] : ", "+urls[i];
859+ }
860+ copyright.setText(license);
861+ copyright.setCaretPosition(0);
862+ }
863+ });
864+
865+ authorActionListener.actionPerformed(null);
866+ authorNameListener.keyReleased(null);
867+ }
868+
869+ @Override
870+ public void exportData(File file,Layer layer) throws IOException {
871+ String fn = file.getPath();
872+ if (fn.indexOf('.') == -1) {
873+ fn += ".gpx";
874+ file = new File(fn);
875+ }
876+
877+ // open the dialog asking for options
878+ JPanel p = new JPanel(new GridBagLayout());
879+
880+ p.add(new JLabel(tr("gps track description")), GBC.eol());
881+ JTextArea desc = new JTextArea(3,40);
882+ desc.setWrapStyleWord(true);
883+ desc.setLineWrap(true);
884+ p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
885+
886+ JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true));
887+ author.setSelected(true);
888+ p.add(author, GBC.eol());
889+ JLabel nameLabel = new JLabel(tr("Real name"));
890+ p.add(nameLabel, GBC.std().insets(10,0,5,0));
891+ JTextField authorName = new JTextField(Main.pref.get("lastAuthorName"));
892+ p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
893+ JLabel emailLabel = new JLabel(tr("E-Mail"));
894+ p.add(emailLabel, GBC.std().insets(10,0,5,0));
895+ JTextField email = new JTextField(Main.pref.get("osm-server.username"));
896+ p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
897+ JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
898+ p.add(copyrightLabel, GBC.std().insets(10,0,5,0));
899+ JTextField copyright = new JTextField();
900+ p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
901+ JButton predefined = new JButton(tr("Predefined"));
902+ p.add(predefined, GBC.eol().insets(5,0,0,0));
903+ JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
904+ p.add(copyrightYearLabel, GBC.std().insets(10,0,5,5));
905+ JTextField copyrightYear = new JTextField("");
906+ p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
907+ JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
908+ p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15,0,0,0));
909+ GpxExporter.addDependencies(author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel, copyrightLabel, copyrightYearLabel, warning);
910+
911+ // if the user name is not the email address, but the osm user name
912+ // move it from the email textfield to the author textfield
913+ if(!email.getText().contains("@")) {
914+ authorName.setText(email.getText());
915+ email.setText("");
916+ }
917+
918+ p.add(new JLabel(tr("Keywords")), GBC.eol());
919+ JTextField keywords = new JTextField();
920+ p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
921+
922+ int answer = new ExtendedDialog(Main.parent,
923+ tr("Export options"),
924+ p,
925+ new String[] {tr("Export and Save"), tr("Cancel")},
926+ new String[] {"exportgpx.png", "cancel.png"}).getValue();
927+ if (answer != 1)
928+ return;
929+
930+ Main.pref.put("lastAddAuthor", author.isSelected());
931+ if (authorName.getText().length() != 0) {
932+ Main.pref.put("lastAuthorName", authorName.getText());
933+ }
934+ if (copyright.getText().length() != 0) {
935+ Main.pref.put("lastCopyright", copyright.getText());
936+ }
937+
938+ GpxData gpxData;
939+ if (layer instanceof OsmDataLayer) {
940+ gpxData = ((OsmDataLayer)layer).toGpxData();
941+ } else if (layer instanceof GpxLayer) {
942+ gpxData = ((GpxLayer)layer).data;
943+ } else {
944+ gpxData = OsmDataLayer.toGpxData(Main.ds, file);
945+ }
946+
947+ // add author and copyright details to the gpx data
948+ if(author.isSelected()) {
949+ if(authorName.getText().length() > 0) {
950+ gpxData.attr.put(GpxData.META_AUTHOR_NAME, authorName.getText());
951+ gpxData.attr.put(GpxData.META_COPYRIGHT_AUTHOR, authorName.getText());
952+ }
953+ if(email.getText().length() > 0) {
954+ gpxData.attr.put(GpxData.META_AUTHOR_EMAIL, email.getText());
955+ }
956+ if(copyright.getText().length() > 0) {
957+ gpxData.attr.put(GpxData.META_COPYRIGHT_LICENSE, copyright.getText());
958+ }
959+ if(copyrightYear.getText().length() > 0) {
960+ gpxData.attr.put(GpxData.META_COPYRIGHT_YEAR, copyrightYear.getText());
961+ }
962+ }
963+
964+ // add the description to the gpx data
965+ if(desc.getText().length() > 0) {
966+ gpxData.attr.put(GpxData.META_DESC, desc.getText());
967+ }
968+
969+ // add keywords to the gpx data
970+ if(keywords.getText().length() > 0) {
971+ gpxData.attr.put(GpxData.META_KEYWORDS, keywords.getText());
972+ }
973+
974+ try {
975+ FileOutputStream fo = new FileOutputStream(file);
976+ new GpxWriter(fo).write(gpxData);
977+ fo.flush();
978+ fo.close();
979+ } catch (IOException x) {
980+ x.printStackTrace();
981+ JOptionPane.showMessageDialog(Main.parent, tr("Error while exporting {0}:\n{1}", fn,x.getMessage()), tr("Error"), JOptionPane.ERROR_MESSAGE);
982+ }
983+ }
984+}
985Index: src/org/openstreetmap/josm/io/OsmBzip2Exporter.java
986===================================================================
987--- src/org/openstreetmap/josm/io/OsmBzip2Exporter.java (revision 0)
988+++ src/org/openstreetmap/josm/io/OsmBzip2Exporter.java (revision 0)
989@@ -0,0 +1,30 @@
990+// License: GPL. For details, see LICENSE file.
991+package org.openstreetmap.josm.io;
992+
993+import static org.openstreetmap.josm.tools.I18n.tr;
994+
995+import java.io.File;
996+import java.io.FileNotFoundException;
997+import java.io.FileOutputStream;
998+import java.io.IOException;
999+import java.io.OutputStream;
1000+
1001+import org.apache.tools.bzip2.CBZip2OutputStream;
1002+import org.openstreetmap.josm.actions.ExtensionFileFilter;
1003+
1004+public class OsmBzip2Exporter extends OsmExporter {
1005+
1006+ public OsmBzip2Exporter() {
1007+ super(new ExtensionFileFilter("osm.bz2, osm.bz", "osm.bz2", tr("OSM Server Files bzip2 compressed")
1008+ + " (*.osm.bz2 *.osm.bz)"));
1009+ }
1010+
1011+ @Override
1012+ protected OutputStream getOutputStream(File file) throws FileNotFoundException,IOException {
1013+ OutputStream out = new FileOutputStream(file);
1014+ out.write('B');
1015+ out.write('Z');
1016+ out = new CBZip2OutputStream(out);
1017+ return out;
1018+ }
1019+}
1020Index: src/org/openstreetmap/josm/io/OsmExporter.java
1021===================================================================
1022--- src/org/openstreetmap/josm/io/OsmExporter.java (revision 0)
1023+++ src/org/openstreetmap/josm/io/OsmExporter.java (revision 0)
1024@@ -0,0 +1,129 @@
1025+// License: GPL. For details, see LICENSE file.
1026+package org.openstreetmap.josm.io;
1027+
1028+import static org.openstreetmap.josm.tools.I18n.tr;
1029+
1030+import java.io.File;
1031+import java.io.FileNotFoundException;
1032+import java.io.FileOutputStream;
1033+import java.io.IOException;
1034+import java.io.OutputStream;
1035+import java.io.OutputStreamWriter;
1036+import java.io.PrintWriter;
1037+import java.io.Writer;
1038+import javax.swing.JOptionPane;
1039+import org.openstreetmap.josm.Main;
1040+import org.openstreetmap.josm.actions.ExtensionFileFilter;
1041+import org.openstreetmap.josm.actions.SaveActionBase;
1042+import org.openstreetmap.josm.gui.layer.GpxLayer;
1043+import org.openstreetmap.josm.gui.layer.Layer;
1044+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
1045+
1046+public class OsmExporter extends FileExporter {
1047+
1048+ public OsmExporter() {
1049+ super(new ExtensionFileFilter("osm,xml", "osm", tr("OSM Server Files") + " (*.osm *.xml)"));
1050+ }
1051+
1052+ public OsmExporter(ExtensionFileFilter filter) {
1053+ super(filter);
1054+ }
1055+
1056+ @Override
1057+ public void exportData(File file, Layer layer) throws IOException {
1058+ if (layer instanceof GpxLayer) {
1059+ save(file, (GpxLayer)layer);
1060+ ((GpxLayer)layer).data.storageFile = file;
1061+ } else if (layer instanceof OsmDataLayer) {
1062+ save(file, (OsmDataLayer)layer);
1063+ }
1064+ }
1065+
1066+ private void save(File file, OsmDataLayer layer) {
1067+ File tmpFile = null;
1068+ try {
1069+ // use a tmp file because if something errors out in the
1070+ // process of writing the file, we might just end up with
1071+ // a truncated file. That can destroy lots of work.
1072+ if (file.exists()) {
1073+ tmpFile = new File(file.getPath() + "~");
1074+ SaveActionBase.copy(file, tmpFile);
1075+ }
1076+
1077+ // create outputstream and wrap it with gzip or bzip, if necessary
1078+ OutputStream out = getOutputStream(file);
1079+ Writer writer = new OutputStreamWriter(out, "UTF-8");
1080+
1081+ OsmWriter w = new OsmWriter(new PrintWriter(writer), false, layer.data.version);
1082+ w.header();
1083+ w.writeDataSources(layer.data);
1084+ w.writeContent(layer.data);
1085+ w.footer();
1086+ w.close();
1087+ // FIXME - how to close?
1088+ if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
1089+ tmpFile.delete();
1090+ }
1091+ layer.cleanData(null, false);
1092+ } catch (IOException e) {
1093+ e.printStackTrace();
1094+ JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
1095+
1096+ try {
1097+ // if the file save failed, then the tempfile will not
1098+ // be deleted. So, restore the backup if we made one.
1099+ if (tmpFile != null && tmpFile.exists()) {
1100+ SaveActionBase.copy(tmpFile, file);
1101+ }
1102+ } catch (IOException e2) {
1103+ e2.printStackTrace();
1104+ JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e2.getMessage());
1105+ }
1106+ }
1107+ }
1108+
1109+ protected OutputStream getOutputStream(File file) throws FileNotFoundException,IOException {
1110+ return new FileOutputStream(file);
1111+ }
1112+
1113+ private void save(File file, GpxLayer layer) {
1114+ File tmpFile = null;
1115+ try {
1116+ GpxImporter gpxImExporter = new GpxImporter();
1117+ if (gpxImExporter.acceptFile(file)) {
1118+
1119+ // use a tmp file because if something errors out in the
1120+ // process of writing the file, we might just end up with
1121+ // a truncated file. That can destroy lots of work.
1122+ if (file.exists()) {
1123+ tmpFile = new File(file.getPath() + "~");
1124+ SaveActionBase.copy(file, tmpFile);
1125+ }
1126+ FileOutputStream fo = (FileOutputStream) getOutputStream(file);
1127+ new GpxWriter(fo).write(layer.data);
1128+ fo.flush();
1129+ fo.close();
1130+
1131+ if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
1132+ tmpFile.delete();
1133+ }
1134+ } else {
1135+ JOptionPane.showMessageDialog(Main.parent, tr("Unknown file extension."));
1136+ return;
1137+ }
1138+ } catch (IOException e) {
1139+ e.printStackTrace();
1140+ JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while saving.")+"\n"+e.getMessage());
1141+ }
1142+ try {
1143+ // if the file save failed, then the tempfile will not
1144+ // be deleted. So, restore the backup if we made one.
1145+ if (tmpFile != null && tmpFile.exists()) {
1146+ SaveActionBase.copy(tmpFile, file);
1147+ }
1148+ } catch (IOException e) {
1149+ e.printStackTrace();
1150+ JOptionPane.showMessageDialog(Main.parent, tr("An error occurred while restoring backup file.")+"\n"+e.getMessage());
1151+ }
1152+ }
1153+}
1154Index: src/org/openstreetmap/josm/io/OsmGzipExporter.java
1155===================================================================
1156--- src/org/openstreetmap/josm/io/OsmGzipExporter.java (revision 0)
1157+++ src/org/openstreetmap/josm/io/OsmGzipExporter.java (revision 0)
1158@@ -0,0 +1,26 @@
1159+// License: GPL. For details, see LICENSE file.
1160+package org.openstreetmap.josm.io;
1161+
1162+import static org.openstreetmap.josm.tools.I18n.tr;
1163+
1164+import java.io.File;
1165+import java.io.FileNotFoundException;
1166+import java.io.FileOutputStream;
1167+import java.io.IOException;
1168+import java.io.OutputStream;
1169+import java.util.zip.GZIPOutputStream;
1170+
1171+import org.openstreetmap.josm.actions.ExtensionFileFilter;
1172+
1173+public class OsmGzipExporter extends OsmExporter {
1174+
1175+ public OsmGzipExporter() {
1176+ super(new ExtensionFileFilter("osm.gz", "osm.gz", tr("OSM Server Files gzip compressed") + " (*.osm.gz)"));
1177+ }
1178+
1179+ @Override
1180+ protected OutputStream getOutputStream(File file) throws FileNotFoundException, IOException {
1181+ OutputStream out = new FileOutputStream(file);
1182+ return new GZIPOutputStream(out);
1183+ }
1184+}