001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.io;
003
004 import static org.openstreetmap.josm.tools.I18n.tr;
005
006 import java.awt.GridBagLayout;
007 import java.awt.event.ActionEvent;
008 import java.awt.event.ActionListener;
009 import java.awt.event.KeyAdapter;
010 import java.awt.event.KeyEvent;
011 import java.io.File;
012 import java.io.FileOutputStream;
013 import java.io.IOException;
014 import java.text.MessageFormat;
015 import java.util.Calendar;
016
017 import javax.swing.JButton;
018 import javax.swing.JCheckBox;
019 import javax.swing.JLabel;
020 import javax.swing.JList;
021 import javax.swing.JOptionPane;
022 import javax.swing.JPanel;
023 import javax.swing.JScrollPane;
024 import javax.swing.JTextArea;
025 import javax.swing.JTextField;
026 import javax.swing.ListSelectionModel;
027
028 import org.openstreetmap.josm.Main;
029 import org.openstreetmap.josm.data.gpx.GpxData;
030 import org.openstreetmap.josm.data.osm.DataSet;
031 import org.openstreetmap.josm.gui.ExtendedDialog;
032 import org.openstreetmap.josm.gui.layer.GpxLayer;
033 import org.openstreetmap.josm.gui.layer.Layer;
034 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
035 import org.openstreetmap.josm.tools.CheckParameterUtil;
036 import org.openstreetmap.josm.tools.GBC;
037
038 public class GpxExporter extends FileExporter {
039 private final static String warningGpl = "<html><font color='red' size='-2'>"
040 + tr("Note: GPL is not compatible with the OSM license. Do not upload GPL licensed tracks.") + "</html>";
041
042 public GpxExporter() {
043 super(GpxImporter.FILE_FILTER);
044 }
045
046 @Override
047 public boolean acceptFile(File pathname, Layer layer) {
048 if (!(layer instanceof OsmDataLayer) && !(layer instanceof GpxLayer))
049 return false;
050 return super.acceptFile(pathname, layer);
051 }
052
053 @Override
054 public void exportData(File file, Layer layer) throws IOException {
055 CheckParameterUtil.ensureParameterNotNull(layer, "layer");
056 if (!(layer instanceof OsmDataLayer) && !(layer instanceof GpxLayer))
057 throw new IllegalArgumentException(MessageFormat.format("Expected instance of OsmDataLayer or GpxLayer. Got ''{0}''.", layer
058 .getClass().getName()));
059 CheckParameterUtil.ensureParameterNotNull(file, "file");
060
061 String fn = file.getPath();
062 if (fn.indexOf('.') == -1) {
063 fn += ".gpx";
064 file = new File(fn);
065 }
066
067 // open the dialog asking for options
068 JPanel p = new JPanel(new GridBagLayout());
069
070 GpxData gpxData;
071 // At this moment, we only need to know the attributes of the GpxData,
072 // conversion of OsmDataLayer (if needed) will be done after the dialog
073 // is closed.
074 if (layer instanceof GpxLayer) {
075 gpxData = ((GpxLayer) layer).data;
076 } else {
077 gpxData = new GpxData();
078 }
079
080 p.add(new JLabel(tr("GPS track description")), GBC.eol());
081 JTextArea desc = new JTextArea(3, 40);
082 desc.setWrapStyleWord(true);
083 desc.setLineWrap(true);
084 desc.setText((String) gpxData.attr.get(GpxData.META_DESC));
085 p.add(new JScrollPane(desc), GBC.eop().fill(GBC.BOTH));
086
087 JCheckBox author = new JCheckBox(tr("Add author information"), Main.pref.getBoolean("lastAddAuthor", true));
088 p.add(author, GBC.eol());
089 JLabel nameLabel = new JLabel(tr("Real name"));
090 p.add(nameLabel, GBC.std().insets(10, 0, 5, 0));
091 JTextField authorName = new JTextField();
092 p.add(authorName, GBC.eol().fill(GBC.HORIZONTAL));
093 JLabel emailLabel = new JLabel(tr("E-Mail"));
094 p.add(emailLabel, GBC.std().insets(10, 0, 5, 0));
095 JTextField email = new JTextField();
096 p.add(email, GBC.eol().fill(GBC.HORIZONTAL));
097 JLabel copyrightLabel = new JLabel(tr("Copyright (URL)"));
098 p.add(copyrightLabel, GBC.std().insets(10, 0, 5, 0));
099 JTextField copyright = new JTextField();
100 p.add(copyright, GBC.std().fill(GBC.HORIZONTAL));
101 JButton predefined = new JButton(tr("Predefined"));
102 p.add(predefined, GBC.eol().insets(5, 0, 0, 0));
103 JLabel copyrightYearLabel = new JLabel(tr("Copyright year"));
104 p.add(copyrightYearLabel, GBC.std().insets(10, 0, 5, 5));
105 JTextField copyrightYear = new JTextField("");
106 p.add(copyrightYear, GBC.eol().fill(GBC.HORIZONTAL));
107 JLabel warning = new JLabel("<html><font size='-2'> </html");
108 p.add(warning, GBC.eol().fill(GBC.HORIZONTAL).insets(15, 0, 0, 0));
109 addDependencies(gpxData, author, authorName, email, copyright, predefined, copyrightYear, nameLabel, emailLabel,
110 copyrightLabel, copyrightYearLabel, warning);
111
112 p.add(new JLabel(tr("Keywords")), GBC.eol());
113 JTextField keywords = new JTextField();
114 keywords.setText((String) gpxData.attr.get(GpxData.META_KEYWORDS));
115 p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
116
117 ExtendedDialog ed = new ExtendedDialog(Main.parent,
118 tr("Export options"),
119 new String[] { tr("Export and Save"), tr("Cancel") });
120 ed.setButtonIcons(new String[] { "exportgpx.png", "cancel.png" });
121 ed.setContent(p);
122 ed.showDialog();
123
124 if (ed.getValue() != 1)
125 return;
126
127 Main.pref.put("lastAddAuthor", author.isSelected());
128 if (authorName.getText().length() != 0) {
129 Main.pref.put("lastAuthorName", authorName.getText());
130 }
131 if (copyright.getText().length() != 0) {
132 Main.pref.put("lastCopyright", copyright.getText());
133 }
134
135 if (layer instanceof OsmDataLayer) {
136 gpxData = ((OsmDataLayer) layer).toGpxData();
137 } else if (layer instanceof GpxLayer) {
138 gpxData = ((GpxLayer) layer).data;
139 } else {
140 gpxData = OsmDataLayer.toGpxData(getCurrentDataSet(), file);
141 }
142
143 // add author and copyright details to the gpx data
144 if (author.isSelected()) {
145 if (authorName.getText().length() > 0) {
146 gpxData.attr.put(GpxData.META_AUTHOR_NAME, authorName.getText());
147 gpxData.attr.put(GpxData.META_COPYRIGHT_AUTHOR, authorName.getText());
148 }
149 if (email.getText().length() > 0) {
150 gpxData.attr.put(GpxData.META_AUTHOR_EMAIL, email.getText());
151 }
152 if (copyright.getText().length() > 0) {
153 gpxData.attr.put(GpxData.META_COPYRIGHT_LICENSE, copyright.getText());
154 }
155 if (copyrightYear.getText().length() > 0) {
156 gpxData.attr.put(GpxData.META_COPYRIGHT_YEAR, copyrightYear.getText());
157 }
158 }
159
160 // add the description to the gpx data
161 if (desc.getText().length() > 0) {
162 gpxData.attr.put(GpxData.META_DESC, desc.getText());
163 }
164
165 // add keywords to the gpx data
166 if (keywords.getText().length() > 0) {
167 gpxData.attr.put(GpxData.META_KEYWORDS, keywords.getText());
168 }
169
170 try {
171 FileOutputStream fo = new FileOutputStream(file);
172 new GpxWriter(fo).write(gpxData);
173 fo.flush();
174 fo.close();
175 } catch (IOException x) {
176 x.printStackTrace();
177 JOptionPane.showMessageDialog(Main.parent, tr("Error while exporting {0}:\n{1}", fn, x.getMessage()),
178 tr("Error"), JOptionPane.ERROR_MESSAGE);
179 }
180
181 }
182
183 private static void enableCopyright(final GpxData data, final JTextField copyright, final JButton predefined,
184 final JTextField copyrightYear, final JLabel copyrightLabel, final JLabel copyrightYearLabel,
185 final JLabel warning, boolean enable) {
186 copyright.setEnabled(enable);
187 predefined.setEnabled(enable);
188 copyrightYear.setEnabled(enable);
189 copyrightLabel.setEnabled(enable);
190 copyrightYearLabel.setEnabled(enable);
191 warning.setText(enable ? warningGpl : "<html><font size='-2'> </html");
192
193 if (enable) {
194 if (copyrightYear.getText().length()==0) {
195 String sCopyrightYear = (String) data.attr.get(GpxData.META_COPYRIGHT_YEAR);
196 if (sCopyrightYear == null) {
197 sCopyrightYear = Integer.toString(Calendar.getInstance().get(Calendar.YEAR));
198 }
199 copyrightYear.setText(sCopyrightYear);
200 }
201 if (copyright.getText().length()==0) {
202 String sCopyright = (String) data.attr.get(GpxData.META_COPYRIGHT_LICENSE);
203 if (sCopyright == null) {
204 sCopyright = Main.pref.get("lastCopyright", "http://creativecommons.org/licenses/by-sa/2.5");
205 }
206 copyright.setText(sCopyright);
207 copyright.setCaretPosition(0);
208 }
209 } else {
210 copyrightYear.setText("");
211 copyright.setText("");
212 }
213 }
214
215 /**
216 * Add all those listeners to handle the enable state of the fields.
217 * @param copyrightYearLabel
218 * @param copyrightLabel
219 * @param emailLabel
220 * @param nameLabel
221 * @param warning
222 */
223 private static void addDependencies(
224 final GpxData data,
225 final JCheckBox author,
226 final JTextField authorName,
227 final JTextField email,
228 final JTextField copyright,
229 final JButton predefined,
230 final JTextField copyrightYear,
231 final JLabel nameLabel,
232 final JLabel emailLabel,
233 final JLabel copyrightLabel,
234 final JLabel copyrightYearLabel,
235 final JLabel warning) {
236
237 ActionListener authorActionListener = new ActionListener(){
238 public void actionPerformed(ActionEvent e) {
239 boolean b = author.isSelected();
240 authorName.setEnabled(b);
241 email.setEnabled(b);
242 nameLabel.setEnabled(b);
243 emailLabel.setEnabled(b);
244 if (b) {
245 String sAuthorName = (String) data.attr.get(GpxData.META_AUTHOR_NAME);
246 if (sAuthorName == null) {
247 sAuthorName = Main.pref.get("lastAuthorName");
248 }
249 authorName.setText(sAuthorName);
250 String sEmail = (String) data.attr.get(GpxData.META_AUTHOR_EMAIL);
251 if (sEmail == null) {
252 sEmail = Main.pref.get("lastAuthorEmail");
253 }
254 email.setText(sEmail);
255 } else {
256 authorName.setText("");
257 email.setText("");
258 }
259 boolean isAuthorSet = authorName.getText().length() != 0;
260 GpxExporter.enableCopyright(data, copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b && isAuthorSet);
261 }
262 };
263 author.addActionListener(authorActionListener);
264
265 KeyAdapter authorNameListener = new KeyAdapter(){
266 @Override public void keyReleased(KeyEvent e) {
267 boolean b = authorName.getText().length()!=0 && author.isSelected();
268 GpxExporter.enableCopyright(data, copyright, predefined, copyrightYear, copyrightLabel, copyrightYearLabel, warning, b);
269 }
270 };
271 authorName.addKeyListener(authorNameListener);
272
273 predefined.addActionListener(new ActionListener(){
274 public void actionPerformed(ActionEvent e) {
275 final String[] licenses = {
276 "Creative Commons By-SA",
277 "Open Database License (ODbL)",
278 "public domain",
279 "GNU Lesser Public License (LGPL)",
280 "BSD License (MIT/X11)"};
281 JList l = new JList(licenses);
282 l.setVisibleRowCount(licenses.length);
283 l.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
284 int answer = JOptionPane.showConfirmDialog(
285 Main.parent,
286 new JScrollPane(l),
287 tr("Choose a predefined license"),
288 JOptionPane.OK_CANCEL_OPTION,
289 JOptionPane.QUESTION_MESSAGE
290 );
291 if (answer != JOptionPane.OK_OPTION || l.getSelectedIndex() == -1)
292 return;
293 final String[] urls = {
294 "http://creativecommons.org/licenses/by-sa/2.5",
295 "http://opendatacommons.org/licenses/odbl/1.0",
296 "public domain",
297 "http://www.gnu.org/copyleft/lesser.html",
298 "http://www.opensource.org/licenses/bsd-license.php"};
299 String license = "";
300 for (int i : l.getSelectedIndices()) {
301 if (i == 2) {
302 license = "public domain";
303 break;
304 }
305 license += license.length()==0 ? urls[i] : ", "+urls[i];
306 }
307 copyright.setText(license);
308 copyright.setCaretPosition(0);
309 }
310 });
311
312 authorActionListener.actionPerformed(null);
313 authorNameListener.keyReleased(null);
314 }
315
316 /**
317 * Replies the current dataset
318 *
319 * @return the current dataset. null, if no current dataset exists
320 */
321 private DataSet getCurrentDataSet() {
322 return Main.main.getCurrentDataSet();
323 }
324
325 }