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

Last change on this file since 15497 was 15497, checked in by Don-vip, 4 years ago

see #16796 - fix most of checkstyle/pmd/findbugs violations

  • Property svn:eol-style set to native
File size: 16.0 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.data.gpx.GpxConstants;
27import org.openstreetmap.josm.data.gpx.GpxData;
28import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
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.spi.preferences.Config;
39import org.openstreetmap.josm.tools.CheckParameterUtil;
40import org.openstreetmap.josm.tools.GBC;
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 exportData(file, layer, false);
82 }
83
84 @Override
85 public void exportDataQuiet(File file, Layer layer) throws IOException {
86 exportData(file, layer, true);
87 }
88
89 private void exportData(File file, Layer layer, boolean quiet) throws IOException {
90 CheckParameterUtil.ensureParameterNotNull(layer, "layer");
91 if (!(layer instanceof OsmDataLayer) && !(layer instanceof GpxLayer))
92 throw new IllegalArgumentException(MessageFormat.format("Expected instance of OsmDataLayer or GpxLayer. Got ''{0}''.", layer
93 .getClass().getName()));
94 CheckParameterUtil.ensureParameterNotNull(file, "file");
95
96 String fn = file.getPath();
97 if (fn.indexOf('.') == -1) {
98 fn += ".gpx";
99 file = new File(fn);
100 }
101
102 GpxData gpxData;
103 if (quiet) {
104 gpxData = getGpxData(layer, file);
105 try (OutputStream fo = Compression.getCompressedFileOutputStream(file)) {
106 GpxWriter w = new GpxWriter(fo);
107 w.write(gpxData);
108 w.close();
109 fo.flush();
110 }
111 return;
112 }
113
114 // open the dialog asking for options
115 JPanel p = new JPanel(new GridBagLayout());
116
117 // At this moment, we only need to know the attributes of the GpxData,
118 // conversion of OsmDataLayer (if needed) will be done after the dialog is closed.
119 if (layer instanceof GpxLayer) {
120 gpxData = ((GpxLayer) layer).data;
121 } else {
122 gpxData = new GpxData();
123 }
124
125 p.add(new JLabel(tr("GPS track description")), GBC.eol());
126 JosmTextArea desc = new JosmTextArea(3, 40);
127 desc.setWrapStyleWord(true);
128 desc.setLineWrap(true);
129 desc.setText(gpxData.getString(META_DESC));
130 p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
131
132 JCheckBox author = new JCheckBox(tr("Add author information"), Config.getPref().getBoolean("lastAddAuthor", true));
133 p.add(author, GBC.eol());
134
135 JLabel nameLabel = new JLabel(tr("Real name"));
136 p.add(nameLabel, GBC.std().insets(10, 0, 5, 0));
137 JosmTextField authorName = new JosmTextField();
138 p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
139 nameLabel.setLabelFor(authorName);
140
141 JLabel emailLabel = new JLabel(tr("E-Mail"));
142 p.add(emailLabel, GBC.std().insets(10, 0, 5, 0));
143 JosmTextField email = new JosmTextField();
144 p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
145 emailLabel.setLabelFor(email);
146
147 JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
148 p.add(copyrightLabel, GBC.std().insets(10, 0, 5, 0));
149 JosmTextField copyright = new JosmTextField();
150 p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
151 copyrightLabel.setLabelFor(copyright);
152
153 JButton predefined = new JButton(tr("Predefined"));
154 p.add(predefined, GBC.eol().insets(5, 0, 0, 0));
155
156 JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
157 p.add(copyrightYearLabel, GBC.std().insets(10, 0, 5, 5));
158 JosmTextField copyrightYear = new JosmTextField("");
159 p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
160 copyrightYearLabel.setLabelFor(copyrightYear);
161
162 JLabel warning = new JLabel("<html><font size='-2'>&nbsp;</html");
163 p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15, 0, 0, 0));
164 addDependencies(gpxData, author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel,
165 copyrightLabel, copyrightYearLabel, warning);
166
167 p.add(new JLabel(tr("Keywords")), GBC.eol());
168 JosmTextField keywords = new JosmTextField();
169 keywords.setText(gpxData.getString(META_KEYWORDS));
170 p.add(keywords, GBC.eol().fill(GBC.HORIZONTAL));
171
172 boolean sel = Config.getPref().getBoolean("gpx.export.colors", true);
173 JCheckBox colors = new JCheckBox(tr("Save track colors in GPX file"), sel);
174 p.add(colors, GBC.eol().fill(GBC.HORIZONTAL));
175 JCheckBox garmin = new JCheckBox(tr("Use Garmin compatible GPX extensions"),
176 Config.getPref().getBoolean("gpx.export.colors.garmin", false));
177 garmin.setEnabled(sel);
178 p.add(garmin, GBC.eol().fill(GBC.HORIZONTAL).insets(20, 0, 0, 0));
179
180 boolean hasPrefs = !gpxData.getLayerPrefs().isEmpty();
181 JCheckBox layerPrefs = new JCheckBox(tr("Save layer specific preferences"),
182 hasPrefs && Config.getPref().getBoolean("gpx.export.prefs", true));
183 layerPrefs.setEnabled(hasPrefs);
184 p.add(layerPrefs, GBC.eop().fill(GBC.HORIZONTAL));
185
186 ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(),
187 tr("Export options"),
188 tr("Export and Save"), tr("Cancel"))
189 .setButtonIcons("exportgpx", "cancel")
190 .setContent(p);
191
192 colors.addActionListener(l -> {
193 garmin.setEnabled(colors.isSelected());
194 });
195
196 garmin.addActionListener(l -> {
197 if (garmin.isSelected() && !ConditionalOptionPaneUtil.showConfirmationDialog(
198 "gpx_color_garmin",
199 ed,
200 new JLabel("<html>" + tr("Garmin track extensions only support 16 colors.") + "<br>"
201 + tr("If you continue, the closest supported track color will be used.")
202 + "</html>"),
203 tr("Information"),
204 JOptionPane.OK_CANCEL_OPTION,
205 JOptionPane.INFORMATION_MESSAGE,
206 JOptionPane.OK_OPTION)) {
207 garmin.setSelected(false);
208 }
209 });
210
211 if (ed.showDialog().getValue() != 1) {
212 setCanceled(true);
213 return;
214 }
215 setCanceled(false);
216
217 Config.getPref().putBoolean("lastAddAuthor", author.isSelected());
218 if (!authorName.getText().isEmpty()) {
219 Config.getPref().put("lastAuthorName", authorName.getText());
220 }
221 if (!copyright.getText().isEmpty()) {
222 Config.getPref().put("lastCopyright", copyright.getText());
223 }
224 Config.getPref().putBoolean("gpx.export.colors", colors.isSelected());
225 Config.getPref().putBoolean("gpx.export.colors.garmin", garmin.isSelected());
226 if (hasPrefs) {
227 Config.getPref().putBoolean("gpx.export.prefs", layerPrefs.isSelected());
228 }
229 ColorFormat cFormat = null;
230 if (colors.isSelected()) {
231 cFormat = garmin.isSelected() ? ColorFormat.GPXX : ColorFormat.GPXD;
232 }
233
234 gpxData = getGpxData(layer, file);
235
236 // add author and copyright details to the gpx data
237 if (author.isSelected()) {
238 if (!authorName.getText().isEmpty()) {
239 gpxData.put(META_AUTHOR_NAME, authorName.getText());
240 gpxData.put(META_COPYRIGHT_AUTHOR, authorName.getText());
241 }
242 if (!email.getText().isEmpty()) {
243 gpxData.put(META_AUTHOR_EMAIL, email.getText());
244 }
245 if (!copyright.getText().isEmpty()) {
246 gpxData.put(META_COPYRIGHT_LICENSE, copyright.getText());
247 }
248 if (!copyrightYear.getText().isEmpty()) {
249 gpxData.put(META_COPYRIGHT_YEAR, copyrightYear.getText());
250 }
251 }
252
253 // add the description to the gpx data
254 if (!desc.getText().isEmpty()) {
255 gpxData.put(META_DESC, desc.getText());
256 }
257
258 // add keywords to the gpx data
259 if (!keywords.getText().isEmpty()) {
260 gpxData.put(META_KEYWORDS, keywords.getText());
261 }
262
263 try (OutputStream fo = Compression.getCompressedFileOutputStream(file)) {
264 GpxWriter w = new GpxWriter(fo);
265 w.write(gpxData, cFormat, layerPrefs.isSelected());
266 w.close();
267 fo.flush();
268 }
269 }
270
271 private static GpxData getGpxData(Layer layer, File file) {
272 if (layer instanceof OsmDataLayer) {
273 return ((OsmDataLayer) layer).toGpxData();
274 } else if (layer instanceof GpxLayer) {
275 return ((GpxLayer) layer).data;
276 }
277 return OsmDataLayer.toGpxData(MainApplication.getLayerManager().getEditDataSet(), file);
278 }
279
280 private static void enableCopyright(final GpxData data, final JosmTextField copyright, final JButton predefined,
281 final JosmTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel,
282 final JLabel warning, boolean enable) {
283 copyright.setEnabled(enable);
284 predefined.setEnabled(enable);
285 copyrightYear.setEnabled(enable);
286 copyrightLabel.setEnabled(enable);
287 copyrightYearLabel.setEnabled(enable);
288 warning.setText(enable ? GPL_WARNING : "<html><font size='-2'>&nbsp;</html");
289
290 if (enable) {
291 if (copyrightYear.getText().isEmpty()) {
292 copyrightYear.setText(Optional.ofNullable(data.getString(META_COPYRIGHT_YEAR)).orElseGet(
293 () -> Year.now().toString()));
294 }
295 if (copyright.getText().isEmpty()) {
296 copyright.setText(Optional.ofNullable(data.getString(META_COPYRIGHT_LICENSE)).orElseGet(
297 () -> Config.getPref().get("lastCopyright", "https://creativecommons.org/licenses/by-sa/2.5")));
298 copyright.setCaretPosition(0);
299 }
300 } else {
301 copyrightYear.setText("");
302 copyright.setText("");
303 }
304 }
305
306 // CHECKSTYLE.OFF: ParameterNumber
307
308 /**
309 * Add all those listeners to handle the enable state of the fields.
310 * @param data GPX data
311 * @param author Author checkbox
312 * @param authorName Author name textfield
313 * @param email E-mail textfield
314 * @param copyright Copyright textfield
315 * @param predefined Predefined button
316 * @param copyrightYear Copyright year textfield
317 * @param nameLabel Name label
318 * @param emailLabel E-mail label
319 * @param copyrightLabel Copyright label
320 * @param copyrightYearLabel Copyright year label
321 * @param warning Warning label
322 */
323 private static void addDependencies(
324 final GpxData data,
325 final JCheckBox author,
326 final JosmTextField authorName,
327 final JosmTextField email,
328 final JosmTextField copyright,
329 final JButton predefined,
330 final JosmTextField copyrightYear,
331 final JLabel nameLabel,
332 final JLabel emailLabel,
333 final JLabel copyrightLabel,
334 final JLabel copyrightYearLabel,
335 final JLabel warning) {
336
337 // CHECKSTYLE.ON: ParameterNumber
338 ActionListener authorActionListener = e -> {
339 boolean b = author.isSelected();
340 authorName.setEnabled(b);
341 email.setEnabled(b);
342 nameLabel.setEnabled(b);
343 emailLabel.setEnabled(b);
344 if (b) {
345 authorName.setText(Optional.ofNullable(data.getString(META_AUTHOR_NAME)).orElseGet(
346 () -> Config.getPref().get("lastAuthorName")));
347 email.setText(Optional.ofNullable(data.getString(META_AUTHOR_EMAIL)).orElseGet(
348 () -> Config.getPref().get("lastAuthorEmail")));
349 } else {
350 authorName.setText("");
351 email.setText("");
352 }
353 boolean isAuthorSet = !authorName.getText().isEmpty();
354 GpxExporter.enableCopyright(data, copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning,
355 b && isAuthorSet);
356 };
357 author.addActionListener(authorActionListener);
358
359 KeyAdapter authorNameListener = new KeyAdapter() {
360 @Override public void keyReleased(KeyEvent e) {
361 boolean b = !authorName.getText().isEmpty() && author.isSelected();
362 GpxExporter.enableCopyright(data, copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
363 }
364 };
365 authorName.addKeyListener(authorNameListener);
366
367 predefined.addActionListener(e -> {
368 JList<String> l = new JList<>(LICENSES);
369 l.setVisibleRowCount(LICENSES.length);
370 l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
371 int answer = JOptionPane.showConfirmDialog(
372 MainApplication.getMainFrame(),
373 new JScrollPane(l),
374 tr("Choose a predefined license"),
375 JOptionPane.OK_CANCEL_OPTION,
376 JOptionPane.QUESTION_MESSAGE
377 );
378 if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
379 return;
380 StringBuilder license = new StringBuilder();
381 for (int i : l.getSelectedIndices()) {
382 if (i == 2) {
383 license = new StringBuilder("public domain");
384 break;
385 }
386 if (license.length() > 0) {
387 license.append(", ");
388 }
389 license.append(URLS[i]);
390 }
391 copyright.setText(license.toString());
392 copyright.setCaretPosition(0);
393 });
394
395 authorActionListener.actionPerformed(null);
396 authorNameListener.keyReleased(null);
397 }
398}
Note: See TracBrowser for help on using the repository browser.