// License: GPL. Copyright 2007 by Immanuel Scholz and others package org.openstreetmap.josm.gui.layer; import static org.openstreetmap.josm.tools.I18n.tr; import static org.openstreetmap.josm.tools.I18n.trn; import java.awt.CheckboxGroup; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; import java.util.Collection; import java.util.LinkedList; import javax.swing.AbstractAction; import javax.swing.Box; import javax.swing.ButtonGroup; import javax.swing.Icon; import javax.swing.JCheckBox; import javax.swing.JColorChooser; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSeparator; import javax.swing.JTextField; import javax.swing.filechooser.FileFilter; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.actions.GpxExportAction; import org.openstreetmap.josm.actions.RenameLayerAction; import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener; import org.openstreetmap.josm.data.coor.EastNorth; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; import org.openstreetmap.josm.gui.MapView; import org.openstreetmap.josm.gui.dialogs.LayerListDialog; import org.openstreetmap.josm.gui.dialogs.LayerListPopup; import org.openstreetmap.josm.io.MultiPartFormOutputStream; import org.openstreetmap.josm.io.OsmWriter; import org.openstreetmap.josm.tools.ColorHelper; import org.openstreetmap.josm.tools.DontShowAgainInfo; import org.openstreetmap.josm.tools.GBC; import org.openstreetmap.josm.tools.ImageProvider; import org.openstreetmap.josm.tools.UrlLabel; /** * A layer holding data from a gps source. * The data is read only. * * @author imi */ public class RawGpsLayer extends Layer implements PreferenceChangedListener { public class ConvertToDataLayerAction extends AbstractAction { public ConvertToDataLayerAction() { super(tr("Convert to data layer"), ImageProvider.get("converttoosm")); } public void actionPerformed(ActionEvent e) { JPanel msg = new JPanel(new GridBagLayout()); msg.add(new JLabel(tr("Upload of unprocessed GPS data as map data is considered harmful.
If you want to upload traces, look here:")), GBC.eol()); msg.add(new UrlLabel(tr("http://www.openstreetmap.org/traces")), GBC.eop()); if (!DontShowAgainInfo.show("convert_to_data", msg)) return; DataSet ds = new DataSet(); for (Collection c : data) { Way w = new Way(); for (GpsPoint p : c) { Node n = new Node(p.latlon); ds.nodes.add(n); w.nodes.add(n); } ds.ways.add(w); } Main.main.addLayer(new OsmDataLayer(ds, tr("Converted from: {0}", RawGpsLayer.this.name), null)); Main.main.removeLayer(RawGpsLayer.this); } } public class UploadTraceAction extends AbstractAction { public UploadTraceAction() { super(tr("Upload this trace..."), ImageProvider.get("uploadtrace")); } public void actionPerformed(ActionEvent e) { JPanel msg = new JPanel(new GridBagLayout()); msg.add(new JLabel(tr("This functionality has been added only recently. Please
"+ "use with care and check if it works as expected.")), GBC.eop()); ButtonGroup bg = new ButtonGroup(); JRadioButton c1 = null; JRadioButton c2 = null; if (associatedFile != null) { c1 = new JRadioButton(tr("Upload track filtered by JOSM"), false); c2 = new JRadioButton(tr("Upload raw file: {0}", associatedFile.getName()), true); } else { c1 = new JRadioButton(tr("Upload track filtered by JOSM"), true); c2 = new JRadioButton(tr("Upload raw file: "), false); c2.setEnabled(false); } c1.setEnabled(false); bg.add(c1); bg.add(c2); msg.add(c1, GBC.eol()); msg.add(c2, GBC.eop()); JTextField description = new JTextField(); JTextField tags = new JTextField(); msg.add(new JLabel(tr("Description:")), GBC.std()); msg.add(description, GBC.eol().fill(GBC.HORIZONTAL)); msg.add(new JLabel(tr("Tags:")), GBC.std()); msg.add(tags, GBC.eol().fill(GBC.HORIZONTAL)); JCheckBox c3 = new JCheckBox("public"); msg.add(c3, GBC.eop()); msg.add(new JLabel("Please ensure that you don't upload your traces twice."), GBC.eop()); int answer = JOptionPane.showConfirmDialog(Main.parent, msg, tr("GPX-Upload"), JOptionPane.OK_CANCEL_OPTION); if (answer == JOptionPane.OK_OPTION) { try { String version = Main.pref.get("osm-server.version", "0.5"); URL url = new URL(Main.pref.get("osm-server.url") + "/" + version + "/gpx/create"); // create a boundary string String boundary = MultiPartFormOutputStream.createBoundary(); URLConnection urlConn = MultiPartFormOutputStream.createConnection(url); urlConn.setRequestProperty("Accept", "*/*"); urlConn.setRequestProperty("Content-Type", MultiPartFormOutputStream.getContentType(boundary)); // set some other request headers... urlConn.setRequestProperty("Connection", "Keep-Alive"); urlConn.setRequestProperty("Cache-Control", "no-cache"); // no need to connect cuz getOutputStream() does it MultiPartFormOutputStream out = new MultiPartFormOutputStream(urlConn.getOutputStream(), boundary); out.writeField("description", description.getText()); out.writeField("tags", tags.getText()); out.writeField("public", (c3.getSelectedObjects() != null) ? "1" : "0"); // upload a file out.writeFile("gpx_file", "text/xml", associatedFile); // can also write bytes directly // out.writeFile("myFile", "text/plain", "C:\\test.txt", // "This is some file text.".getBytes("ASCII")); out.close(); // read response from server BufferedReader in = new BufferedReader( new InputStreamReader(urlConn.getInputStream())); String line = ""; while((line = in.readLine()) != null) { System.out.println(line); } in.close(); /* int retCode = activeConnection.getResponseCode(); System.out.println("got return: "+retCode); String retMsg = activeConnection.getResponseMessage(); activeConnection.disconnect(); if (retCode != 200) { // Look for a detailed error message from the server if (activeConnection.getHeaderField("Error") != null) retMsg += "\n" + activeConnection.getHeaderField("Error"); // Report our error ByteArrayOutputStream o = new ByteArrayOutputStream(); System.out.println(new String(o.toByteArray(), "UTF-8").toString()); throw new RuntimeException(retCode+" "+retMsg); } */ } catch (UnknownHostException ex) { throw new RuntimeException(tr("Unknown host")+": "+ex.getMessage(), ex); } catch (Exception ex) { //if (cancel) // return; // assume cancel if (ex instanceof RuntimeException) throw (RuntimeException)ex; throw new RuntimeException(ex.getMessage(), ex); } } } } public static class GpsPoint { public final LatLon latlon; public final EastNorth eastNorth; public final String time; public GpsPoint(LatLon ll, String t) { latlon = ll; eastNorth = Main.proj.latlon2eastNorth(ll); time = t; } } /** * A list of ways which containing a list of points. */ public final Collection> data; public final boolean fromServer; public RawGpsLayer(boolean fromServer, Collection> data, String name, File associatedFile) { super(name); this.fromServer = fromServer; this.associatedFile = associatedFile; this.data = data; Main.pref.listener.add(this); } /** * Return a static icon. */ @Override public Icon getIcon() { return ImageProvider.get("layer", "rawgps_small"); } @Override public void paint(Graphics g, MapView mv) { String gpsCol = Main.pref.get("color.gps point"); String gpsColSpecial = Main.pref.get("color.layer "+name); if (!gpsColSpecial.equals("")) g.setColor(ColorHelper.html2color(gpsColSpecial)); else if (!gpsCol.equals("")) g.setColor(ColorHelper.html2color(gpsCol)); else g.setColor(Color.GRAY); Point old = null; boolean force = Main.pref.getBoolean("draw.rawgps.lines.force"); boolean lines = Main.pref.getBoolean("draw.rawgps.lines"); String linesKey = "draw.rawgps.lines.layer "+name; if (Main.pref.hasKey(linesKey)) lines = Main.pref.getBoolean(linesKey); boolean large = Main.pref.getBoolean("draw.rawgps.large"); for (Collection c : data) { if (!force) old = null; for (GpsPoint p : c) { Point screen = mv.getPoint(p.eastNorth); if (lines && old != null) g.drawLine(old.x, old.y, screen.x, screen.y); else if (!large) g.drawRect(screen.x, screen.y, 0, 0); if (large) g.fillRect(screen.x-1, screen.y-1, 3, 3); old = screen; } } } @Override public String getToolTipText() { int points = 0; for (Collection c : data) points += c.size(); String tool = data.size()+" "+trn("track", "tracks", data.size()) +" "+points+" "+trn("point", "points", points); if (associatedFile != null) tool = ""+tool+"
"+associatedFile.getPath()+""; return tool; } @Override public void mergeFrom(Layer from) { RawGpsLayer layer = (RawGpsLayer)from; data.addAll(layer.data); } @Override public boolean isMergable(Layer other) { return other instanceof RawGpsLayer; } @Override public void visitBoundingBox(BoundingXYVisitor v) { for (Collection c : data) for (GpsPoint p : c) v.visit(p.eastNorth); } @Override public Object getInfoComponent() { StringBuilder b = new StringBuilder(); int points = 0; for (Collection c : data) { b.append("     "+trn("a track with {0} point","a track with {0} points", c.size(), c.size())+"
"); points += c.size(); } b.append(""); return ""+trn("{0} consists of {1} track", "{0} consists of {1} tracks", data.size(), name, data.size())+" ("+trn("{0} point", "{0} points", points, points)+")
"+b.toString(); } @Override public Component[] getMenuEntries() { JMenuItem line = new JMenuItem(tr("Customize line drawing"), ImageProvider.get("mapmode/addsegment")); line.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { JRadioButton[] r = new JRadioButton[3]; r[0] = new JRadioButton(tr("Use global settings.")); r[1] = new JRadioButton(tr("Draw lines between points for this layer.")); r[2] = new JRadioButton(tr("Do not draw lines between points for this layer.")); ButtonGroup group = new ButtonGroup(); Box panel = Box.createVerticalBox(); for (JRadioButton b : r) { group.add(b); panel.add(b); } String propName = "draw.rawgps.lines.layer "+name; if (Main.pref.hasKey(propName)) group.setSelected(r[Main.pref.getBoolean(propName) ? 1:2].getModel(), true); else group.setSelected(r[0].getModel(), true); int answer = JOptionPane.showConfirmDialog(Main.parent, panel, tr("Select line drawing options"), JOptionPane.OK_CANCEL_OPTION); if (answer == JOptionPane.CANCEL_OPTION) return; if (group.getSelection() == r[0].getModel()) Main.pref.put(propName, null); else Main.pref.put(propName, group.getSelection() == r[1].getModel()); Main.map.repaint(); } }); JMenuItem color = new JMenuItem(tr("Customize Color"), ImageProvider.get("colorchooser")); color.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { String col = Main.pref.get("color.layer "+name, Main.pref.get("color.gps point", ColorHelper.color2html(Color.gray))); JColorChooser c = new JColorChooser(ColorHelper.html2color(col)); Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")}; int answer = JOptionPane.showOptionDialog(Main.parent, c, tr("Choose a color"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]); switch (answer) { case 0: Main.pref.put("color.layer "+name, ColorHelper.color2html(c.getColor())); break; case 1: return; case 2: Main.pref.put("color.layer "+name, null); break; } Main.map.repaint(); } }); JMenuItem tagimage = new JMenuItem(tr("Import images"), ImageProvider.get("tagimages")); tagimage.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { JFileChooser fc = new JFileChooser(Main.pref.get("tagimages.lastdirectory")); fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); fc.setMultiSelectionEnabled(true); fc.setAcceptAllFileFilterUsed(false); fc.setFileFilter(new FileFilter(){ @Override public boolean accept(File f) { return f.isDirectory() || f.getName().toLowerCase().endsWith(".jpg"); } @Override public String getDescription() { return tr("JPEG images (*.jpg)"); } }); fc.showOpenDialog(Main.parent); File[] sel = fc.getSelectedFiles(); if (sel == null || sel.length == 0) return; LinkedList files = new LinkedList(); addRecursiveFiles(files, sel); Main.pref.put("tagimages.lastdirectory", fc.getCurrentDirectory().getPath()); GeoImageLayer.create(files, RawGpsLayer.this); } private void addRecursiveFiles(LinkedList files, File[] sel) { for (File f : sel) { if (f.isDirectory()) addRecursiveFiles(files, f.listFiles()); else if (f.getName().toLowerCase().endsWith(".jpg")) files.add(f); } } }); if (Main.applet) return new Component[]{ new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)), new JMenuItem(new LayerListDialog.DeleteLayerAction(this)), new JSeparator(), color, line, new JMenuItem(new ConvertToDataLayerAction()), //new JMenuItem(new UploadTraceAction()), new JSeparator(), new JMenuItem(new RenameLayerAction(associatedFile, this)), new JSeparator(), new JMenuItem(new LayerListPopup.InfoAction(this))}; return new Component[]{ new JMenuItem(new LayerListDialog.ShowHideLayerAction(this)), new JMenuItem(new LayerListDialog.DeleteLayerAction(this)), new JSeparator(), new JMenuItem(new GpxExportAction(this)), color, line, tagimage, new JMenuItem(new ConvertToDataLayerAction()), //new JMenuItem(new UploadTraceAction()), new JSeparator(), new JMenuItem(new RenameLayerAction(associatedFile, this)), new JSeparator(), new JMenuItem(new LayerListPopup.InfoAction(this))}; } public void preferenceChanged(String key, String newValue) { if (Main.map != null && (key.equals("draw.rawgps.lines") || key.equals("draw.rawgps.lines.force"))) Main.map.repaint(); } @Override public void destroy() { Main.pref.listener.remove(RawGpsLayer.this); } }