Changeset 4282 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2011-08-07T09:08:29+02:00 (13 years ago)
Author:
jttt
Message:

Allow to specify custom pattern for marker text labels

Location:
trunk/src/org/openstreetmap/josm
Files:
12 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java

    r4129 r4282  
    55
    66import java.awt.Color;
     7import java.util.ArrayList;
    78import java.util.Date;
     9import java.util.List;
    810
    911import org.openstreetmap.josm.Main;
     12import org.openstreetmap.josm.actions.search.SearchCompiler.Match;
    1013import org.openstreetmap.josm.data.coor.EastNorth;
    1114import org.openstreetmap.josm.data.coor.LatLon;
    1215import org.openstreetmap.josm.data.projection.Projections;
    1316import org.openstreetmap.josm.tools.PrimaryDateParser;
     17import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider;
    1418
    15 public class WayPoint extends WithAttributes implements Comparable<WayPoint> {
     19public class WayPoint extends WithAttributes implements Comparable<WayPoint>, TemplateEngineDataProvider {
    1620
    1721    private static ThreadLocal<PrimaryDateParser> dateParser = new ThreadLocal<PrimaryDateParser>() {
     
    117121        return new Date((long) (time * 1000));
    118122    }
     123
     124    @Override
     125    public Object getTemplateValue(String name) {
     126        return attr.get(name);
     127    }
     128
     129    @Override
     130    public boolean evaluateCondition(Match condition) {
     131        throw new UnsupportedOperationException();
     132    }
     133
     134    @Override
     135    public List<String> getTemplateKeys() {
     136        return new ArrayList<String>(attr.keySet());
     137    }
    119138}
  • trunk/src/org/openstreetmap/josm/data/preferences/AbstractProperty.java

    r3730 r4282  
    77 * captures the common functionality of preference properties
    88 */
    9 public class AbstractProperty {
     9public abstract class AbstractProperty<T> {
    1010    protected final String key;
    1111
     
    2121        return Main.pref.hasKey(key);
    2222    }
     23
     24    public abstract T getDefaultValue();
     25
     26    public void remove() {
     27        Main.pref.put(getKey(), String.valueOf(getDefaultValue()));
     28    }
     29
    2330}
  • trunk/src/org/openstreetmap/josm/data/preferences/BooleanProperty.java

    r3730 r4282  
    44import org.openstreetmap.josm.Main;
    55
    6 public class BooleanProperty extends AbstractProperty {
     6public class BooleanProperty extends AbstractProperty<Boolean> {
    77
    88    protected final boolean defaultValue;
     
    1414
    1515    public boolean get() {
    16         return Main.pref.getBoolean(getKey(), isDefaultValue());
     16        return Main.pref.getBoolean(getKey(), defaultValue);
    1717    }
    1818
     
    2121    }
    2222
    23     public boolean isDefaultValue() {
     23    @Override
     24    public Boolean getDefaultValue() {
    2425        return defaultValue;
    2526    }
  • trunk/src/org/openstreetmap/josm/data/preferences/CollectionProperty.java

    r3730 r4282  
    66import org.openstreetmap.josm.Main;
    77
    8 public class CollectionProperty extends AbstractProperty {
     8public class CollectionProperty extends AbstractProperty<Collection<String>> {
    99    protected final Collection<String> defaultValue;
    1010
     
    2222    }
    2323
     24    @Override
    2425    public Collection<String> getDefaultValue() {
    2526        return defaultValue;
  • trunk/src/org/openstreetmap/josm/data/preferences/IntegerProperty.java

    r3730 r4282  
    44import org.openstreetmap.josm.Main;
    55
    6 public class IntegerProperty extends AbstractProperty {
     6public class IntegerProperty extends AbstractProperty<Integer> {
    77
    88    protected final int defaultValue;
     
    3737    }
    3838
    39     public int getDefaultValue() {
     39    @Override
     40    public Integer getDefaultValue() {
    4041        return defaultValue;
    4142    }
  • trunk/src/org/openstreetmap/josm/data/preferences/StringProperty.java

    r3730 r4282  
    44import org.openstreetmap.josm.Main;
    55
    6 public class StringProperty extends AbstractProperty {
     6public class StringProperty extends AbstractProperty<String> {
    77
    88    protected final String defaultValue;
     
    2121    }
    2222
     23    @Override
    2324    public String getDefaultValue() {
    2425        return defaultValue;
  • trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java

    r4276 r4282  
    2020import java.awt.geom.Rectangle2D;
    2121import java.io.File;
     22import java.net.MalformedURLException;
     23import java.net.URL;
    2224import java.text.DateFormat;
    2325import java.util.ArrayList;
     
    2628import java.util.Collections;
    2729import java.util.Comparator;
    28 import java.util.Date;
    29 import java.util.HashMap;
    3030import java.util.LinkedList;
    3131import java.util.List;
    32 import java.util.Map;
    3332import java.util.concurrent.Future;
    3433
    3534import javax.swing.AbstractAction;
    3635import javax.swing.Action;
    37 import javax.swing.Box;
    38 import javax.swing.ButtonGroup;
    39 import javax.swing.ButtonModel;
    4036import javax.swing.Icon;
    4137import javax.swing.JFileChooser;
     
    4541import javax.swing.JOptionPane;
    4642import javax.swing.JPanel;
    47 import javax.swing.JRadioButton;
    4843import javax.swing.JScrollPane;
    4944import javax.swing.SwingUtilities;
     
    358353
    359354    /**
    360      * transition function: 
     355     * transition function:
    361356     *  w(0)=1, w(1)=0, 0<=w(x)<=1
    362357     * @param x number: 0<=x<=1
     
    364359     */
    365360    private static float w(float x) {
    366         if (x < 0.5) {
     361        if (x < 0.5)
    367362            return 1 - 2*x*x;
    368         } else {
    369         return 2*(1-x)*(1-x);
    370         }
    371     }
    372    
     363        else
     364            return 2*(1-x)*(1-x);
     365    }
     366
    373367    // lookup array to draw arrows without doing any math
    374368    private final static int ll0 = 9;
     
    463457                    for (GpxTrack trk : data.tracks) {
    464458                        for (GpxTrackSegment segment : trk.getSegments()) {
    465                             if(!forceLines) oldWp = null;
     459                            if(!forceLines) {
     460                                oldWp = null;
     461                            }
    466462                            for (WayPoint trkPnt : segment.getWayPoints()) {
    467463                                LatLon c = trkPnt.getCoor();
     
    472468                                    double vel = c.greatCircleDistance(oldWp.getCoor())
    473469                                            / (trkPnt.time - oldWp.time);
    474                                     if(vel > maxval) maxval = vel;
    475                                     if(vel < minval) minval = vel;
     470                                    if(vel > maxval) {
     471                                        maxval = vel;
     472                                    }
     473                                    if(vel < minval) {
     474                                        minval = vel;
     475                                    }
    476476                                }
    477477                                oldWp = trkPnt;
     
    486486                                if (val != null) {
    487487                                    double hdop = ((Float) val).doubleValue();
    488                                     if(hdop > maxval) maxval = hdop;
    489                                     if(hdop < minval) minval = hdop;
     488                                    if(hdop > maxval) {
     489                                        maxval = hdop;
     490                                    }
     491                                    if(hdop < minval) {
     492                                        minval = hdop;
     493                                    }
    490494                                }
    491495                            }
     
    496500            }
    497501            if (colored == colorModes.time) {
    498                     for (GpxTrack trk : data.tracks) {
    499                         for (GpxTrackSegment segment : trk.getSegments()) {
    500                             for (WayPoint trkPnt : segment.getWayPoints()) {
    501                                double t=trkPnt.time;
    502                                if (t==0) continue; // skip non-dated trackpoints
    503                                if(t > maxval) maxval = t;
    504                                if(t < minval) minval = t;
     502                for (GpxTrack trk : data.tracks) {
     503                    for (GpxTrackSegment segment : trk.getSegments()) {
     504                        for (WayPoint trkPnt : segment.getWayPoints()) {
     505                            double t=trkPnt.time;
     506                            if (t==0) {
     507                                continue; // skip non-dated trackpoints
    505508                            }
    506                         }
    507                     }
    508                 }
    509            
     509                            if(t > maxval) {
     510                                maxval = t;
     511                            }
     512                            if(t < minval) {
     513                                minval = t;
     514                            }
     515                        }
     516                    }
     517                }
     518            }
     519
    510520            for (GpxTrack trk : data.tracks) {
    511521                for (GpxTrackSegment segment : trk.getSegments()) {
     
    522532                            float hdop = ((Float) trkPnt.attr.get("hdop")).floatValue();
    523533                            int hdoplvl =(int) Math.round(colorModeDynamic ? ((hdop-minval)*255/(maxval-minval))
    524                             : (hdop <= 0 ? 0 : hdop * hdopfactor));
     534                                    : (hdop <= 0 ? 0 : hdop * hdopfactor));
    525535                            // High hdop is bad, but high values in colors are green.
    526536                            // Therefore inverse the logic
     
    537547                                    float vel = (float) (dist / dtime);
    538548                                    int velColor =(int) Math.round(colorModeDynamic ? ((vel-minval)*255/(maxval-minval))
    539                                     : (vel <= 0 ? 0 : vel / colorTracksTune * 255));
     549                                            : (vel <= 0 ? 0 : vel / colorTracksTune * 255));
    540550                                    trkPnt.customColoring = colors[velColor > 255 ? 255 : velColor];
    541551                                } else {
     
    561571                                break;
    562572                            }
    563                            
     573
    564574                            if (!noDraw && (maxLineLength == -1 || dist <= maxLineLength)) {
    565575                                trkPnt.drawLine = true;
     
    585595                {
    586596                    Bounds b = new Bounds(pt.getCoor());
    587                     if(pt.drawLine) // last should never be null when this is true!
     597                    // last should never be null when this is true!
     598                    if(pt.drawLine) {
    588599                        b.extend(last.getCoor());
     600                    }
    589601                    if(b.intersects(box))
    590602                    {
    591603                        if(last != null && (visibleSegments.isEmpty()
    592                         || visibleSegments.getLast() != last)) {
     604                                || visibleSegments.getLast() != last)) {
    593605                            if(last.drawLine) {
    594606                                WayPoint l = new WayPoint(last);
     
    646658                    if (old != null
    647659                            && (oldA == null || screen.x < oldA.x - delta || screen.x > oldA.x + delta
    648                                     || screen.y < oldA.y - delta || screen.y > oldA.y + delta)) {
     660                            || screen.y < oldA.y - delta || screen.y > oldA.y + delta)) {
    649661                        g.setColor(trkPnt.customColoring);
    650662                        double t = Math.atan2(screen.y - old.y, screen.x - old.x) + Math.PI;
     
    676688                    if (old != null
    677689                            && (oldA == null || screen.x < oldA.x - delta || screen.x > oldA.x + delta
    678                                     || screen.y < oldA.y - delta || screen.y > oldA.y + delta)) {
     690                            || screen.y < oldA.y - delta || screen.y > oldA.y + delta)) {
    679691                        g.setColor(trkPnt.customColoring);
    680692                        g.drawLine(screen.x, screen.y, screen.x + dir[trkPnt.dir][0], screen.y
     
    859871                    JOptionPane.OK_CANCEL_OPTION,
    860872                    JOptionPane.QUESTION_MESSAGE
    861             );
     873                    );
    862874            switch(ret) {
    863875            case JOptionPane.CANCEL_OPTION:
     
    982994                        JOptionPane.OK_CANCEL_OPTION,
    983995                        JOptionPane.PLAIN_MESSAGE
    984                 );
     996                        );
    985997                switch(ret) {
    986998                case JOptionPane.CANCEL_OPTION:
     
    10061018                        }
    10071019                    }
    1008             );
     1020                    );
    10091021        }
    10101022    }
     
    10491061     */
    10501062    private void importAudio(File wavFile, MarkerLayer ml, double firstStartTime, Markers markers) {
    1051         String uri = "file:".concat(wavFile.getAbsolutePath());
     1063        URL url = null;
     1064        try {
     1065            url = wavFile.toURI().toURL();
     1066        } catch (MalformedURLException e) {
     1067            System.err.println("Unable to convert filename " + wavFile.getAbsolutePath() + " to URL");
     1068        }
    10521069        Collection<WayPoint> waypoints = new ArrayList<WayPoint>();
    10531070        boolean timedMarkersOmitted = false;
     
    10841101                    tr("Error"),
    10851102                    JOptionPane.ERROR_MESSAGE
    1086             );
     1103                    );
    10871104            return;
    10881105        }
     
    11431160            double startTime = lastModified - duration;
    11441161            startTime = firstStartTime + (startTime - firstStartTime)
    1145             / Main.pref.getDouble("audio.calibration", "1.0" /* default, ratio */);
     1162                    / Main.pref.getDouble("audio.calibration", "1.0" /* default, ratio */);
    11461163            WayPoint w1 = null;
    11471164            WayPoint w2 = null;
     
    12191236            }
    12201237            double offset = w.time - firstTime;
    1221             String name;
    1222             if (w.attr.containsKey("name")) {
    1223                 name = w.getString("name");
    1224             } else if (w.attr.containsKey("desc")) {
    1225                 name = w.getString("desc");
    1226             } else {
    1227                 name = AudioMarker.inventName(offset);
    1228             }
    1229             AudioMarker am = AudioMarker.create(w.getCoor(), name, uri, ml, w.time, offset);
     1238            AudioMarker am = new AudioMarker(w.getCoor(), w, url, ml, w.time, offset);
    12301239            /*
    12311240             * timeFromAudio intended for future use to shift markers of this type on
     
    13791388            this();
    13801389            layers = new LinkedList<Layer>();
    1381             layers.add(l); 
     1390            layers.add(l);
    13821391        }
    13831392
     
    14101419            for (Layer layer : layers) {
    14111420                if (layer instanceof GpxLayer) {
    1412                     if (((GpxLayer) layer).isLocalFile) hasLocal = true;
    1413                     else hasNonlocal = true;
    1414                 }
    1415             }
    1416             GPXSettingsPanel panel=new GPXSettingsPanel(getName(), hasLocal, hasNonlocal);
     1421                    if (((GpxLayer) layer).isLocalFile) {
     1422                        hasLocal = true;
     1423                    } else {
     1424                        hasNonlocal = true;
     1425                    }
     1426                }
     1427            }
     1428            GPXSettingsPanel panel=new GPXSettingsPanel(getName(), hasLocal, hasNonlocal);
    14171429
    14181430            int answer = JOptionPane.showConfirmDialog(Main.parent, panel,
     
    14211433            for(Layer layer : layers) {
    14221434                // save preferences for all layers
    1423                 boolean f=false;
    1424                 if (layer instanceof GpxLayer) f=((GpxLayer)layer).isLocalFile;
    1425                     panel.savePreferences(layer.getName(),f);
     1435                boolean f=false;
     1436                if (layer instanceof GpxLayer) {
     1437                    f=((GpxLayer)layer).isLocalFile;
     1438                }
     1439                panel.savePreferences(layer.getName(),f);
    14261440            }
    14271441            Main.map.repaint();
     
    14681482                    + "Because its way points do not include a timestamp we cannot correlate them with audio data.</html>",
    14691483                    layer.getName()
    1470             );
     1484                    );
    14711485            HelpAwareOptionPane.showOptionDialog(
    14721486                    Main.parent,
     
    14751489                    JOptionPane.WARNING_MESSAGE,
    14761490                    ht("/Action/ImportAudio#CantImportIntoGpxLayerFromServer")
    1477             );
     1491                    );
    14781492        }
    14791493
     
    15341548                        getAssociatedFile(), GpxLayer.this);
    15351549                double firstStartTime = sel[0].lastModified() / 1000.0 /* ms -> seconds */
    1536                 - AudioUtil.getCalibratedDuration(sel[0]);
     1550                        - AudioUtil.getCalibratedDuration(sel[0]);
    15371551
    15381552                Markers m = new Markers();
     
    15581572                    + "Because its way points do not include a timestamp we cannot correlate them with images.</html>",
    15591573                    layer.getName()
    1560             );
     1574                    );
    15611575            HelpAwareOptionPane.showOptionDialog(
    15621576                    Main.parent,
     
    15651579                    JOptionPane.WARNING_MESSAGE,
    15661580                    ht("/Action/ImportImages#CantImportIntoGpxLayerFromServer")
    1567             );
     1581                    );
    15681582        }
    15691583
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java

    r1685 r4282  
    88import org.openstreetmap.josm.data.coor.LatLon;
    99import org.openstreetmap.josm.tools.AudioPlayer;
     10import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider;
    1011
    1112/**
     
    2223    public boolean timeFromAudio = false; // as opposed to from the GPX track
    2324
    24     /**
    25      * Verifies the parameter whether a new AudioMarker can be created and return
    26      * one or return <code>null</code>.
    27      */
    28     public static AudioMarker create(LatLon ll, String text, String url, MarkerLayer parentLayer, double time, double offset) {
    29         try {
    30             return new AudioMarker(ll, text, new URL(url), parentLayer, time, offset);
    31         } catch (Exception ex) {
    32             return null;
    33         }
    34     }
    35 
    36     private AudioMarker(LatLon ll, String text, URL audioUrl, MarkerLayer parentLayer, double time, double offset) {
    37         super(ll, text, "speech.png", parentLayer, time, offset);
     25    public AudioMarker(LatLon ll, TemplateEngineDataProvider dataProvider, URL audioUrl, MarkerLayer parentLayer, double time, double offset) {
     26        super(ll, dataProvider, "speech.png", parentLayer, time, offset);
    3827        this.audioUrl = audioUrl;
    3928        this.syncOffset = 0.0;
     
    8473    }
    8574
    86     public static String inventName (double offset) {
    87         int wholeSeconds = (int)(offset + 0.5);
    88         if (wholeSeconds < 60)
    89             return Integer.toString(wholeSeconds);
    90         else if (wholeSeconds < 3600)
    91             return String.format("%d:%02d", wholeSeconds / 60, wholeSeconds % 60);
    92         else
    93             return String.format("%d:%02d:%02d", wholeSeconds / 3600, (wholeSeconds % 3600)/60, wholeSeconds % 60);
     75    @Override
     76    protected TemplateEntryProperty getTextTemplate() {
     77        return TemplateEntryProperty.forAudioMarker(parentLayer.getName());
    9478    }
    9579}
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ButtonMarker.java

    r3396 r4282  
    1414import org.openstreetmap.josm.data.coor.LatLon;
    1515import org.openstreetmap.josm.gui.MapView;
     16import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider;
    1617
    1718/**
     
    2627
    2728    public ButtonMarker(LatLon ll, String buttonImage, MarkerLayer parentLayer, double time, double offset) {
    28         super(ll, "", buttonImage, parentLayer, time, offset);
     29        super(ll, null, buttonImage, parentLayer, time, offset);
    2930        buttonRectangle = new Rectangle(0, 0, symbol.getIconWidth(), symbol.getIconHeight());
    3031    }
    3132
    32     public ButtonMarker(LatLon ll, String text, String buttonImage, MarkerLayer parentLayer, double time, double offset) {
    33         super(ll, text, buttonImage, parentLayer, time, offset);
     33    public ButtonMarker(LatLon ll, TemplateEngineDataProvider dataProvider, String buttonImage, MarkerLayer parentLayer, double time, double offset) {
     34        super(ll, dataProvider, buttonImage, parentLayer, time, offset);
    3435        buttonRectangle = new Rectangle(0, 0, symbol.getIconWidth(), symbol.getIconHeight());
    3536    }
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarker.java

    r1847 r4282  
    3434    public URL imageUrl;
    3535
    36     public static ImageMarker create(LatLon ll, String url, MarkerLayer parentLayer, double time, double offset) {
    37         try {
    38             return new ImageMarker(ll, new URL(url), parentLayer, time, offset);
    39         } catch (Exception ex) {
    40             return null;
    41         }
    42     }
    43 
    44     private ImageMarker(LatLon ll, URL imageUrl, MarkerLayer parentLayer, double time, double offset) {
     36    public ImageMarker(LatLon ll, URL imageUrl, MarkerLayer parentLayer, double time, double offset) {
    4537        super(ll, "photo.png", parentLayer, time, offset);
    4638        this.imageUrl = imageUrl;
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java

    r4172 r4282  
    55import java.awt.Point;
    66import java.awt.event.ActionEvent;
    7 import java.awt.event.ActionListener;
    87import java.io.File;
    98import java.net.MalformedURLException;
    109import java.net.URL;
     10import java.util.ArrayList;
    1111import java.util.Collection;
    1212import java.util.HashMap;
    1313import java.util.LinkedList;
     14import java.util.List;
    1415import java.util.Map;
    1516
    1617import javax.swing.Icon;
    1718
     19import org.openstreetmap.josm.actions.search.SearchCompiler.Match;
     20import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
    1821import org.openstreetmap.josm.data.coor.CachedLatLon;
    1922import org.openstreetmap.josm.data.coor.EastNorth;
     
    2225import org.openstreetmap.josm.data.gpx.GpxLink;
    2326import org.openstreetmap.josm.data.gpx.WayPoint;
     27import org.openstreetmap.josm.data.preferences.CachedProperty;
    2428import org.openstreetmap.josm.data.preferences.IntegerProperty;
    2529import org.openstreetmap.josm.gui.MapView;
    2630import org.openstreetmap.josm.tools.ImageProvider;
     31import org.openstreetmap.josm.tools.template_engine.ParseError;
     32import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider;
     33import org.openstreetmap.josm.tools.template_engine.TemplateEntry;
     34import org.openstreetmap.josm.tools.template_engine.TemplateParser;
    2735
    2836/**
     
    6169 * @author Frederik Ramm <frederik@remote.org>
    6270 */
    63 public class Marker implements ActionListener {
    64     public final String text;
    65     public final Map<String,String> textMap = new HashMap<String,String>();
    66     public final Icon symbol;
    67     public final MarkerLayer parentLayer;
    68     public double time; /* absolute time of marker since epoch */
    69     public double offset; /* time offset in seconds from the gpx point from which it was derived,
    70                              may be adjusted later to sync with other data, so not final */
    71 
    72     private CachedLatLon coor;
    73 
    74     public final void setCoor(LatLon coor) {
    75         if(this.coor == null) {
    76             this.coor = new CachedLatLon(coor);
    77         } else {
    78             this.coor.setCoor(coor);
    79         }
    80     }
    81 
    82     public final LatLon getCoor() {
    83         return coor;
    84     }
    85 
    86     public final void setEastNorth(EastNorth eastNorth) {
    87         coor.setEastNorth(eastNorth);
    88     }
    89 
    90     public final EastNorth getEastNorth() {
    91         return coor.getEastNorth();
    92     }
     71public class Marker implements TemplateEngineDataProvider {
     72
     73    public static class TemplateEntryProperty extends CachedProperty<TemplateEntry> {
     74        // This class is a bit complicated because it supports both global and per layer settings. I've added per layer settings because
     75        // GPXSettingsPanel had possibility to set waypoint label but then I've realized that markers use different layer then gpx data
     76        // so per layer settings is useless. Anyway it's possible to specify marker layer pattern in Einstein preferences and maybe somebody
     77        // will make gui for it so I'm keeping it here
     78
     79        private final static Map<String, TemplateEntryProperty> cache = new HashMap<String, Marker.TemplateEntryProperty>();
     80
     81        // Legacy code - convert label from int to template engine expression
     82        private static final IntegerProperty PROP_LABEL = new IntegerProperty("draw.rawgps.layer.wpt", 0 );
     83        private static String getDefaultLabelPattern() {
     84            switch (PROP_LABEL.get()) {
     85            case 1:
     86                return LABEL_PATTERN_NAME;
     87            case 2:
     88                return LABEL_PATTERN_DESC;
     89            case 0:
     90            case 3:
     91                return LABEL_PATTERN_AUTO;
     92            default:
     93                return "";
     94            }
     95        }
     96
     97        public static TemplateEntryProperty forMarker(String layerName) {
     98            String key = "draw.rawgps.layer.wpt.pattern";
     99            if (layerName != null) {
     100                key += "." + layerName;
     101            }
     102            TemplateEntryProperty result = cache.get(key);
     103            if (result == null) {
     104                String defaultValue = layerName == null?getDefaultLabelPattern():"";
     105                TemplateEntryProperty parent = layerName == null?null:forMarker(null);
     106                result = new TemplateEntryProperty(key, defaultValue, parent);
     107                cache.put(key, result);
     108            }
     109            return result;
     110        }
     111
     112        public static TemplateEntryProperty forAudioMarker(String layerName) {
     113            String key = "draw.rawgps.layer.audiowpt.pattern";
     114            if (layerName != null) {
     115                key += "." + layerName;
     116            }
     117            TemplateEntryProperty result = cache.get(key);
     118            if (result == null) {
     119                String defaultValue = layerName == null?"?{ '{name}' | '{desc}' | '{" + Marker.MARKER_FORMATTED_OFFSET + "}' }":"";
     120                TemplateEntryProperty parent = layerName == null?null:forAudioMarker(null);
     121                result = new TemplateEntryProperty(key, defaultValue, parent);
     122                cache.put(key, result);
     123            }
     124            return result;
     125        }
     126
     127        private TemplateEntryProperty parent;
     128
     129
     130        private TemplateEntryProperty(String key, String defaultValue, TemplateEntryProperty parent) {
     131            super(key, defaultValue);
     132            this.parent = parent;
     133            updateValue(); // Needs to be called because parent wasn't know in super constructor
     134        }
     135
     136        @Override
     137        protected TemplateEntry fromString(String s) {
     138            try {
     139                return new TemplateParser(s).parse();
     140            } catch (ParseError e) {
     141                System.out.println(String.format("Unable to parse template engine pattern '%s' for property %s. Using default ('%s') instead",
     142                        s, getKey(), defaultValue));
     143                return getDefaultValue();
     144            }
     145        }
     146
     147        @Override
     148        public String getDefaultValueAsString() {
     149            if (parent == null)
     150                return super.getDefaultValueAsString();
     151            else
     152                return parent.getAsString();
     153        }
     154
     155        @Override
     156        public void preferenceChanged(PreferenceChangeEvent e) {
     157            if (e.getKey().equals(key) || (parent != null && e.getKey().equals(parent.getKey()))) {
     158                updateValue();
     159            }
     160        }
     161    }
     162
    93163
    94164    /**
     
    97167     * stuff).
    98168     */
    99     public static LinkedList<MarkerProducers> markerProducers = new LinkedList<MarkerProducers>();
    100 
    101     private static final IntegerProperty PROP_LABEL = new IntegerProperty("draw.rawgps.layer.wpt", 0 );
    102     private static final String[] labelAttributes = new String[] {"name", "desc"};
     169    public static List<MarkerProducers> markerProducers = new LinkedList<MarkerProducers>();
    103170
    104171    // Add one Maker specifying the default behaviour.
     
    110177                // cheapest way to check whether "link" object exists and is a non-empty
    111178                // collection of GpxLink objects...
    112                 try {
    113                     for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get(GpxData.META_LINKS)) {
     179                Collection<GpxLink> links = (Collection<GpxLink>)wpt.attr.get(GpxData.META_LINKS);
     180                if (links != null) {
     181                    for (GpxLink oneLink : links ) {
    114182                        uri = oneLink.uri;
    115183                        break;
    116184                    }
    117                 } catch (Exception ex) {}
    118 
    119                 // Try a relative file:// url, if the link is not in an URL-compatible form
    120                 if (relativePath != null && uri != null && !isWellFormedAddress(uri)) {
    121                     uri = new File(relativePath.getParentFile(), uri).toURI().toString();
    122185                }
    123186
    124                 Map<String,String> nameDesc = new HashMap<String,String>();
    125                 for(String attribute : labelAttributes) {
    126                     if (wpt.attr.containsKey(attribute)) {
    127                         nameDesc.put(attribute, wpt.getString(attribute));
     187                URL url = null;
     188                if (uri != null) {
     189                    try {
     190                        url = new URL(uri);
     191                    } catch (MalformedURLException e) {
     192                        // Try a relative file:// url, if the link is not in an URL-compatible form
     193                        if (relativePath != null) {
     194                            try {
     195                                url = new File(relativePath.getParentFile(), uri).toURI().toURL();
     196                            } catch (MalformedURLException e1) {
     197                                System.err.println("Unable to convert uri " + uri + " to URL: "  + e1.getMessage());
     198                            }
     199                        }
    128200                    }
    129201                }
    130202
    131                 if (uri == null) {
     203
     204                if (url == null) {
    132205                    String symbolName = wpt.getString("symbol");
    133206                    if (symbolName == null) {
    134207                        symbolName = wpt.getString("sym");
    135208                    }
    136                     return new Marker(wpt.getCoor(), nameDesc, symbolName, parentLayer, time, offset);
     209                    return new Marker(wpt.getCoor(), wpt, symbolName, parentLayer, time, offset);
    137210                }
    138                 else if (uri.endsWith(".wav"))
    139                     return AudioMarker.create(wpt.getCoor(), getText(nameDesc), uri, parentLayer, time, offset);
    140                 else if (uri.endsWith(".png") || uri.endsWith(".jpg") || uri.endsWith(".jpeg") || uri.endsWith(".gif"))
    141                     return ImageMarker.create(wpt.getCoor(), uri, parentLayer, time, offset);
     211                else if (url.toString().endsWith(".wav"))
     212                    return new AudioMarker(wpt.getCoor(), wpt, url, parentLayer, time, offset);
     213                else if (url.toString().endsWith(".png") || url.toString().endsWith(".jpg") || url.toString().endsWith(".jpeg") || url.toString().endsWith(".gif"))
     214                    return new ImageMarker(wpt.getCoor(), url, parentLayer, time, offset);
    142215                else
    143                     return WebMarker.create(wpt.getCoor(), uri, parentLayer, time, offset);
    144             }
    145 
    146             private boolean isWellFormedAddress(String link) {
    147                 try {
    148                     new URL(link);
    149                     return true;
    150                 } catch (MalformedURLException x) {
    151                     return false;
    152                 }
     216                    return new WebMarker(wpt.getCoor(), url, parentLayer, time, offset);
    153217            }
    154218        });
    155     }
    156 
    157     public Marker(LatLon ll, String text, String iconName, MarkerLayer parentLayer, double time, double offset) {
    158         setCoor(ll);
    159         if (text == null || text.length() == 0) {
    160             this.text = null;
    161         }
    162         else {
    163             this.text = text;
    164         }
    165         this.offset = offset;
    166         this.time = time;
    167         this.symbol = ImageProvider.getIfAvailable("markers",iconName);
    168         this.parentLayer = parentLayer;
    169     }
    170 
    171     public Marker(LatLon ll, Map<String,String> textMap, String iconName, MarkerLayer parentLayer, double time, double offset) {
    172         setCoor(ll);
    173         if (textMap != null) {
    174             this.textMap.clear();
    175             this.textMap.putAll(textMap);
    176         }
    177 
    178         this.text = null;
    179         this.offset = offset;
    180         this.time = time;
    181         // /* ICON(markers/) */"Bridge"
    182         // /* ICON(markers/) */"Crossing"
    183         this.symbol = ImageProvider.getIfAvailable("markers",iconName);
    184         this.parentLayer = parentLayer;
    185     }
    186 
    187     /**
    188      * Checks whether the marker display area contains the given point.
    189      * Markers not interested in mouse clicks may always return false.
    190      *
    191      * @param p The point to check
    192      * @return <code>true</code> if the marker "hotspot" contains the point.
    193      */
    194     public boolean containsPoint(Point p) {
    195         return false;
    196     }
    197 
    198     /**
    199      * Called when the mouse is clicked in the marker's hotspot. Never
    200      * called for markers which always return false from containsPoint.
    201      *
    202      * @param ev A dummy ActionEvent
    203      */
    204     public void actionPerformed(ActionEvent ev) {
    205     }
    206 
    207     /**
    208      * Paints the marker.
    209      * @param g graphics context
    210      * @param mv map view
    211      * @param mousePressed true if the left mouse button is pressed
    212      */
    213     public void paint(Graphics g, MapView mv, boolean mousePressed, boolean showTextOrIcon) {
    214         Point screen = mv.getPoint(getEastNorth());
    215         if (symbol != null && showTextOrIcon) {
    216             symbol.paintIcon(mv, g, screen.x-symbol.getIconWidth()/2, screen.y-symbol.getIconHeight()/2);
    217         } else {
    218             g.drawLine(screen.x-2, screen.y-2, screen.x+2, screen.y+2);
    219             g.drawLine(screen.x+2, screen.y-2, screen.x-2, screen.y+2);
    220         }
    221 
    222         String labelText = getText();
    223         if ((labelText != null) && showTextOrIcon) {
    224             g.drawString(labelText, screen.x+4, screen.y+2);
    225         }
    226219    }
    227220
     
    246239    }
    247240
    248     /**
    249      * Returns an AudioMarker derived from this Marker and the provided uri
    250      * Subclasses of specific marker types override this to return null as they can't
    251      * be turned into AudioMarkers. This includes AudioMarkers themselves, as they
    252      * already have audio.
     241    public static final String MARKER_OFFSET = "waypointOffset";
     242    public static final String MARKER_FORMATTED_OFFSET = "formattedWaypointOffset";
     243
     244    public static final String LABEL_PATTERN_AUTO = "?{ '{name} - {desc}' | '{name}' | '{desc}' }";
     245    public static final String LABEL_PATTERN_NAME = "{name}";
     246    public static final String LABEL_PATTERN_DESC = "{desc}";
     247
     248
     249    private final TemplateEngineDataProvider dataProvider;
     250    public final Icon symbol;
     251    public final MarkerLayer parentLayer;
     252    public double time; /* absolute time of marker since epoch */
     253    public double offset; /* time offset in seconds from the gpx point from which it was derived,
     254                             may be adjusted later to sync with other data, so not final */
     255
     256    private String cachedText;
     257    private int textVersion = -1;
     258    private CachedLatLon coor;
     259
     260    public Marker(LatLon ll, TemplateEngineDataProvider dataProvider, String iconName, MarkerLayer parentLayer, double time, double offset) {
     261        setCoor(ll);
     262
     263        this.offset = offset;
     264        this.time = time;
     265        // /* ICON(markers/) */"Bridge"
     266        // /* ICON(markers/) */"Crossing"
     267        this.symbol = ImageProvider.getIfAvailable("markers",iconName);
     268        this.parentLayer = parentLayer;
     269
     270        this.dataProvider = dataProvider;
     271    }
     272
     273    public final void setCoor(LatLon coor) {
     274        if(this.coor == null) {
     275            this.coor = new CachedLatLon(coor);
     276        } else {
     277            this.coor.setCoor(coor);
     278        }
     279    }
     280
     281    public final LatLon getCoor() {
     282        return coor;
     283    }
     284
     285    public final void setEastNorth(EastNorth eastNorth) {
     286        coor.setEastNorth(eastNorth);
     287    }
     288
     289    public final EastNorth getEastNorth() {
     290        return coor.getEastNorth();
     291    }
     292
     293
     294    /**
     295     * Checks whether the marker display area contains the given point.
     296     * Markers not interested in mouse clicks may always return false.
    253297     *
    254      * @param uri uri of wave file
    255      * @return AudioMarker
    256      */
    257 
    258     public AudioMarker audioMarkerFromMarker(String uri) {
    259         AudioMarker audioMarker = AudioMarker.create(getCoor(), this.getText(), uri, this.parentLayer, this.time, this.offset);
    260         return audioMarker;
     298     * @param p The point to check
     299     * @return <code>true</code> if the marker "hotspot" contains the point.
     300     */
     301    public boolean containsPoint(Point p) {
     302        return false;
     303    }
     304
     305    /**
     306     * Called when the mouse is clicked in the marker's hotspot. Never
     307     * called for markers which always return false from containsPoint.
     308     *
     309     * @param ev A dummy ActionEvent
     310     */
     311    public void actionPerformed(ActionEvent ev) {
     312    }
     313
     314
     315    /**
     316     * Paints the marker.
     317     * @param g graphics context
     318     * @param mv map view
     319     * @param mousePressed true if the left mouse button is pressed
     320     */
     321    public void paint(Graphics g, MapView mv, boolean mousePressed, boolean showTextOrIcon) {
     322        Point screen = mv.getPoint(getEastNorth());
     323        if (symbol != null && showTextOrIcon) {
     324            symbol.paintIcon(mv, g, screen.x-symbol.getIconWidth()/2, screen.y-symbol.getIconHeight()/2);
     325        } else {
     326            g.drawLine(screen.x-2, screen.y-2, screen.x+2, screen.y+2);
     327            g.drawLine(screen.x+2, screen.y-2, screen.x-2, screen.y+2);
     328        }
     329
     330        String labelText = getText();
     331        if ((labelText != null) && showTextOrIcon) {
     332            g.drawString(labelText, screen.x+4, screen.y+2);
     333        }
     334    }
     335
     336
     337    protected TemplateEntryProperty getTextTemplate() {
     338        return TemplateEntryProperty.forMarker(parentLayer.getName());
    261339    }
    262340
     
    266344     */
    267345    public String getText() {
    268         if (this.text != null )
    269             return this.text;
     346        TemplateEntryProperty property = getTextTemplate();
     347        if (property.getUpdateCount() != textVersion) {
     348            TemplateEntry templateEntry = property.get();
     349            StringBuilder sb = new StringBuilder();
     350            templateEntry.appendText(sb, this);
     351
     352            cachedText = sb.toString();
     353            textVersion = property.getUpdateCount();
     354        }
     355        return cachedText;
     356    }
     357
     358    @Override
     359    public List<String> getTemplateKeys() {
     360        List<String> result;
     361        if (dataProvider != null) {
     362            result = dataProvider.getTemplateKeys();
     363        } else {
     364            result = new ArrayList<String>();
     365        }
     366        result.add(MARKER_FORMATTED_OFFSET);
     367        result.add(MARKER_OFFSET);
     368        return result;
     369    }
     370
     371    private String formatOffset () {
     372        int wholeSeconds = (int)(offset + 0.5);
     373        if (wholeSeconds < 60)
     374            return Integer.toString(wholeSeconds);
     375        else if (wholeSeconds < 3600)
     376            return String.format("%d:%02d", wholeSeconds / 60, wholeSeconds % 60);
    270377        else
    271             return getText(this.textMap);
    272     }
    273 
    274     /**
    275      * Returns the Text which should be displayed, depending on chosen preference.
    276      * The possible attributes are read from textMap.
    277      *
    278      * @param textMap A map with available texts/attributes
    279      * @return Text
    280      */
    281     private static String getText(Map<String,String> textMap) {
    282         String text = "";
    283 
    284         if (textMap != null && !textMap.isEmpty()) {
    285             switch(PROP_LABEL.get())
    286             {
    287                 // name
    288                 case 1:
    289                 {
    290                     if (textMap.containsKey("name")) {
    291                         text = textMap.get("name");
    292                     }
    293                     break;
    294                 }
    295 
    296                 // desc
    297                 case 2:
    298                 {
    299                     if (textMap.containsKey("desc")) {
    300                         text = textMap.get("desc");
    301                     }
    302                     break;
    303                 }
    304 
    305                 // auto
    306                 case 0:
    307                 // both
    308                 case 3:
    309                 {
    310                     if (textMap.containsKey("name")) {
    311                         text = textMap.get("name");
    312 
    313                         if (textMap.containsKey("desc")) {
    314                             if (PROP_LABEL.get() != 0 || !text.equals(textMap.get("desc"))) {
    315                                 text += " - " + textMap.get("desc");
    316                             }
    317                         }
    318                     }
    319                     else if (textMap.containsKey("desc")) {
    320                         text = textMap.get("desc");
    321                     }
    322                     break;
    323                 }
    324 
    325                 // none
    326                 case 4:
    327                 default:
    328                 {
    329                     text = "";
    330                     break;
    331                 }
    332             }
    333         }
    334 
    335         return text;
     378            return String.format("%d:%02d:%02d", wholeSeconds / 3600, (wholeSeconds % 3600)/60, wholeSeconds % 60);
     379    }
     380
     381    @Override
     382    public Object getTemplateValue(String name) {
     383        if (MARKER_FORMATTED_OFFSET.equals(name))
     384            return formatOffset();
     385        else if (MARKER_OFFSET.equals(name))
     386            return offset;
     387        else if (dataProvider != null)
     388            return dataProvider.getTemplateValue(name);
     389        else
     390            return null;
     391    }
     392
     393    @Override
     394    public boolean evaluateCondition(Match condition) {
     395        throw new UnsupportedOperationException();
    336396    }
    337397}
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java

    r4230 r4282  
    3232import org.openstreetmap.josm.data.coor.LatLon;
    3333import org.openstreetmap.josm.data.gpx.GpxData;
    34 import org.openstreetmap.josm.data.gpx.GpxLink;
    3534import org.openstreetmap.josm.data.gpx.WayPoint;
    3635import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     
    7271        this.fromLayer = fromLayer;
    7372        double firstTime = -1.0;
    74         String lastLinkedFile = "";
    7573
    7674        for (WayPoint wpt : indata.waypoints) {
    77             /* calculate time differences in waypoints */
    7875            double time = wpt.time;
    79             boolean wpt_has_link = wpt.attr.containsKey(GpxData.META_LINKS);
    80             if (firstTime < 0 && wpt_has_link) {
     76            if (firstTime < 0) {
    8177                firstTime = time;
    82                 for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get(GpxData.META_LINKS)) {
    83                     lastLinkedFile = oneLink.uri;
    84                     break;
    85                 }
    86             }
    87             if (wpt_has_link) {
    88                 for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get(GpxData.META_LINKS)) {
    89                     if (!oneLink.uri.equals(lastLinkedFile)) {
    90                         firstTime = time;
    91                     }
    92                     lastLinkedFile = oneLink.uri;
    93                     break;
    94                 }
    9578            }
    9679            Marker m = Marker.createMarker(wpt, indata.storageFile, this, time, time - firstTime);
     
    274257                    tr("Error"),
    275258                    JOptionPane.ERROR_MESSAGE
    276             );
     259                    );
    277260            return null;
    278261        }
    279262
    280263        // make our new marker
    281         AudioMarker newAudioMarker = AudioMarker.create(coor,
    282                 AudioMarker.inventName(offset), AudioPlayer.url().toString(), this, time, offset);
     264        AudioMarker newAudioMarker = new AudioMarker(coor,
     265                null, AudioPlayer.url(), this, time, offset);
    283266
    284267        // insert it at the right place in a copy the collection
     
    425408                        tr("Warning"),
    426409                        JOptionPane.WARNING_MESSAGE
    427                 );
     410                        );
    428411                return;
    429412            }
     
    432415                JOptionPane.showMessageDialog(
    433416                        Main.parent,
    434                         tr("Audio synchronized at point {0}.", recent.text),
     417                        tr("Audio synchronized at point {0}.", recent.getText()),
    435418                        tr("Information"),
    436419                        JOptionPane.INFORMATION_MESSAGE
    437                 );
     420                        );
    438421            } else {
    439422                JOptionPane.showMessageDialog(
     
    442425                        tr("Error"),
    443426                        JOptionPane.ERROR_MESSAGE
    444                 );
     427                        );
    445428            }
    446429        }
     
    462445                        tr("Warning"),
    463446                        JOptionPane.WARNING_MESSAGE
    464                 );
     447                        );
    465448                return;
    466449            }
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/PlayHeadMarker.java

    r2907 r4282  
    5959
    6060    private PlayHeadMarker() {
    61         super(new LatLon(0.0,0.0), "",
     61        super(new LatLon(0.0,0.0), null,
    6262                Main.pref.get("marker.audiotracericon", "audio-tracer"),
    6363                null, -1.0, 0.0);
     
    171171                    tr("Warning"),
    172172                    JOptionPane.WARNING_MESSAGE
    173             );
     173                    );
    174174            endDrag(true);
    175175        } else {
     
    226226                        tr("Warning"),
    227227                        JOptionPane.WARNING_MESSAGE
    228                 );
     228                        );
    229229                endDrag(true);
    230230                return;
     
    241241                    tr("Error"),
    242242                    JOptionPane.ERROR_MESSAGE
    243             );
     243                    );
    244244            endDrag(true);
    245245        }
     
    247247            JOptionPane.showMessageDialog(
    248248                    Main.parent,
    249                     tr("Audio synchronized at point {0}.", ca.text),
     249                    tr("Audio synchronized at point {0}.", ca.getText()),
    250250                    tr("Information"),
    251251                    JOptionPane.INFORMATION_MESSAGE
    252             );
     252                    );
    253253            setCoor(ca.getCoor());
    254254            endDrag(false);
     
    259259                    tr("Error"),
    260260                    JOptionPane.ERROR_MESSAGE
    261             );
     261                    );
    262262            endDrag(true);
    263263        }
     
    294294            return;
    295295        double audioTime = recentlyPlayedMarker.time +
    296         AudioPlayer.position() -
    297         recentlyPlayedMarker.offset -
    298         recentlyPlayedMarker.syncOffset;
     296                AudioPlayer.position() -
     297                recentlyPlayedMarker.offset -
     298                recentlyPlayedMarker.syncOffset;
    299299        if (Math.abs(audioTime - time) < animationInterval)
    300300            return;
  • trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/WebMarker.java

    r2017 r4282  
    2121public class WebMarker extends ButtonMarker {
    2222
    23     public URL webUrl;
     23    public final URL webUrl;
    2424
    25     public static WebMarker create (LatLon ll, String url, MarkerLayer parentLayer, double time, double offset) {
    26         try {
    27             return new WebMarker(ll, new URL(url), parentLayer, time, offset);
    28         } catch (Exception ex) {
    29             return null;
    30         }
    31     }
    32 
    33     private WebMarker(LatLon ll, URL webUrl, MarkerLayer parentLayer, double time, double offset) {
     25    public WebMarker(LatLon ll, URL webUrl, MarkerLayer parentLayer, double time, double offset) {
    3426        super(ll, "web.png", parentLayer, time, offset);
    3527        this.webUrl = webUrl;
     
    4133            JOptionPane.showMessageDialog(Main.parent,
    4234                    "<html><b>" +
    43                     tr("There was an error while trying to display the URL for this marker") +
    44                     "</b><br>" + tr("(URL was: ") + webUrl.toString() + ")" + "<br>" + error,
    45                     tr("Error displaying URL"), JOptionPane.ERROR_MESSAGE);
     35                            tr("There was an error while trying to display the URL for this marker") +
     36                            "</b><br>" + tr("(URL was: ") + webUrl.toString() + ")" + "<br>" + error,
     37                            tr("Error displaying URL"), JOptionPane.ERROR_MESSAGE);
    4638        }
    4739    }
  • trunk/src/org/openstreetmap/josm/gui/preferences/AudioPreference.java

    r3719 r4282  
    6060
    6161        // buttonLabels
    62         markerButtonLabels.setSelected(Main.pref.getBoolean("marker.buttonlabels"));
     62        markerButtonLabels.setSelected(Main.pref.getBoolean("marker.buttonlabels", true));
    6363        markerButtonLabels.setToolTipText(tr("Put text labels against audio (and image and web) markers as well as their button icons."));
    6464        gui.audio.add(markerButtonLabels, GBC.eol().insets(0,0,0,0));
  • trunk/src/org/openstreetmap/josm/gui/preferences/GPXSettingsPanel.java

    r4276 r4282  
    11package org.openstreetmap.josm.gui.preferences;
    22
    3 import javax.swing.AbstractButton;
     3import static org.openstreetmap.josm.tools.I18n.tr;
     4import static org.openstreetmap.josm.tools.I18n.trc;
     5
     6import java.awt.GridBagLayout;
     7import java.awt.event.ActionEvent;
     8import java.awt.event.ActionListener;
     9
     10import javax.swing.BorderFactory;
    411import javax.swing.Box;
    5 import javax.swing.event.ChangeEvent;
    6 import javax.swing.event.ChangeListener;
    7 import java.awt.event.ActionEvent;
    8 import javax.swing.JLabel;
    9 import javax.swing.BorderFactory;
    10 import org.openstreetmap.josm.Main;
    11 import org.openstreetmap.josm.tools.GBC;
    12 import java.awt.GridBagLayout;
    13 import java.awt.event.ActionListener;
    1412import javax.swing.ButtonGroup;
    1513import javax.swing.JCheckBox;
    1614import javax.swing.JComboBox;
     15import javax.swing.JLabel;
    1716import javax.swing.JPanel;
    1817import javax.swing.JRadioButton;
    1918import javax.swing.JTextField;
    20 
    21 import static org.openstreetmap.josm.tools.I18n.tr;
    22 import static org.openstreetmap.josm.tools.I18n.trc;
     19import javax.swing.event.ChangeEvent;
     20import javax.swing.event.ChangeListener;
     21
     22import org.openstreetmap.josm.Main;
     23import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
     24import org.openstreetmap.josm.gui.layer.markerlayer.Marker.TemplateEntryProperty;
     25import org.openstreetmap.josm.tools.GBC;
    2326
    2427public class GPXSettingsPanel extends JPanel {
     28
     29    private static final int WAYPOINT_LABEL_CUSTOM = 6;
     30    private static final String[] LABEL_PATTERN_TEMPLATE = new String[] {Marker.LABEL_PATTERN_AUTO, Marker.LABEL_PATTERN_NAME,
     31        Marker.LABEL_PATTERN_DESC, "{*}", "?{ '{name}' | '{desc}' | '{formattedWaypointOffset}' }", ""};
     32    private static final String[] LABEL_PATTERN_DESC = new String[] {tr("Auto"), /* gpx data field name */ trc("gpx_field", "Name"),
     33        /* gpx data field name */ trc("gpx_field", "Desc(ription)"), tr("Everything"), tr("Name or offset"), tr("None"), tr("Custom")};
     34
     35
    2536    private JRadioButton drawRawGpsLinesGlobal = new JRadioButton(tr("Use global settings."));
    2637    private JRadioButton drawRawGpsLinesAll = new JRadioButton(tr("All"));
     
    4657    private JTextField drawGpsArrowsMinDist = new JTextField(8);
    4758    private JCheckBox colorDynamic = new JCheckBox(tr("Dynamic color range based on data limits"));
    48     private JComboBox waypointLabel = new JComboBox(new String[] {tr("Auto"), /* gpx data field name */ trc("gpx_field", "Name"),
    49             /* gpx data field name */ trc("gpx_field", "Desc(ription)"), tr("Both"), tr("None")});
     59    private JComboBox waypointLabel = new JComboBox(LABEL_PATTERN_DESC);
     60    private JTextField waypointLabelPattern = new JTextField();
     61    private JComboBox audioWaypointLabel = new JComboBox(LABEL_PATTERN_DESC);
     62    private JTextField audioWaypointLabelPattern = new JTextField();
     63
    5064    private String layerName;
    51     private boolean local; // flag to display LocalOnly checkbox 
    52     private boolean nonlocal; // flag to display AllLines checkbox 
     65    private boolean local; // flag to display LocalOnly checkbox
     66    private boolean nonlocal; // flag to display AllLines checkbox
    5367
    5468    public GPXSettingsPanel(String layerName, boolean local, boolean nonlocal) {
     
    7690        // drawRawGpsLines
    7791        ButtonGroup gpsLinesGroup = new ButtonGroup();
    78         if (layerName!=null) gpsLinesGroup.add(drawRawGpsLinesGlobal);
     92        if (layerName!=null) {
     93            gpsLinesGroup.add(drawRawGpsLinesGlobal);
     94        }
    7995        gpsLinesGroup.add(drawRawGpsLinesNone);
    8096        gpsLinesGroup.add(drawRawGpsLinesLocal);
     
    84100
    85101        add(new JLabel(tr("Draw lines between raw GPS points")), GBC.eol().insets(20,0,0,0));
    86         if (layerName!=null) add(drawRawGpsLinesGlobal, GBC.eol().insets(40,0,0,0));
     102        if (layerName!=null) {
     103            add(drawRawGpsLinesGlobal, GBC.eol().insets(40,0,0,0));
     104        }
    87105        add(drawRawGpsLinesNone, GBC.eol().insets(40,0,0,0));
    88         if (layerName==null || local) add(drawRawGpsLinesLocal, GBC.eol().insets(40,0,0,0));
    89         if (layerName==null || nonlocal) add(drawRawGpsLinesAll, GBC.eol().insets(40,0,0,0));
     106        if (layerName==null || local) {
     107            add(drawRawGpsLinesLocal, GBC.eol().insets(40,0,0,0));
     108        }
     109        if (layerName==null || nonlocal) {
     110            add(drawRawGpsLinesAll, GBC.eol().insets(40,0,0,0));
     111        }
    90112
    91113        drawRawGpsLinesActionListener = new ActionListener(){
     
    149171        // colorTracks
    150172        colorGroup = new ButtonGroup();
    151         if (layerName!=null) colorGroup.add(colorTypeGlobal);
     173        if (layerName!=null) {
     174            colorGroup.add(colorTypeGlobal);
     175        }
    152176        colorGroup.add(colorTypeNone);
    153177        colorGroup.add(colorTypeVelocity);
     
    180204
    181205        add(new JLabel(tr("Track and Point Coloring")), GBC.eol().insets(20,0,0,0));
    182         if (layerName!=null) add(colorTypeGlobal, GBC.eol().insets(40,0,0,0));
     206        if (layerName!=null) {
     207            add(colorTypeGlobal, GBC.eol().insets(40,0,0,0));
     208        }
    183209        add(colorTypeNone, GBC.eol().insets(40,0,0,0));
    184210        add(colorTypeVelocity, GBC.std().insets(40,0,0,0));
     
    191217        add(colorDynamic, GBC.eop().insets(40,0,0,0));
    192218
    193         // waypointLabel
    194         add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0));
    195         add(new JLabel(tr("Waypoint labelling")), GBC.std().insets(20,0,0,0));
    196         if(layerName!= null)
    197             waypointLabel.addItem(tr("Global settings"));
    198         add(waypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
     219        if (layerName == null) {
     220            // Setting waypoints for gpx layer doesn't make sense - waypoints are shown in marker layer that has different name - so show
     221            // this only for global config
     222
     223            // waypointLabel
     224            add(new JLabel(tr("Waypoint labelling")), GBC.std().insets(20,0,0,0));
     225            add(waypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
     226            waypointLabel.addActionListener(new ActionListener() {
     227                @Override
     228                public void actionPerformed(ActionEvent e) {
     229                    updateWaypointPattern(waypointLabel, waypointLabelPattern);
     230                }
     231            });
     232            updateWaypointLabelCombobox(waypointLabel, waypointLabelPattern, TemplateEntryProperty.forMarker(layerName));
     233            add(waypointLabelPattern, GBC.eol().fill(GBC.HORIZONTAL).insets(20,0,0,5));
     234
     235            // audioWaypointLabel
     236            add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0));
     237
     238            add(new JLabel(tr("Audio waypoint labelling")), GBC.std().insets(20,0,0,0));
     239            add(audioWaypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
     240            audioWaypointLabel.addActionListener(new ActionListener() {
     241                @Override
     242                public void actionPerformed(ActionEvent e) {
     243                    updateWaypointPattern(audioWaypointLabel, audioWaypointLabelPattern);
     244                }
     245            });
     246            updateWaypointLabelCombobox(audioWaypointLabel, audioWaypointLabelPattern, TemplateEntryProperty.forAudioMarker(layerName));
     247            add(audioWaypointLabelPattern, GBC.eol().fill(GBC.HORIZONTAL).insets(20,0,0,5));
     248        }
     249
    199250        add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
    200251    }
     
    235286            colorDynamic.setEnabled(false);
    236287        } else {
    237          switch(Main.pref.getInteger("draw.rawgps.colors",layerName, 0)) {
     288            switch(Main.pref.getInteger("draw.rawgps.colors",layerName, 0)) {
    238289            case 0: colorTypeNone.setSelected(true);   break;
    239290            case 1: colorTypeVelocity.setSelected(true);  break;
     
    248299            colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected());
    249300        }
    250         if(layerName != null)
    251           waypointLabel.setSelectedIndex(Main.pref.getInteger("draw.rawgps.layer.wpt."+layerName, 5));
    252         else
    253           waypointLabel.setSelectedIndex(Main.pref.getInteger("draw.rawgps.layer.wpt", 0));
    254301    }
    255302
     
    261308    public boolean savePreferences (String layerName, boolean locLayer) {
    262309        String layerNameDot = ".layer "+layerName;
    263         if (layerName==null) layerNameDot="";
     310        if (layerName==null) {
     311            layerNameDot="";
     312        }
    264313        Main.pref.put("marker.makeautomarkers"+layerNameDot, makeAutoMarkers.isSelected());
    265314        if (drawRawGpsLinesGlobal.isSelected()) {
     
    289338        Main.pref.put("draw.rawgps.hdopcircle"+layerNameDot, hdopCircleGpsPoints.isSelected());
    290339        Main.pref.put("draw.rawgps.large"+layerNameDot, largeGpsPoints.isSelected());
    291         if (waypointLabel.getSelectedIndex()==5) Main.pref.put("draw.rawgps.layer.wpt"+layerNameDot,null);
    292         else Main.pref.putInteger("draw.rawgps.layer.wpt"+layerNameDot, waypointLabel.getSelectedIndex());
     340
     341        TemplateEntryProperty.forMarker(layerName).put(waypointLabelPattern.getText());
     342        TemplateEntryProperty.forAudioMarker(layerName).put(audioWaypointLabelPattern.getText());
    293343
    294344        if(colorTypeGlobal.isSelected()) {
     
    320370        savePreferences(null, false);
    321371    }
     372
     373    private void updateWaypointLabelCombobox(JComboBox cb, JTextField tf, TemplateEntryProperty property) {
     374        String labelPattern = property.getAsString();
     375        boolean found = false;
     376        for (int i=0; i<LABEL_PATTERN_TEMPLATE.length; i++) {
     377            if (LABEL_PATTERN_TEMPLATE[i].equals(labelPattern)) {
     378                cb.setSelectedIndex(i);
     379                found = true;
     380                break;
     381            }
     382        }
     383        if (!found) {
     384            cb.setSelectedIndex(WAYPOINT_LABEL_CUSTOM);
     385            tf.setEnabled(true);
     386            tf.setText(labelPattern);
     387        }
     388    }
     389
     390    private void updateWaypointPattern(JComboBox cb, JTextField tf) {
     391        if (cb.getSelectedIndex() == WAYPOINT_LABEL_CUSTOM) {
     392            tf.setEnabled(true);
     393        } else {
     394            tf.setEnabled(false);
     395            tf.setText(LABEL_PATTERN_TEMPLATE[cb.getSelectedIndex()]);
     396        }
     397    }
     398
    322399}
Note: See TracChangeset for help on using the changeset viewer.