source: josm/trunk/src/org/openstreetmap/josm/io/GpxExporter.java@ 7438

Last change on this file since 7438 was 7414, checked in by Don-vip, 10 years ago

fix #10165 - Wrong waypoint order in exported GPX

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