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.Font; 008import java.awt.GridBagLayout; 009import java.awt.Insets; 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.AbstractAction; 028import javax.swing.ButtonGroup; 029import javax.swing.JButton; 030import javax.swing.JCheckBox; 031import javax.swing.JLabel; 032import javax.swing.JPanel; 033import javax.swing.JRadioButton; 034import javax.swing.SwingConstants; 035 036import org.w3c.dom.Element; 037 038import org.openstreetmap.josm.actions.SaveAction; 039import org.openstreetmap.josm.gui.layer.Layer; 040import org.openstreetmap.josm.gui.layer.OsmDataLayer; 041import org.openstreetmap.josm.gui.util.GuiHelper; 042import org.openstreetmap.josm.gui.widgets.JosmTextField; 043import org.openstreetmap.josm.io.OsmWriter; 044import org.openstreetmap.josm.io.OsmWriterFactory; 045import org.openstreetmap.josm.io.session.SessionWriter.ExportSupport; 046import org.openstreetmap.josm.tools.GBC; 047import org.openstreetmap.josm.tools.ImageProvider; 048 049public class OsmDataSessionExporter implements SessionLayerExporter { 050 051 private OsmDataLayer layer; 052 private JRadioButton link, include; 053 private JCheckBox export; 054 055 public OsmDataSessionExporter(OsmDataLayer layer) { 056 this.layer = layer; 057 } 058 059 public OsmDataSessionExporter() { 060 } 061 062 @Override 063 public Collection<Layer> getDependencies() { 064 return Collections.emptySet(); 065 } 066 067 private class LayerSaveAction extends AbstractAction { 068 public LayerSaveAction() { 069 putValue(SMALL_ICON, new ImageProvider("save").setWidth(16).get()); 070 putValue(SHORT_DESCRIPTION, layer.requiresSaveToFile() ? 071 tr("Layer contains unsaved data - save to file.") : 072 tr("Layer does not contain unsaved data.")); 073 updateEnabledState(); 074 } 075 076 @Override 077 public void actionPerformed(ActionEvent e) { 078 SaveAction.getInstance().doSave(layer); 079 updateEnabledState(); 080 } 081 082 public void updateEnabledState() { 083 setEnabled(layer.requiresSaveToFile()); 084 } 085 } 086 087 @Override 088 public JPanel getExportPanel() { 089 final JPanel p = new JPanel(new GridBagLayout()); 090 JPanel topRow = new JPanel(new GridBagLayout()); 091 export = new JCheckBox(); 092 export.setSelected(true); 093 final JLabel lbl = new JLabel(layer.getName(), layer.getIcon(), SwingConstants.LEFT); 094 lbl.setToolTipText(layer.getToolTipText()); 095 096 JLabel lblData = new JLabel(tr("Data:")); 097 /* I18n: Refer to a OSM data file in session file */ link = new JRadioButton(tr("local file")); 098 link.putClientProperty("actionname", "link"); 099 link.setToolTipText(tr("Link to a OSM data file on your local disk.")); 100 /* I18n: Include OSM data in session file */ include = new JRadioButton(tr("include")); 101 include.setToolTipText(tr("Include OSM data in the .joz session file.")); 102 include.putClientProperty("actionname", "include"); 103 ButtonGroup group = new ButtonGroup(); 104 group.add(link); 105 group.add(include); 106 107 JPanel cardLink = new JPanel(new GridBagLayout()); 108 final File file = layer.getAssociatedFile(); 109 final LayerSaveAction saveAction = new LayerSaveAction(); 110 final JButton save = new JButton(saveAction); 111 if (file != null) { 112 JosmTextField tf = new JosmTextField(); 113 tf.setText(file.getPath()); 114 tf.setEditable(false); 115 cardLink.add(tf, GBC.std()); 116 save.setMargin(new Insets(0,0,0,0)); 117 cardLink.add(save, GBC.eol().insets(2,0,0,0)); 118 } else { 119 cardLink.add(new JLabel(tr("No file association")), GBC.eol()); 120 } 121 122 JPanel cardInclude = new JPanel(new GridBagLayout()); 123 JLabel lblIncl = new JLabel(tr("OSM data will be included in the session file.")); 124 lblIncl.setFont(lblIncl.getFont().deriveFont(Font.PLAIN)); 125 cardInclude.add(lblIncl, GBC.eol().fill(GBC.HORIZONTAL)); 126 127 final CardLayout cl = new CardLayout(); 128 final JPanel cards = new JPanel(cl); 129 cards.add(cardLink, "link"); 130 cards.add(cardInclude, "include"); 131 132 if (file != null) { 133 link.setSelected(true); 134 } else { 135 link.setEnabled(false); 136 link.setToolTipText(tr("No file association")); 137 include.setSelected(true); 138 cl.show(cards, "include"); 139 } 140 141 link.addActionListener(new ActionListener() { 142 @Override 143 public void actionPerformed(ActionEvent e) { 144 cl.show(cards, "link"); 145 } 146 }); 147 include.addActionListener(new ActionListener() { 148 @Override 149 public void actionPerformed(ActionEvent e) { 150 cl.show(cards, "include"); 151 } 152 }); 153 154 topRow.add(export, GBC.std()); 155 topRow.add(lbl, GBC.std()); 156 topRow.add(GBC.glue(1,0), GBC.std().fill(GBC.HORIZONTAL)); 157 p.add(topRow, GBC.eol().fill(GBC.HORIZONTAL)); 158 p.add(lblData, GBC.std().insets(10,0,0,0)); 159 p.add(link, GBC.std()); 160 p.add(include, GBC.eol()); 161 p.add(cards, GBC.eol().insets(15,0,3,3)); 162 163 export.addItemListener(new ItemListener() { 164 @Override 165 public void itemStateChanged(ItemEvent e) { 166 if (e.getStateChange() == ItemEvent.DESELECTED) { 167 GuiHelper.setEnabledRec(p, false); 168 export.setEnabled(true); 169 } else { 170 GuiHelper.setEnabledRec(p, true); 171 save.setEnabled(saveAction.isEnabled()); 172 link.setEnabled(file != null); 173 } 174 } 175 }); 176 return p; 177 } 178 179 @Override 180 public boolean shallExport() { 181 return export.isSelected(); 182 } 183 184 @Override 185 public boolean requiresZip() { 186 return include.isSelected(); 187 } 188 189 @Override 190 public Element export(ExportSupport support) throws IOException { 191 Element layerEl = support.createElement("layer"); 192 layerEl.setAttribute("type", "osm-data"); 193 layerEl.setAttribute("version", "0.1"); 194 195 Element file = support.createElement("file"); 196 layerEl.appendChild(file); 197 198 if (requiresZip()) { 199 String zipPath = "layers/" + String.format("%02d", support.getLayerIndex()) + "/data.osm"; 200 file.appendChild(support.createTextNode(zipPath)); 201 addDataFile(support.getOutputStreamZip(zipPath)); 202 } else { 203 URI uri = layer.getAssociatedFile().toURI(); 204 URL url = null; 205 try { 206 url = uri.toURL(); 207 } catch (MalformedURLException e) { 208 throw new IOException(e); 209 } 210 file.appendChild(support.createTextNode(url.toString())); 211 } 212 return layerEl; 213 } 214 215 protected void addDataFile(OutputStream out) throws IOException { 216 Writer writer = null; 217 try { 218 writer = new OutputStreamWriter(out, "UTF-8"); 219 } catch (UnsupportedEncodingException e) { 220 throw new RuntimeException(e); 221 } 222 OsmWriter w = OsmWriterFactory.createOsmWriter(new PrintWriter(writer), false, layer.data.getVersion()); 223 layer.data.getReadLock().lock(); 224 try { 225 w.writeLayer(layer); 226 w.flush(); 227 } finally { 228 layer.data.getReadLock().unlock(); 229 } 230 } 231} 232