Index: src/org/openstreetmap/josm/actions/DiskAccessAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/DiskAccessAction.java	(revision 1946)
+++ src/org/openstreetmap/josm/actions/DiskAccessAction.java	(working copy)
@@ -5,7 +5,6 @@
 
 import java.io.File;
 import javax.swing.JFileChooser;
-import javax.swing.filechooser.FileFilter;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.tools.Shortcut;
@@ -58,51 +57,4 @@
 
         return fc;
     }
-
-    public static File createAndOpenSaveFileChooser(String title, String extension) {
-        String curDir = Main.pref.get("lastDirectory");
-        if (curDir.equals("")) {
-            curDir = ".";
-        }
-        JFileChooser fc = new JFileChooser(new File(curDir));
-        if (title != null) {
-            fc.setDialogTitle(title);
-        }
-
-        fc.setMultiSelectionEnabled(false);
-        for (FileImporter imExporter: ExtensionFileFilter.importers) {
-            fc.addChoosableFileFilter(imExporter.filter);
-        }
-
-        fc.setAcceptAllFileFilterUsed(true);
-
-        int answer = fc.showSaveDialog(Main.parent);
-        if (answer != JFileChooser.APPROVE_OPTION)
-            return null;
-
-        if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) {
-            Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
-        }
-
-        File file = fc.getSelectedFile();
-        if(extension != null){
-            String fn = file.getPath();
-            if(fn.indexOf('.') == -1)
-            {
-                FileFilter ff = fc.getFileFilter();
-                if (ff instanceof ExtensionFileFilter) {
-                    fn += "." + ((ExtensionFileFilter)ff).defaultExtension;
-                } else {
-                    fn += extension;
-                }
-                file = new File(fn);
-            }
-        }
-        if(file == null || (file.exists() && 1 != new ExtendedDialog(Main.parent,
-                tr("Overwrite"), tr("File exists. Overwrite?"),
-                new String[] {tr("Overwrite"), tr("Cancel")},
-                new String[] {"save_as.png", "cancel.png"}).getValue()))
-            return null;
-        return file;
-    }
 }
Index: src/org/openstreetmap/josm/actions/ExtensionFileFilter.java
===================================================================
--- src/org/openstreetmap/josm/actions/ExtensionFileFilter.java	(revision 1946)
+++ src/org/openstreetmap/josm/actions/ExtensionFileFilter.java	(working copy)
@@ -7,10 +7,15 @@
 
 import javax.swing.filechooser.FileFilter;
 
+import org.openstreetmap.josm.io.FileExporter;
 import org.openstreetmap.josm.io.FileImporter;
+import org.openstreetmap.josm.io.GpxExporter;
 import org.openstreetmap.josm.io.GpxImporter;
 import org.openstreetmap.josm.io.NMEAImporter;
+import org.openstreetmap.josm.io.OsmBzip2Exporter;
 import org.openstreetmap.josm.io.OsmBzip2Importer;
+import org.openstreetmap.josm.io.OsmExporter;
+import org.openstreetmap.josm.io.OsmGzipExporter;
 import org.openstreetmap.josm.io.OsmGzipImporter;
 import org.openstreetmap.josm.io.OsmImporter;
 
@@ -28,6 +33,10 @@
     public static ArrayList<FileImporter> importers = new ArrayList<FileImporter>(Arrays.asList(new OsmImporter(),
             new OsmGzipImporter(), new OsmBzip2Importer(), new GpxImporter(), new NMEAImporter()));
 
+    // list of supported export formats
+    public static ArrayList<FileExporter> exporters = new ArrayList<FileExporter>(Arrays.asList(new GpxExporter(),
+            new OsmExporter(), new OsmGzipExporter(), new OsmBzip2Exporter()));
+
     /**
      * Construct an extension file filter by giving the extension to check after.
      *
Index: src/org/openstreetmap/josm/actions/GpxExportAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/GpxExportAction.java	(revision 1946)
+++ src/org/openstreetmap/josm/actions/GpxExportAction.java	(working copy)
@@ -1,39 +1,22 @@
 // License: GPL. Copyright 2007 by Immanuel Scholz and others
 package org.openstreetmap.josm.actions;
 
+import static org.openstreetmap.josm.actions.SaveActionBase.createAndOpenSaveFileChooser;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.util.Calendar;
 
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JFileChooser;
-import javax.swing.JLabel;
-import javax.swing.JList;
 import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.gpx.GpxData;
-import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.OptionPaneUtil;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.io.GpxWriter;
-import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.io.FileExporter;
 import org.openstreetmap.josm.tools.Shortcut;
 
 /**
@@ -41,7 +24,6 @@
  */
 public class GpxExportAction extends DiskAccessAction {
 
-    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>";
 
     public GpxExportAction() {
         super(tr("Export to GPX..."), "exportgpx", tr("Export the data to GPX file."),
@@ -90,255 +72,18 @@
         if (! (layer instanceof OsmDataLayer) && ! (layer instanceof GpxLayer))
             throw new IllegalArgumentException(tr("expected instance of OsmDataLayer or GpxLayer. Got ''{0}''.", layer.getClass().getName()));
 
-        JFileChooser fc = createAndOpenFileChooser(false, false, null);
-        if (fc == null)
-            return;
-        File file = fc.getSelectedFile();
+        File file = createAndOpenSaveFileChooser(tr("Export GPX file"), ".gpx");
         if (file == null)
             return;
 
-        exportGpx(file, layer);
-    }
-
-    /**
-     * Exports a layer to a file.
-     * 
-     * <code>layer</code> must not be null. <code>layer</code> must be an instance of
-     * {@see OsmDataLayer} or {@see GpxLayer}.
-     * 
-     * @param layer the layer
-     * @exception IllegalArgumentException thrown if layer is null
-     * @exception IllegalArgumentException thrown if layer is neither an instance of {@see OsmDataLayer}
-     *  nor of {@see GpxLayer}
-     */
-
-    public void exportGpx(File file, Layer layer) {
-        if (layer == null)
-            throw new IllegalArgumentException(tr("paramenter ''{0}'' must not be null", "layer"));
-        if (! (layer instanceof OsmDataLayer) && ! (layer instanceof GpxLayer))
-            throw new IllegalArgumentException(tr("expected instance of OsmDataLayer or GpxLayer. Got ''{0}''.", layer.getClass().getName()));
-        if (file == null)
-            throw new IllegalArgumentException(tr("paramenter ''{0}'' must not be null", "file"));
-
-        String fn = file.getPath();
-        if (fn.indexOf('.') == -1) {
-            fn += ".gpx";
-            file = new File(fn);
-        }
-
-        // open the dialog asking for options
-        JPanel p = new JPanel(new GridBagLayout());
-
-        p.add(new JLabel(tr("gps track description")), GBC.eol());
-        JTextArea desc = new JTextArea(3,40);
-        desc.setWrapStyleWord(true);
-        desc.setLineWrap(true);
-        p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
-
-        JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true));
-        author.setSelected(true);
-        p.add(author, GBC.eol());
-        JLabel nameLabel = new JLabel(tr("Real name"));
-        p.add(nameLabel, GBC.std().insets(10,0,5,0));
-        JTextField authorName = new JTextField(Main.pref.get("lastAuthorName"));
-        p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
-        JLabel emailLabel = new JLabel(tr("E-Mail"));
-        p.add(emailLabel, GBC.std().insets(10,0,5,0));
-        JTextField email = new JTextField(Main.pref.get("osm-server.username"));
-        p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
-        JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
-        p.add(copyrightLabel, GBC.std().insets(10,0,5,0));
-        JTextField copyright = new JTextField();
-        p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
-        JButton predefined = new JButton(tr("Predefined"));
-        p.add(predefined, GBC.eol().insets(5,0,0,0));
-        JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
-        p.add(copyrightYearLabel, GBC.std().insets(10,0,5,5));
-        JTextField copyrightYear = new JTextField("");
-        p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
-        JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
-        p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15,0,0,0));
-        addDependencies(author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel, copyrightLabel, copyrightYearLabel, warning);
-
-        // if the user name is not the email address, but the osm user name
-        // move it from the email textfield to the author textfield
-        if(!email.getText().contains("@")) {
-            authorName.setText(email.getText());
-            email.setText("");
-        }
-
-        p.add(new JLabel(tr("Keywords")), GBC.eol());
-        JTextField keywords = new JTextField();
-        p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
-
-        int answer = new ExtendedDialog(Main.parent,
-                tr("Export options"),
-                p,
-                new String[] {tr("Export and Save"), tr("Cancel")},
-                new String[] {"exportgpx.png", "cancel.png"}).getValue();
-        if (answer != 1)
-            return;
-
-        Main.pref.put("lastAddAuthor", author.isSelected());
-        if (authorName.getText().length() != 0) {
-            Main.pref.put("lastAuthorName", authorName.getText());
-        }
-        if (copyright.getText().length() != 0) {
-            Main.pref.put("lastCopyright", copyright.getText());
-        }
-
-        GpxData gpxData;
-        if (layer instanceof OsmDataLayer) {
-            gpxData = ((OsmDataLayer)layer).toGpxData();
-        } else if (layer instanceof GpxLayer) {
-            gpxData = ((GpxLayer)layer).data;
-        } else {
-            gpxData = OsmDataLayer.toGpxData(getCurrentDataSet(), file);
-        }
-
-        // add author and copyright details to the gpx data
-        if(author.isSelected()) {
-            if(authorName.getText().length() > 0) {
-                gpxData.attr.put(GpxData.META_AUTHOR_NAME, authorName.getText());
-                gpxData.attr.put(GpxData.META_COPYRIGHT_AUTHOR, authorName.getText());
-            }
-            if(email.getText().length() > 0) {
-                gpxData.attr.put(GpxData.META_AUTHOR_EMAIL, email.getText());
-            }
-            if(copyright.getText().length() > 0) {
-                gpxData.attr.put(GpxData.META_COPYRIGHT_LICENSE, copyright.getText());
-            }
-            if(copyrightYear.getText().length() > 0) {
-                gpxData.attr.put(GpxData.META_COPYRIGHT_YEAR, copyrightYear.getText());
-            }
-        }
-
-        // add the description to the gpx data
-        if(desc.getText().length() > 0) {
-            gpxData.attr.put(GpxData.META_DESC, desc.getText());
-        }
-
-        // add keywords to the gpx data
-        if(keywords.getText().length() > 0) {
-            gpxData.attr.put(GpxData.META_KEYWORDS, keywords.getText());
-        }
-
-        try {
-            FileOutputStream fo = new FileOutputStream(file);
-            new GpxWriter(fo).write(gpxData);
-            fo.flush();
-            fo.close();
-        } catch (IOException x) {
-            x.printStackTrace();
-            OptionPaneUtil.showMessageDialog(
-                    Main.parent,
-                    tr("Error while exporting {0}:\n{1}", fn,x.getMessage()),
-                    tr("Error"),
-                    JOptionPane.ERROR_MESSAGE
-            );
-        }
-    }
-
-    /**
-     * Add all those listeners to handle the enable state of the fields.
-     * @param copyrightYearLabel
-     * @param copyrightLabel
-     * @param emailLabel
-     * @param nameLabel
-     * @param warning
-     */
-    private static void addDependencies(
-            final JCheckBox author,
-            final JTextField authorName,
-            final JTextField email,
-            final JTextField copyright,
-            final JButton predefined,
-            final JTextField copyrightYear,
-            final JLabel nameLabel,
-            final JLabel emailLabel,
-            final JLabel copyrightLabel,
-            final JLabel copyrightYearLabel,
-            final JLabel warning) {
-
-        ActionListener authorActionListener = new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                boolean b = author.isSelected();
-                authorName.setEnabled(b);
-                email.setEnabled(b);
-                nameLabel.setEnabled(b);
-                emailLabel.setEnabled(b);
-                authorName.setText(b ? Main.pref.get("lastAuthorName") : "");
-                email.setText(b ? Main.pref.get("osm-server.username") : "");
-
-                boolean authorSet = authorName.getText().length() != 0;
-                enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && authorSet);
-            }
-        };
-        author.addActionListener(authorActionListener);
-
-        KeyAdapter authorNameListener = new KeyAdapter(){
-            @Override public void keyReleased(KeyEvent e) {
-                boolean b = authorName.getText().length()!=0 && author.isSelected();
-                enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
-            }
-        };
-        authorName.addKeyListener(authorNameListener);
-
-        predefined.addActionListener(new ActionListener(){
-            public void actionPerformed(ActionEvent e) {
-                JList l = new JList(new String[]{"Creative Commons By-SA", "public domain", "GNU Lesser Public License (LGPL)", "BSD License (MIT/X11)"});
-                l.setVisibleRowCount(4);
-                l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-                int answer = OptionPaneUtil.showConfirmationDialog(
-                        Main.parent,
-                        new JScrollPane(l),
-                        tr("Choose a predefined license"),
-                        JOptionPane.OK_CANCEL_OPTION,
-                        JOptionPane.QUESTION_MESSAGE
-                );
-                if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
-                    return;
-                final String[] urls = {
-                        "http://creativecommons.org/licenses/by-sa/2.5",
-                        "public domain",
-                        "http://www.gnu.org/copyleft/lesser.html",
-                "http://www.opensource.org/licenses/bsd-license.php"};
-                String license = "";
-                for (int i : l.getSelectedIndices()) {
-                    if (i == 1) {
-                        license = "public domain";
-                        break;
-                    }
-                    license += license.length()==0 ? urls[i] : ", "+urls[i];
+        for (FileExporter exporter : ExtensionFileFilter.exporters) {
+            if (exporter.acceptFile(file, layer)) {
+                try {
+                    exporter.exportData(file, layer);
+                } catch (IOException e1) {
+                    e1.printStackTrace();
                 }
-                copyright.setText(license);
-                copyright.setCaretPosition(0);
             }
-        });
-
-        authorActionListener.actionPerformed(null);
-        authorNameListener.keyReleased(null);
-    }
-
-    private static void enableCopyright(final JTextField copyright, final JButton predefined, final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel, final JLabel warning, boolean enable) {
-        copyright.setEnabled(enable);
-        predefined.setEnabled(enable);
-        copyrightYear.setEnabled(enable);
-        copyrightLabel.setEnabled(enable);
-        copyrightYearLabel.setEnabled(enable);
-        warning.setText(enable ? warningGpl : "<html><font size='-2'>&nbsp;</html");
-
-        if (enable && copyrightYear.getText().length()==0) {
-            copyrightYear.setText(enable ? Integer.toString(Calendar.getInstance().get(Calendar.YEAR)) : "");
-        } else if (!enable) {
-            copyrightYear.setText("");
-        }
-
-        if (enable && copyright.getText().length()==0) {
-            copyright.setText(enable ? Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5") : "");
-            copyright.setCaretPosition(0);
-        } else if (!enable) {
-            copyright.setText("");
         }
     }
 
Index: src/org/openstreetmap/josm/actions/SaveActionBase.java
===================================================================
--- src/org/openstreetmap/josm/actions/SaveActionBase.java	(revision 1946)
+++ src/org/openstreetmap/josm/actions/SaveActionBase.java	(working copy)
@@ -5,19 +5,12 @@
 
 import java.awt.event.ActionEvent;
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.Writer;
-import java.util.zip.GZIPOutputStream;
 
+import javax.swing.JFileChooser;
 import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
 
-import org.apache.tools.bzip2.CBZip2OutputStream;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.conflict.ConflictCollection;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -26,12 +19,7 @@
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.io.GpxImporter;
-import org.openstreetmap.josm.io.GpxWriter;
-import org.openstreetmap.josm.io.OsmBzip2Importer;
-import org.openstreetmap.josm.io.OsmGzipImporter;
-import org.openstreetmap.josm.io.OsmImporter;
-import org.openstreetmap.josm.io.OsmWriter;
+import org.openstreetmap.josm.io.FileExporter;
 import org.openstreetmap.josm.tools.Shortcut;
 
 public abstract class SaveActionBase extends DiskAccessAction {
@@ -69,11 +57,26 @@
         if (file == null)
             return false;
 
-        save(file, layer);
-
-        layer.setName(file.getName());
-        layer.setAssociatedFile(file);
-        Main.parent.repaint();
+        try {
+            boolean exported = false;
+            for (FileExporter exporter : ExtensionFileFilter.exporters) {
+                if (exporter.acceptFile(file, layer)) {
+                    exporter.exportData(file, layer);
+                    exported = true;
+                }
+            }
+            if (!exported) {
+                OptionPaneUtil.showMessageDialog(Main.parent, tr("No Exporter found! Nothing saved."), tr("Warning"),
+                        JOptionPane.WARNING_MESSAGE);
+                return false;
+            }
+            layer.setName(file.getName());
+            layer.setAssociatedFile(file);
+            Main.parent.repaint();
+        } catch (IOException e) {
+            e.printStackTrace();
+            return false;
+        }
         return true;
     }
 
@@ -131,173 +134,6 @@
         return createAndOpenSaveFileChooser(tr("Save Layer"), ".lay");
     }
 
-    private static void copy(File src, File dst) throws IOException {
-        FileInputStream srcStream;
-        FileOutputStream dstStream;
-        try {
-            srcStream = new FileInputStream(src);
-            dstStream = new FileOutputStream(dst);
-        } catch (FileNotFoundException e) {
-            OptionPaneUtil.showMessageDialog(
-                    Main.parent,
-                    tr("Could not back up file. Exception is: {0}", e.getMessage()),
-                    tr("Error"),
-                    JOptionPane.ERROR_MESSAGE
-            );
-            return;
-        }
-        byte buf[] = new byte[1<<16];
-        int len;
-        while ((len = srcStream.read(buf)) != -1) {
-            dstStream.write(buf, 0, len);
-        }
-        srcStream.close();
-        dstStream.close();
-    }
-
-    public static void save(File file, Layer layer) {
-        if (layer instanceof GpxLayer) {
-            save(file, (GpxLayer)layer);
-            ((GpxLayer)layer).data.storageFile = file;
-        } else if (layer instanceof OsmDataLayer) {
-            save(file, (OsmDataLayer)layer);
-        }
-    }
-
-    public static void save(File file, OsmDataLayer layer) {
-        File tmpFile = null;
-        try {
-            GpxImporter gpxImExporter = new GpxImporter();
-            OsmImporter osmImExporter = new OsmImporter();
-            OsmGzipImporter osmGzipImporter = new OsmGzipImporter();
-            OsmBzip2Importer osmBzip2Importer = new OsmBzip2Importer();
-            if (gpxImExporter.acceptFile(file)) {
-                new GpxExportAction().exportGpx(file, layer);
-            } else if (osmImExporter.acceptFile(file)
-                    || osmGzipImporter.acceptFile(file)
-                    || osmBzip2Importer.acceptFile(file))
-            {
-                // use a tmp file because if something errors out in the
-                // process of writing the file, we might just end up with
-                // a truncated file.  That can destroy lots of work.
-                if (file.exists()) {
-                    tmpFile = new File(file.getPath() + "~");
-                    copy(file, tmpFile);
-                }
-
-                // create outputstream and wrap it with gzip or bzip, if necessary
-                OutputStream out = new FileOutputStream(file);
-                if(osmGzipImporter.acceptFile(file)) {
-                    out = new GZIPOutputStream(out);
-                } else if(osmBzip2Importer.acceptFile(file)) {
-                    out.write('B');
-                    out.write('Z');
-                    out = new CBZip2OutputStream(out);
-                }
-                Writer writer = new OutputStreamWriter(out, "UTF-8");
-
-                OsmWriter w = new OsmWriter(new PrintWriter(writer), false, layer.data.version);
-                w.header();
-                w.writeDataSources(layer.data);
-                w.writeContent(layer.data);
-                w.footer();
-                w.close();
-                // FIXME - how to close?
-                if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
-                    tmpFile.delete();
-                }
-            } else {
-                OptionPaneUtil.showMessageDialog(
-                        Main.parent,
-                        tr("Unknown file extension for file ''{0}''", file.toString()),
-                        tr("Error"),
-                        JOptionPane.ERROR_MESSAGE
-                );
-                return;
-            }
-            layer.cleanupAfterSaveToDisk();
-        } catch (IOException e) {
-            e.printStackTrace();
-            OptionPaneUtil.showMessageDialog(
-                    Main.parent,
-                    tr("<html>An error occurred while saving.<br>Error is: <br>{0}</html>", e.getMessage()),
-                    tr("Error"),
-                    JOptionPane.ERROR_MESSAGE
-            );
-
-            try {
-                // if the file save failed, then the tempfile will not
-                // be deleted.  So, restore the backup if we made one.
-                if (tmpFile != null && tmpFile.exists()) {
-                    copy(tmpFile, file);
-                }
-            } catch (IOException e2) {
-                e2.printStackTrace();
-                OptionPaneUtil.showMessageDialog(
-                        Main.parent,
-                        tr("<html>An error occurred while restoring backup file.<br>Error is: <br>{0}</html>", e2.getMessage()),
-                        tr("Error"),
-                        JOptionPane.ERROR_MESSAGE
-                );
-            }
-        }
-    }
-
-    public static void save(File file, GpxLayer layer) {
-        File tmpFile = null;
-        try {
-            GpxImporter gpxImExporter = new GpxImporter();
-            if (gpxImExporter.acceptFile(file)) {
-
-                // use a tmp file because if something errors out in the
-                // process of writing the file, we might just end up with
-                // a truncated file.  That can destroy lots of work.
-                if (file.exists()) {
-                    tmpFile = new File(file.getPath() + "~");
-                    copy(file, tmpFile);
-                }
-                FileOutputStream fo = new FileOutputStream(file);
-                new GpxWriter(fo).write(layer.data);
-                fo.flush();
-                fo.close();
-
-                if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
-                    tmpFile.delete();
-                }
-            } else {
-                OptionPaneUtil.showMessageDialog(
-                        Main.parent,
-                        tr("Unknown file extension."),
-                        tr("Error"),
-                        JOptionPane.ERROR_MESSAGE
-                );
-                return;
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-            OptionPaneUtil.showMessageDialog(
-                    Main.parent,
-                    tr("An error occurred while saving. Error is: {0}", e.getMessage()),
-                    tr("Error"),
-                    JOptionPane.ERROR_MESSAGE
-            );
-        }
-        try {
-            // if the file save failed, then the tempfile will not
-            // be deleted.  So, restore the backup if we made one.
-            if (tmpFile != null && tmpFile.exists()) {
-                copy(tmpFile, file);
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-            OptionPaneUtil.showMessageDialog(
-                    Main.parent,
-                    tr("<html>An error occurred while restoring backup file.<br>Error is:<br>{0}</html>", e.getMessage()),
-                    tr("Error"),
-                    JOptionPane.ERROR_MESSAGE
-            );;
-        }
-    }
 
     /**
      * Check the data set if it would be empty on save. It is empty, if it contains
@@ -333,4 +169,59 @@
         Layer layer = Main.map.mapView.getActiveLayer();
         setEnabled(layer instanceof OsmDataLayer || layer instanceof GpxLayer);
     }
+
+    public static File createAndOpenSaveFileChooser(String title, String extension) {
+        String curDir = Main.pref.get("lastDirectory");
+        if (curDir.equals("")) {
+            curDir = ".";
+        }
+        JFileChooser fc = new JFileChooser(new File(curDir));
+        if (title != null) {
+            fc.setDialogTitle(title);
+        }
+
+        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
+        fc.setMultiSelectionEnabled(false);
+        fc.setAcceptAllFileFilterUsed(false);
+
+        FileFilter defaultFilter = null;
+        for (FileExporter exporter : ExtensionFileFilter.exporters) {
+            fc.addChoosableFileFilter(exporter.filter);
+            if (extension.endsWith(exporter.filter.defaultExtension)) {
+                defaultFilter = exporter.filter;
+            }
+        }
+        if (defaultFilter != null) {
+            fc.setFileFilter(defaultFilter);
+        }
+
+        int answer = fc.showSaveDialog(Main.parent);
+        if (answer != JFileChooser.APPROVE_OPTION)
+            return null;
+
+        if (!fc.getCurrentDirectory().getAbsolutePath().equals(curDir)) {
+            Main.pref.put("lastDirectory", fc.getCurrentDirectory().getAbsolutePath());
+        }
+
+        File file = fc.getSelectedFile();
+        if(extension != null){
+            String fn = file.getPath();
+            if(fn.indexOf('.') == -1)
+            {
+                FileFilter ff = fc.getFileFilter();
+                if (ff instanceof ExtensionFileFilter) {
+                    fn += "." + ((ExtensionFileFilter)ff).defaultExtension;
+                } else {
+                    fn += extension;
+                }
+                file = new File(fn);
+            }
+        }
+        if(file == null || (file.exists() && 1 != new ExtendedDialog(Main.parent,
+                tr("Overwrite"), tr("File exists. Overwrite?"),
+                new String[] {tr("Overwrite"), tr("Cancel")},
+                new String[] {"save_as.png", "cancel.png"}).getValue()))
+            return null;
+        return file;
+    }
 }
Index: src/org/openstreetmap/josm/io/FileExporter.java
===================================================================
--- src/org/openstreetmap/josm/io/FileExporter.java	(revision 0)
+++ src/org/openstreetmap/josm/io/FileExporter.java	(revision 0)
@@ -0,0 +1,26 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.openstreetmap.josm.actions.ExtensionFileFilter;
+import org.openstreetmap.josm.gui.layer.Layer;
+
+public abstract class FileExporter {
+    public ExtensionFileFilter filter;
+
+    public FileExporter(ExtensionFileFilter filter) {
+        this.filter = filter;
+    }
+
+    public boolean acceptFile(File pathname, Layer layer) {
+        return filter.acceptName(pathname.getName());
+    }
+
+    public void exportData(File file, Layer layer) throws IOException {
+        throw new IOException(tr("Could not export \"{0}\"", file.getName()));
+    }
+}
Index: src/org/openstreetmap/josm/io/GpxExporter.java
===================================================================
--- src/org/openstreetmap/josm/io/GpxExporter.java	(revision 0)
+++ src/org/openstreetmap/josm/io/GpxExporter.java	(revision 0)
@@ -0,0 +1,291 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Calendar;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.ExtensionFileFilter;
+import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.gui.OptionPaneUtil;
+import org.openstreetmap.josm.gui.layer.GpxLayer;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.tools.GBC;
+
+public class GpxExporter extends FileExporter {
+    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>";
+
+    public GpxExporter() {
+        super(new ExtensionFileFilter("gpx,gpx.gz", "gpx", tr("GPX Files") + " (*.gpx *.gpx.gz)"));
+    }
+
+    @Override
+    public boolean acceptFile(File pathname, Layer layer) {
+        if (!(layer instanceof OsmDataLayer) && !(layer instanceof GpxLayer))
+            return false;
+        return super.acceptFile(pathname, layer);
+    }
+
+    @Override
+    public void exportData(File file, Layer layer) throws IOException {
+        if (layer == null)
+            throw new IllegalArgumentException(tr("paramenter ''{0}'' must not be null", "layer"));
+        if (!(layer instanceof OsmDataLayer) && !(layer instanceof GpxLayer))
+            throw new IllegalArgumentException(tr("expected instance of OsmDataLayer or GpxLayer. Got ''{0}''.", layer
+                    .getClass().getName()));
+        if (file == null)
+            throw new IllegalArgumentException(tr("paramenter ''{0}'' must not be null", "file"));
+
+        String fn = file.getPath();
+        if (fn.indexOf('.') == -1) {
+            fn += ".gpx";
+            file = new File(fn);
+        }
+
+        // open the dialog asking for options
+        JPanel p = new JPanel(new GridBagLayout());
+
+        p.add(new JLabel(tr("gps track description")), GBC.eol());
+        JTextArea desc = new JTextArea(3, 40);
+        desc.setWrapStyleWord(true);
+        desc.setLineWrap(true);
+        p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
+
+        JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true));
+        author.setSelected(true);
+        p.add(author, GBC.eol());
+        JLabel nameLabel = new JLabel(tr("Real name"));
+        p.add(nameLabel, GBC.std().insets(10, 0, 5, 0));
+        JTextField authorName = new JTextField(Main.pref.get("lastAuthorName"));
+        p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
+        JLabel emailLabel = new JLabel(tr("E-Mail"));
+        p.add(emailLabel, GBC.std().insets(10, 0, 5, 0));
+        JTextField email = new JTextField(Main.pref.get("osm-server.username"));
+        p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
+        JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
+        p.add(copyrightLabel, GBC.std().insets(10, 0, 5, 0));
+        JTextField copyright = new JTextField();
+        p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
+        JButton predefined = new JButton(tr("Predefined"));
+        p.add(predefined, GBC.eol().insets(5, 0, 0, 0));
+        JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
+        p.add(copyrightYearLabel, GBC.std().insets(10, 0, 5, 5));
+        JTextField copyrightYear = new JTextField("");
+        p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
+        JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
+        p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15, 0, 0, 0));
+        addDependencies(author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel,
+                copyrightLabel, copyrightYearLabel, warning);
+
+        // if the user name is not the email address, but the osm user name
+        // move it from the email textfield to the author textfield
+        if (!email.getText().contains("@")) {
+            authorName.setText(email.getText());
+            email.setText("");
+        }
+
+        p.add(new JLabel(tr("Keywords")), GBC.eol());
+        JTextField keywords = new JTextField();
+        p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
+
+        int answer = new ExtendedDialog(Main.parent, tr("Export options"), p, new String[] { tr("Export and Save"),
+            tr("Cancel") }, new String[] { "exportgpx.png", "cancel.png" }).getValue();
+        if (answer != 1)
+            return;
+
+        Main.pref.put("lastAddAuthor", author.isSelected());
+        if (authorName.getText().length() != 0) {
+            Main.pref.put("lastAuthorName", authorName.getText());
+        }
+        if (copyright.getText().length() != 0) {
+            Main.pref.put("lastCopyright", copyright.getText());
+        }
+
+        GpxData gpxData;
+        if (layer instanceof OsmDataLayer) {
+            gpxData = ((OsmDataLayer) layer).toGpxData();
+        } else if (layer instanceof GpxLayer) {
+            gpxData = ((GpxLayer) layer).data;
+        } else {
+            gpxData = OsmDataLayer.toGpxData(getCurrentDataSet(), file);
+        }
+
+        // add author and copyright details to the gpx data
+        if (author.isSelected()) {
+            if (authorName.getText().length() > 0) {
+                gpxData.attr.put(GpxData.META_AUTHOR_NAME, authorName.getText());
+                gpxData.attr.put(GpxData.META_COPYRIGHT_AUTHOR, authorName.getText());
+            }
+            if (email.getText().length() > 0) {
+                gpxData.attr.put(GpxData.META_AUTHOR_EMAIL, email.getText());
+            }
+            if (copyright.getText().length() > 0) {
+                gpxData.attr.put(GpxData.META_COPYRIGHT_LICENSE, copyright.getText());
+            }
+            if (copyrightYear.getText().length() > 0) {
+                gpxData.attr.put(GpxData.META_COPYRIGHT_YEAR, copyrightYear.getText());
+            }
+        }
+
+        // add the description to the gpx data
+        if (desc.getText().length() > 0) {
+            gpxData.attr.put(GpxData.META_DESC, desc.getText());
+        }
+
+        // add keywords to the gpx data
+        if (keywords.getText().length() > 0) {
+            gpxData.attr.put(GpxData.META_KEYWORDS, keywords.getText());
+        }
+
+        try {
+            FileOutputStream fo = new FileOutputStream(file);
+            new GpxWriter(fo).write(gpxData);
+            fo.flush();
+            fo.close();
+        } catch (IOException x) {
+            x.printStackTrace();
+            OptionPaneUtil.showMessageDialog(Main.parent, tr("Error while exporting {0}:\n{1}", fn, x.getMessage()),
+                    tr("Error"), JOptionPane.ERROR_MESSAGE);
+        }
+
+    }
+
+    private static void enableCopyright(final JTextField copyright, final JButton predefined,
+            final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel,
+            final JLabel warning, boolean enable) {
+        copyright.setEnabled(enable);
+        predefined.setEnabled(enable);
+        copyrightYear.setEnabled(enable);
+        copyrightLabel.setEnabled(enable);
+        copyrightYearLabel.setEnabled(enable);
+        warning.setText(enable ? warningGpl : "<html><font size='-2'>&nbsp;</html");
+
+        if (enable && copyrightYear.getText().length()==0) {
+            copyrightYear.setText(enable ? Integer.toString(Calendar.getInstance().get(Calendar.YEAR)) : "");
+        } else if (!enable) {
+            copyrightYear.setText("");
+        }
+
+        if (enable && copyright.getText().length()==0) {
+            copyright.setText(enable ? Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5") : "");
+            copyright.setCaretPosition(0);
+        } else if (!enable) {
+            copyright.setText("");
+        }
+    }
+
+    /**
+     * Add all those listeners to handle the enable state of the fields.
+     * @param copyrightYearLabel
+     * @param copyrightLabel
+     * @param emailLabel
+     * @param nameLabel
+     * @param warning
+     */
+    private static void addDependencies(
+            final JCheckBox author,
+            final JTextField authorName,
+            final JTextField email,
+            final JTextField copyright,
+            final JButton predefined,
+            final JTextField copyrightYear,
+            final JLabel nameLabel,
+            final JLabel emailLabel,
+            final JLabel copyrightLabel,
+            final JLabel copyrightYearLabel,
+            final JLabel warning) {
+
+        ActionListener authorActionListener = new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                boolean b = author.isSelected();
+                authorName.setEnabled(b);
+                email.setEnabled(b);
+                nameLabel.setEnabled(b);
+                emailLabel.setEnabled(b);
+                authorName.setText(b ? Main.pref.get("lastAuthorName") : "");
+                email.setText(b ? Main.pref.get("osm-server.username") : "");
+
+                boolean authorSet = authorName.getText().length() != 0;
+                GpxExporter.enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && authorSet);
+            }
+        };
+        author.addActionListener(authorActionListener);
+
+        KeyAdapter authorNameListener = new KeyAdapter(){
+            @Override public void keyReleased(KeyEvent e) {
+                boolean b = authorName.getText().length()!=0 && author.isSelected();
+                GpxExporter.enableCopyright(copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
+            }
+        };
+        authorName.addKeyListener(authorNameListener);
+
+        predefined.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                JList l = new JList(new String[]{"Creative Commons By-SA", "public domain", "GNU Lesser Public License (LGPL)", "BSD License (MIT/X11)"});
+                l.setVisibleRowCount(4);
+                l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+                int answer = OptionPaneUtil.showConfirmationDialog(
+                        Main.parent,
+                        new JScrollPane(l),
+                        tr("Choose a predefined license"),
+                        JOptionPane.OK_CANCEL_OPTION,
+                        JOptionPane.QUESTION_MESSAGE
+                );
+                if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
+                    return;
+                final String[] urls = {
+                        "http://creativecommons.org/licenses/by-sa/2.5",
+                        "public domain",
+                        "http://www.gnu.org/copyleft/lesser.html",
+                "http://www.opensource.org/licenses/bsd-license.php"};
+                String license = "";
+                for (int i : l.getSelectedIndices()) {
+                    if (i == 1) {
+                        license = "public domain";
+                        break;
+                    }
+                    license += license.length()==0 ? urls[i] : ", "+urls[i];
+                }
+                copyright.setText(license);
+                copyright.setCaretPosition(0);
+            }
+        });
+
+        authorActionListener.actionPerformed(null);
+        authorNameListener.keyReleased(null);
+    }
+
+    /**
+     * Replies the current dataset
+     * 
+     * @return the current dataset. null, if no current dataset exists
+     */
+    private DataSet getCurrentDataSet() {
+        return Main.main.getCurrentDataSet();
+    }
+
+}
Index: src/org/openstreetmap/josm/io/OsmBzip2Exporter.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmBzip2Exporter.java	(revision 0)
+++ src/org/openstreetmap/josm/io/OsmBzip2Exporter.java	(revision 0)
@@ -0,0 +1,29 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.tools.bzip2.CBZip2OutputStream;
+import org.openstreetmap.josm.actions.ExtensionFileFilter;
+public class OsmBzip2Exporter extends OsmExporter {
+
+    public OsmBzip2Exporter() {
+        super(new ExtensionFileFilter("osm.bz2, osm.bz", "osm.bz2", tr("OSM Server Files bzip2 compressed")
+                + " (*.osm.bz2 *.osm.bz)"));
+    }
+
+    @Override
+    protected OutputStream getOutputStream(File file) throws FileNotFoundException, IOException {
+        OutputStream out = new FileOutputStream(file);
+        out.write('B');
+        out.write('Z');
+        out = new CBZip2OutputStream(out);
+        return out;
+    }
+}
Index: src/org/openstreetmap/josm/io/OsmExporter.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmExporter.java	(revision 0)
+++ src/org/openstreetmap/josm/io/OsmExporter.java	(revision 0)
@@ -0,0 +1,127 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.ExtensionFileFilter;
+import org.openstreetmap.josm.gui.OptionPaneUtil;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+
+public class OsmExporter extends FileExporter {
+
+    public OsmExporter() {
+        super(new ExtensionFileFilter("osm,xml", "osm", tr("OSM Server Files") + " (*.osm *.xml)"));
+    }
+
+    public OsmExporter(ExtensionFileFilter filter) {
+        super(filter);
+    }
+
+    @Override
+    public boolean acceptFile(File pathname, Layer layer) {
+        if (!(layer instanceof OsmDataLayer))
+            return false;
+        return super.acceptFile(pathname, layer);
+    }
+
+    @Override
+    public void exportData(File file, Layer layer) throws IOException {
+        if (layer instanceof OsmDataLayer) {
+            save(file, (OsmDataLayer) layer);
+        } else
+            throw new IllegalArgumentException(tr("Expected instance of OsmDataLayer. Got ''{0}''.", layer
+                    .getClass().getName()));
+    }
+
+    protected OutputStream getOutputStream(File file) throws FileNotFoundException, IOException {
+        return new FileOutputStream(file);
+    }
+
+    private void save(File file, OsmDataLayer layer) {
+        File tmpFile = null;
+        try {
+            // use a tmp file because if something errors out in the
+            // process of writing the file, we might just end up with
+            // a truncated file.  That can destroy lots of work.
+            if (file.exists()) {
+                tmpFile = new File(file.getPath() + "~");
+                copy(file, tmpFile);
+            }
+
+            // create outputstream and wrap it with gzip or bzip, if necessary
+            OutputStream out = getOutputStream(file);
+            Writer writer = new OutputStreamWriter(out, "UTF-8");
+
+            OsmWriter w = new OsmWriter(new PrintWriter(writer), false, layer.data.version);
+            w.header();
+            w.writeDataSources(layer.data);
+            w.writeContent(layer.data);
+            w.footer();
+            w.close();
+            // FIXME - how to close?
+            if (!Main.pref.getBoolean("save.keepbackup") && (tmpFile != null)) {
+                tmpFile.delete();
+            }
+            layer.cleanupAfterSaveToDisk();
+        } catch (IOException e) {
+            e.printStackTrace();
+            OptionPaneUtil.showMessageDialog(
+                    Main.parent,
+                    tr("<html>An error occurred while saving.<br>Error is: <br>{0}</html>", e.getMessage()),
+                    tr("Error"),
+                    JOptionPane.ERROR_MESSAGE
+            );
+
+            try {
+                // if the file save failed, then the tempfile will not
+                // be deleted.  So, restore the backup if we made one.
+                if (tmpFile != null && tmpFile.exists()) {
+                    copy(tmpFile, file);
+                }
+            } catch (IOException e2) {
+                e2.printStackTrace();
+                OptionPaneUtil.showMessageDialog(
+                        Main.parent,
+                        tr("<html>An error occurred while restoring backup file.<br>Error is: <br>{0}</html>", e2.getMessage()),
+                        tr("Error"),
+                        JOptionPane.ERROR_MESSAGE
+                );
+            }
+        }
+    }
+
+    private void copy(File src, File dst) throws IOException {
+        FileInputStream srcStream;
+        FileOutputStream dstStream;
+        try {
+            srcStream = new FileInputStream(src);
+            dstStream = new FileOutputStream(dst);
+        } catch (FileNotFoundException e) {
+            OptionPaneUtil.showMessageDialog(Main.parent, tr("Could not back up file. Exception is: {0}", e
+                    .getMessage()), tr("Error"), JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        byte buf[] = new byte[1 << 16];
+        int len;
+        while ((len = srcStream.read(buf)) != -1) {
+            dstStream.write(buf, 0, len);
+        }
+        srcStream.close();
+        dstStream.close();
+    }
+
+}
Index: src/org/openstreetmap/josm/io/OsmGzipExporter.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmGzipExporter.java	(revision 0)
+++ src/org/openstreetmap/josm/io/OsmGzipExporter.java	(revision 0)
@@ -0,0 +1,25 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.GZIPOutputStream;
+
+import org.openstreetmap.josm.actions.ExtensionFileFilter;
+public class OsmGzipExporter extends OsmExporter {
+
+    public OsmGzipExporter() {
+        super(new ExtensionFileFilter("osm.gz", "osm.gz", tr("OSM Server Files gzip compressed") + " (*.osm.gz)"));
+    }
+
+    @Override
+    protected OutputStream getOutputStream(File file) throws FileNotFoundException, IOException {
+        OutputStream out = new FileOutputStream(file);
+        return new GZIPOutputStream(out);
+    }
+}
