001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io.session; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.CardLayout; 007import java.awt.Component; 008import java.awt.Font; 009import java.awt.GridBagLayout; 010import java.awt.event.ActionEvent; 011import java.awt.event.ActionListener; 012import java.awt.event.ItemEvent; 013import java.awt.event.ItemListener; 014import java.io.File; 015import java.io.IOException; 016import java.io.OutputStream; 017import java.io.OutputStreamWriter; 018import java.io.PrintWriter; 019import java.io.Writer; 020import java.net.MalformedURLException; 021import java.net.URI; 022import java.net.URL; 023import java.nio.charset.StandardCharsets; 024import java.util.Collection; 025import java.util.Collections; 026 027import javax.swing.ButtonGroup; 028import javax.swing.JCheckBox; 029import javax.swing.JLabel; 030import javax.swing.JPanel; 031import javax.swing.JRadioButton; 032import javax.swing.SwingConstants; 033 034import org.openstreetmap.josm.gui.layer.GpxLayer; 035import org.openstreetmap.josm.gui.layer.Layer; 036import org.openstreetmap.josm.gui.util.GuiHelper; 037import org.openstreetmap.josm.gui.widgets.JosmTextField; 038import org.openstreetmap.josm.io.GpxWriter; 039import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport; 040import org.openstreetmap.josm.tools.GBC; 041import org.w3c.dom.Element; 042 043public class GpxTracksSessionExporter implements SessionLayerExporter { 044 045 private final GpxLayer layer; 046 private JRadioButton link; 047 private JRadioButton include; 048 private JCheckBox export; 049 050 /** 051 * Constructs a new {@code GpxTracksSessionExporter}. 052 * @param layer GPX layer to export 053 */ 054 public GpxTracksSessionExporter(GpxLayer layer) { 055 this.layer = layer; 056 } 057 058 @Override 059 public Collection<Layer> getDependencies() { 060 return Collections.emptySet(); 061 } 062 063 @Override 064 public Component getExportPanel() { 065 final JPanel p = new JPanel(new GridBagLayout()); 066 JPanel topRow = new JPanel(new GridBagLayout()); 067 export = new JCheckBox(); 068 export.setSelected(true); 069 final JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEFT); 070 lbl.setToolTipText(layer.getToolTipText()); 071 lbl.setLabelFor(export); 072 JLabel lblData = new JLabel(tr("Data:")); 073 /* I18n: Refer to a OSM data file in session file */ link = new JRadioButton(tr("local file")); 074 link.putClientProperty("actionname", "link"); 075 link.setToolTipText(tr("Link to a GPX file on your local disk.")); 076 /* I18n: Include OSM data in session file */ include = new JRadioButton(tr("include")); 077 include.setToolTipText(tr("Include GPX data in the .joz session file.")); 078 include.putClientProperty("actionname", "include"); 079 ButtonGroup group = new ButtonGroup(); 080 group.add(link); 081 group.add(include); 082 083 JPanel cardLink = new JPanel(new GridBagLayout()); 084 final File file = layer.getAssociatedFile(); 085 if (file != null && file.exists()) { 086 JosmTextField tf = new JosmTextField(); 087 tf.setText(file.getPath()); 088 tf.setEditable(false); 089 cardLink.add(tf, GBC.std()); 090 } else { 091 cardLink.add(new JLabel(tr("No file association")), GBC.eol()); 092 } 093 094 JPanel cardInclude = new JPanel(new GridBagLayout()); 095 JLabel lblIncl = new JLabel(tr("GPX data will be included in the session file.")); 096 lblIncl.setFont(lblIncl.getFont().deriveFont(Font.PLAIN)); 097 cardInclude.add(lblIncl, GBC.eol().fill(GBC.HORIZONTAL)); 098 099 final CardLayout cl = new CardLayout(); 100 final JPanel cards = new JPanel(cl); 101 cards.add(cardLink, "link"); 102 cards.add(cardInclude, "include"); 103 104 if (file != null && file.exists()) { 105 link.setSelected(true); 106 } else { 107 link.setEnabled(false); 108 link.setToolTipText(tr("No file association")); 109 include.setSelected(true); 110 cl.show(cards, "include"); 111 } 112 113 link.addActionListener(new ActionListener() { 114 @Override 115 public void actionPerformed(ActionEvent e) { 116 cl.show(cards, "link"); 117 } 118 }); 119 include.addActionListener(new ActionListener() { 120 @Override 121 public void actionPerformed(ActionEvent e) { 122 cl.show(cards, "include"); 123 } 124 }); 125 126 topRow.add(export, GBC.std()); 127 topRow.add(lbl, GBC.std()); 128 topRow.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL)); 129 p.add(topRow, GBC.eol().fill(GBC.HORIZONTAL)); 130 p.add(lblData, GBC.std().insets(10, 0, 0, 0)); 131 p.add(link, GBC.std()); 132 p.add(include, GBC.eol()); 133 p.add(cards, GBC.eol().insets(15, 0, 3, 3)); 134 135 export.addItemListener(new ItemListener() { 136 @Override 137 public void itemStateChanged(ItemEvent e) { 138 if (e.getStateChange() == ItemEvent.DESELECTED) { 139 GuiHelper.setEnabledRec(p, false); 140 export.setEnabled(true); 141 } else { 142 GuiHelper.setEnabledRec(p, true); 143 link.setEnabled(file != null && file.exists()); 144 } 145 } 146 }); 147 return p; 148 } 149 150 @Override 151 public boolean shallExport() { 152 return export.isSelected(); 153 } 154 155 @Override 156 public boolean requiresZip() { 157 return include.isSelected(); 158 } 159 160 @Override 161 public Element export(ExportSupport support) throws IOException { 162 Element layerEl = support.createElement("layer"); 163 layerEl.setAttribute("type", "tracks"); 164 layerEl.setAttribute("version", "0.1"); 165 166 Element file = support.createElement("file"); 167 layerEl.appendChild(file); 168 169 if (requiresZip()) { 170 String zipPath = "layers/" + String.format("%02d", support.getLayerIndex()) + "/data.gpx"; 171 file.appendChild(support.createTextNode(zipPath)); 172 addDataFile(support.getOutputStreamZip(zipPath)); 173 } else { 174 URI uri = layer.getAssociatedFile().toURI(); 175 URL url = null; 176 try { 177 url = uri.toURL(); 178 } catch (MalformedURLException e) { 179 throw new IOException(e); 180 } 181 file.appendChild(support.createTextNode(url.toString())); 182 } 183 return layerEl; 184 } 185 186 @SuppressWarnings("resource") 187 protected void addDataFile(OutputStream out) { 188 Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); 189 GpxWriter w = new GpxWriter(new PrintWriter(writer)); 190 w.write(layer.data); 191 w.flush(); 192 } 193}