source: josm/trunk/src/org/openstreetmap/josm/gui/io/importexport/GpxExporter.java @ 12671

Last change on this file since 12671 was 12671, checked in by Don-vip, 7 weeks ago

see #15182 - move file importers/exporters from io package to gui.io.importexport package, as they rely heavily on GUI and are mainly used from Open/Save actions

  • Property svn:eol-style set to native
File size: 13.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.io.importexport;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagLayout;
7import java.awt.event.ActionListener;
8import java.awt.event.KeyAdapter;
9import java.awt.event.KeyEvent;
10import java.io.File;
11import java.io.IOException;
12import java.io.OutputStream;
13import java.text.MessageFormat;
14import java.time.Year;
15import java.util.Optional;
16
17import javax.swing.JButton;
18import javax.swing.JCheckBox;
19import javax.swing.JLabel;
20import javax.swing.JList;
21import javax.swing.JOptionPane;
22import javax.swing.JPanel;
23import javax.swing.JScrollPane;
24import javax.swing.ListSelectionModel;
25
26import org.openstreetmap.josm.Main;
27import org.openstreetmap.josm.data.gpx.GpxConstants;
28import org.openstreetmap.josm.data.gpx.GpxData;
29import org.openstreetmap.josm.gui.ExtendedDialog;
30import org.openstreetmap.josm.gui.MainApplication;
31import org.openstreetmap.josm.gui.layer.GpxLayer;
32import org.openstreetmap.josm.gui.layer.Layer;
33import org.openstreetmap.josm.gui.layer.OsmDataLayer;
34import org.openstreetmap.josm.gui.widgets.JosmTextArea;
35import org.openstreetmap.josm.gui.widgets.JosmTextField;
36import org.openstreetmap.josm.io.Compression;
37import org.openstreetmap.josm.io.GpxWriter;
38import org.openstreetmap.josm.tools.CheckParameterUtil;
39import org.openstreetmap.josm.tools.GBC;
40import org.openstreetmap.josm.tools.Logging;
41
42/**
43 * Exports data to a .gpx file. Data may be native GPX or OSM data which will be converted.
44 * @since 1949
45 */
46public class GpxExporter extends FileExporter implements GpxConstants {
47
48    private static final String GPL_WARNING = "<html><font color='red' size='-2'>"
49        + tr("Note: GPL is not compatible with the OSM license. Do not upload GPL licensed tracks.") + "</html>";
50
51    private static final String[] LICENSES = {
52            "Creative Commons By-SA",
53            "Open Database License (ODbL)",
54            "public domain",
55            "GNU Lesser Public License (LGPL)",
56            "BSD License (MIT/X11)"};
57
58    private static final String[] URLS = {
59            "https://creativecommons.org/licenses/by-sa/3.0",
60            "http://opendatacommons.org/licenses/odbl/1.0",
61            "public domain",
62            "https://www.gnu.org/copyleft/lesser.html",
63            "http://www.opensource.org/licenses/bsd-license.php"};
64
65    /**
66     * Constructs a new {@code GpxExporter}.
67     */
68    public GpxExporter() {
69        super(GpxImporter.getFileFilter());
70    }
71
72    @Override
73    public boolean acceptFile(File pathname, Layer layer) {
74        if (!(layer instanceof OsmDataLayer) && !(layer instanceof GpxLayer))
75            return false;
76        return super.acceptFile(pathname, layer);
77    }
78
79    @Override
80    public void exportData(File file, Layer layer) throws IOException {
81        CheckParameterUtil.ensureParameterNotNull(layer, "layer");
82        if (!(layer instanceof OsmDataLayer) && !(layer instanceof GpxLayer))
83            throw new IllegalArgumentException(MessageFormat.format("Expected instance of OsmDataLayer or GpxLayer. Got ''{0}''.", layer
84                    .getClass().getName()));
85        CheckParameterUtil.ensureParameterNotNull(file, "file");
86
87        String fn = file.getPath();
88        if (fn.indexOf('.') == -1) {
89            fn += ".gpx";
90            file = new File(fn);
91        }
92
93        // open the dialog asking for options
94        JPanel p = new JPanel(new GridBagLayout());
95
96        GpxData gpxData;
97        // At this moment, we only need to know the attributes of the GpxData,
98        // conversion of OsmDataLayer (if needed) will be done after the dialog is closed.
99        if (layer instanceof GpxLayer) {
100            gpxData = ((GpxLayer) layer).data;
101        } else {
102            gpxData = new GpxData();
103        }
104
105        p.add(new JLabel(tr("GPS track description")), GBC.eol());
106        JosmTextArea desc = new JosmTextArea(3, 40);
107        desc.setWrapStyleWord(true);
108        desc.setLineWrap(true);
109        desc.setText(gpxData.getString(META_DESC));
110        p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
111
112        JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true));
113        p.add(author, GBC.eol());
114
115        JLabel nameLabel = new JLabel(tr("Real name"));
116        p.add(nameLabel, GBC.std().insets(10, 0, 5, 0));
117        JosmTextField authorName = new JosmTextField();
118        p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
119        nameLabel.setLabelFor(authorName);
120
121        JLabel emailLabel = new JLabel(tr("E-Mail"));
122        p.add(emailLabel, GBC.std().insets(10, 0, 5, 0));
123        JosmTextField email = new JosmTextField();
124        p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
125        emailLabel.setLabelFor(email);
126
127        JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
128        p.add(copyrightLabel, GBC.std().insets(10, 0, 5, 0));
129        JosmTextField copyright = new JosmTextField();
130        p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
131        copyrightLabel.setLabelFor(copyright);
132
133        JButton predefined = new JButton(tr("Predefined"));
134        p.add(predefined, GBC.eol().insets(5, 0, 0, 0));
135
136        JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
137        p.add(copyrightYearLabel, GBC.std().insets(10, 0, 5, 5));
138        JosmTextField copyrightYear = new JosmTextField("");
139        p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
140        copyrightYearLabel.setLabelFor(copyrightYear);
141
142        JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
143        p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15, 0, 0, 0));
144        addDependencies(gpxData, author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel,
145                copyrightLabel, copyrightYearLabel, warning);
146
147        p.add(new JLabel(tr("Keywords")), GBC.eol());
148        JosmTextField keywords = new JosmTextField();
149        keywords.setText(gpxData.getString(META_KEYWORDS));
150        p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
151
152        ExtendedDialog ed = new ExtendedDialog(Main.parent,
153                tr("Export options"),
154                tr("Export and Save"), tr("Cancel"))
155            .setButtonIcons("exportgpx", "cancel")
156            .setContent(p);
157
158        if (ed.showDialog().getValue() != 1) {
159            setCanceled(true);
160            return;
161        }
162        setCanceled(false);
163
164        Main.pref.put("lastAddAuthor", author.isSelected());
165        if (!authorName.getText().isEmpty()) {
166            Main.pref.put("lastAuthorName", authorName.getText());
167        }
168        if (!copyright.getText().isEmpty()) {
169            Main.pref.put("lastCopyright", copyright.getText());
170        }
171
172        if (layer instanceof OsmDataLayer) {
173            gpxData = ((OsmDataLayer) layer).toGpxData();
174        } else if (layer instanceof GpxLayer) {
175            gpxData = ((GpxLayer) layer).data;
176        } else {
177            gpxData = OsmDataLayer.toGpxData(MainApplication.getLayerManager().getEditDataSet(), file);
178        }
179
180        // add author and copyright details to the gpx data
181        if (author.isSelected()) {
182            if (!authorName.getText().isEmpty()) {
183                gpxData.put(META_AUTHOR_NAME, authorName.getText());
184                gpxData.put(META_COPYRIGHT_AUTHOR, authorName.getText());
185            }
186            if (!email.getText().isEmpty()) {
187                gpxData.put(META_AUTHOR_EMAIL, email.getText());
188            }
189            if (!copyright.getText().isEmpty()) {
190                gpxData.put(META_COPYRIGHT_LICENSE, copyright.getText());
191            }
192            if (!copyrightYear.getText().isEmpty()) {
193                gpxData.put(META_COPYRIGHT_YEAR, copyrightYear.getText());
194            }
195        }
196
197        // add the description to the gpx data
198        if (!desc.getText().isEmpty()) {
199            gpxData.put(META_DESC, desc.getText());
200        }
201
202        // add keywords to the gpx data
203        if (!keywords.getText().isEmpty()) {
204            gpxData.put(META_KEYWORDS, keywords.getText());
205        }
206
207        try (OutputStream fo = Compression.getCompressedFileOutputStream(file)) {
208            new GpxWriter(fo).write(gpxData);
209            fo.flush();
210        } catch (IOException ex) {
211            Logging.error(ex);
212            JOptionPane.showMessageDialog(Main.parent, tr("Error while exporting {0}:\n{1}", fn, ex.getMessage()),
213                    tr("Error"), JOptionPane.ERROR_MESSAGE);
214        }
215    }
216
217    private static void enableCopyright(final GpxData data, final JosmTextField copyright, final JButton predefined,
218            final JosmTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel,
219            final JLabel warning, boolean enable) {
220        copyright.setEnabled(enable);
221        predefined.setEnabled(enable);
222        copyrightYear.setEnabled(enable);
223        copyrightLabel.setEnabled(enable);
224        copyrightYearLabel.setEnabled(enable);
225        warning.setText(enable ? GPL_WARNING : "<html><font size='-2'>&nbsp;</html");
226
227        if (enable) {
228            if (copyrightYear.getText().isEmpty()) {
229                copyrightYear.setText(Optional.ofNullable(data.getString(META_COPYRIGHT_YEAR)).orElseGet(
230                        () -> Year.now().toString()));
231            }
232            if (copyright.getText().isEmpty()) {
233                copyright.setText(Optional.ofNullable(data.getString(META_COPYRIGHT_LICENSE)).orElseGet(
234                        () -> Main.pref.get("lastCopyright", "https://creativecommons.org/licenses/by-sa/2.5")));
235                copyright.setCaretPosition(0);
236            }
237        } else {
238            copyrightYear.setText("");
239            copyright.setText("");
240        }
241    }
242
243    // CHECKSTYLE.OFF: ParameterNumber
244
245    /**
246     * Add all those listeners to handle the enable state of the fields.
247     * @param data GPX data
248     * @param author Author checkbox
249     * @param authorName Author name textfield
250     * @param email E-mail textfield
251     * @param copyright Copyright textfield
252     * @param predefined Predefined button
253     * @param copyrightYear Copyright year textfield
254     * @param nameLabel Name label
255     * @param emailLabel E-mail label
256     * @param copyrightLabel Copyright label
257     * @param copyrightYearLabel Copyright year label
258     * @param warning Warning label
259     */
260    private static void addDependencies(
261            final GpxData data,
262            final JCheckBox author,
263            final JosmTextField authorName,
264            final JosmTextField email,
265            final JosmTextField copyright,
266            final JButton predefined,
267            final JosmTextField copyrightYear,
268            final JLabel nameLabel,
269            final JLabel emailLabel,
270            final JLabel copyrightLabel,
271            final JLabel copyrightYearLabel,
272            final JLabel warning) {
273
274        // CHECKSTYLE.ON: ParameterNumber
275        ActionListener authorActionListener = e -> {
276            boolean b = author.isSelected();
277            authorName.setEnabled(b);
278            email.setEnabled(b);
279            nameLabel.setEnabled(b);
280            emailLabel.setEnabled(b);
281            if (b) {
282                authorName.setText(Optional.ofNullable(data.getString(META_AUTHOR_NAME)).orElseGet(() -> Main.pref.get("lastAuthorName")));
283                email.setText(Optional.ofNullable(data.getString(META_AUTHOR_EMAIL)).orElseGet(() -> Main.pref.get("lastAuthorEmail")));
284            } else {
285                authorName.setText("");
286                email.setText("");
287            }
288            boolean isAuthorSet = !authorName.getText().isEmpty();
289            GpxExporter.enableCopyright(data, copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning,
290                    b && isAuthorSet);
291        };
292        author.addActionListener(authorActionListener);
293
294        KeyAdapter authorNameListener = new KeyAdapter() {
295            @Override public void keyReleased(KeyEvent e) {
296                boolean b = !authorName.getText().isEmpty() && author.isSelected();
297                GpxExporter.enableCopyright(data, copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
298            }
299        };
300        authorName.addKeyListener(authorNameListener);
301
302        predefined.addActionListener(e -> {
303            JList<String> l = new JList<>(LICENSES);
304            l.setVisibleRowCount(LICENSES.length);
305            l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
306            int answer = JOptionPane.showConfirmDialog(
307                    Main.parent,
308                    new JScrollPane(l),
309                    tr("Choose a predefined license"),
310                    JOptionPane.OK_CANCEL_OPTION,
311                    JOptionPane.QUESTION_MESSAGE
312            );
313            if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
314                return;
315            StringBuilder license = new StringBuilder();
316            for (int i : l.getSelectedIndices()) {
317                if (i == 2) {
318                    license = new StringBuilder("public domain");
319                    break;
320                }
321                if (license.length() > 0) {
322                    license.append(", ");
323                }
324                license.append(URLS[i]);
325            }
326            copyright.setText(license.toString());
327            copyright.setCaretPosition(0);
328        });
329
330        authorActionListener.actionPerformed(null);
331        authorNameListener.keyReleased(null);
332    }
333}
Note: See TracBrowser for help on using the repository browser.