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.UnsupportedEncodingException; 020import java.io.Writer; 021import java.net.MalformedURLException; 022import java.net.URI; 023import java.net.URL; 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 GpxLayer layer; 046 private JRadioButton link, include; 047 private JCheckBox export; 048 049 public GpxTracksSessionExporter(GpxLayer layer) { 050 this.layer = layer; 051 } 052 053 @Override 054 public Collection<Layer> getDependencies() { 055 return Collections.emptySet(); 056 } 057 058 @Override 059 public Component getExportPanel() { 060 final JPanel p = new JPanel(new GridBagLayout()); 061 JPanel topRow = new JPanel(new GridBagLayout()); 062 export = new JCheckBox(); 063 export.setSelected(true); 064 final JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEFT); 065 lbl.setToolTipText(layer.getToolTipText()); 066 067 JLabel lblData = new JLabel(tr("Data:")); 068 /* I18n: Refer to a OSM data file in session file */ link = new JRadioButton(tr("local file")); 069 link.putClientProperty("actionname", "link"); 070 link.setToolTipText(tr("Link to a GPX file on your local disk.")); 071 /* I18n: Include OSM data in session file */ include = new JRadioButton(tr("include")); 072 include.setToolTipText(tr("Include GPX data in the .joz session file.")); 073 include.putClientProperty("actionname", "include"); 074 ButtonGroup group = new ButtonGroup(); 075 group.add(link); 076 group.add(include); 077 078 JPanel cardLink = new JPanel(new GridBagLayout()); 079 final File file = layer.getAssociatedFile(); 080 if (file != null) { 081 JosmTextField tf = new JosmTextField(); 082 tf.setText(file.getPath()); 083 tf.setEditable(false); 084 cardLink.add(tf, GBC.std()); 085 } else { 086 cardLink.add(new JLabel(tr("No file association")), GBC.eol()); 087 } 088 089 JPanel cardInclude = new JPanel(new GridBagLayout()); 090 JLabel lblIncl = new JLabel(tr("GPX data will be included in the session file.")); 091 lblIncl.setFont(lblIncl.getFont().deriveFont(Font.PLAIN)); 092 cardInclude.add(lblIncl, GBC.eol().fill(GBC.HORIZONTAL)); 093 094 final CardLayout cl = new CardLayout(); 095 final JPanel cards = new JPanel(cl); 096 cards.add(cardLink, "link"); 097 cards.add(cardInclude, "include"); 098 099 if (file != null) { 100 link.setSelected(true); 101 } else { 102 link.setEnabled(false); 103 link.setToolTipText(tr("No file association")); 104 include.setSelected(true); 105 cl.show(cards, "include"); 106 } 107 108 link.addActionListener(new ActionListener() { 109 @Override 110 public void actionPerformed(ActionEvent e) { 111 cl.show(cards, "link"); 112 } 113 }); 114 include.addActionListener(new ActionListener() { 115 @Override 116 public void actionPerformed(ActionEvent e) { 117 cl.show(cards, "include"); 118 } 119 }); 120 121 topRow.add(export, GBC.std()); 122 topRow.add(lbl, GBC.std()); 123 topRow.add(GBC.glue(1,0), GBC.std().fill(GBC.HORIZONTAL)); 124 p.add(topRow, GBC.eol().fill(GBC.HORIZONTAL)); 125 p.add(lblData, GBC.std().insets(10,0,0,0)); 126 p.add(link, GBC.std()); 127 p.add(include, GBC.eol()); 128 p.add(cards, GBC.eol().insets(15,0,3,3)); 129 130 export.addItemListener(new ItemListener() { 131 @Override 132 public void itemStateChanged(ItemEvent e) { 133 if (e.getStateChange() == ItemEvent.DESELECTED) { 134 GuiHelper.setEnabledRec(p, false); 135 export.setEnabled(true); 136 } else { 137 GuiHelper.setEnabledRec(p, true); 138 link.setEnabled(file != null); 139 } 140 } 141 }); 142 return p; 143 } 144 145 @Override 146 public boolean shallExport() { 147 return export.isSelected(); 148 } 149 150 @Override 151 public boolean requiresZip() { 152 return include.isSelected(); 153 } 154 155 @Override 156 public Element export(ExportSupport support) throws IOException { 157 Element layerEl = support.createElement("layer"); 158 layerEl.setAttribute("type", "tracks"); 159 layerEl.setAttribute("version", "0.1"); 160 161 Element file = support.createElement("file"); 162 layerEl.appendChild(file); 163 164 if (requiresZip()) { 165 String zipPath = "layers/" + String.format("%02d", support.getLayerIndex()) + "/data.gpx"; 166 file.appendChild(support.createTextNode(zipPath)); 167 addDataFile(support.getOutputStreamZip(zipPath)); 168 } else { 169 URI uri = layer.getAssociatedFile().toURI(); 170 URL url = null; 171 try { 172 url = uri.toURL(); 173 } catch (MalformedURLException e) { 174 throw new IOException(e); 175 } 176 file.appendChild(support.createTextNode(url.toString())); 177 } 178 return layerEl; 179 } 180 181 protected void addDataFile(OutputStream out) throws IOException { 182 Writer writer = null; 183 try { 184 writer = new OutputStreamWriter(out, "UTF-8"); 185 } catch (UnsupportedEncodingException e) { 186 throw new RuntimeException(e); 187 } 188 GpxWriter w = new GpxWriter(new PrintWriter(writer)); 189 w.write(layer.data); 190 w.flush(); 191 } 192 193}