001    package org.openstreetmap.josm.gui.preferences.display;
002    
003    import static org.openstreetmap.josm.tools.I18n.tr;
004    import static org.openstreetmap.josm.tools.I18n.trc;
005    
006    import java.awt.Component;
007    import java.awt.GridBagLayout;
008    import java.awt.event.ActionEvent;
009    import java.awt.event.ActionListener;
010    
011    import javax.swing.BorderFactory;
012    import javax.swing.Box;
013    import javax.swing.ButtonGroup;
014    import javax.swing.JCheckBox;
015    import javax.swing.JLabel;
016    import javax.swing.JOptionPane;
017    import javax.swing.JPanel;
018    import javax.swing.JRadioButton;
019    import javax.swing.JTextField;
020    import javax.swing.event.ChangeEvent;
021    import javax.swing.event.ChangeListener;
022    
023    import org.openstreetmap.josm.Main;
024    import org.openstreetmap.josm.actions.ExpertToggleAction;
025    import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
026    import org.openstreetmap.josm.gui.layer.markerlayer.Marker.TemplateEntryProperty;
027    import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener;
028    import org.openstreetmap.josm.gui.widgets.JosmComboBox;
029    import org.openstreetmap.josm.tools.GBC;
030    import org.openstreetmap.josm.tools.template_engine.ParseError;
031    import org.openstreetmap.josm.tools.template_engine.TemplateParser;
032    
033    public class GPXSettingsPanel extends JPanel implements ValidationListener {
034    
035        private static final int WAYPOINT_LABEL_CUSTOM = 6;
036        private static final String[] LABEL_PATTERN_TEMPLATE = new String[] {Marker.LABEL_PATTERN_AUTO, Marker.LABEL_PATTERN_NAME,
037            Marker.LABEL_PATTERN_DESC, "{special:everything}", "?{ '{name}' | '{desc}' | '{formattedWaypointOffset}' }", ""};
038        private static final String[] LABEL_PATTERN_DESC = new String[] {tr("Auto"), /* gpx data field name */ trc("gpx_field", "Name"),
039            /* gpx data field name */ trc("gpx_field", "Desc(ription)"), tr("Everything"), tr("Name or offset"), tr("None"), tr("Custom")};
040    
041    
042        private JRadioButton drawRawGpsLinesGlobal = new JRadioButton(tr("Use global settings"));
043        private JRadioButton drawRawGpsLinesAll = new JRadioButton(tr("All"));
044        private JRadioButton drawRawGpsLinesLocal = new JRadioButton(tr("Local files"));
045        private JRadioButton drawRawGpsLinesNone = new JRadioButton(tr("None"));
046        private ActionListener drawRawGpsLinesActionListener;
047        private JTextField drawRawGpsMaxLineLength = new JTextField(8);
048        private JTextField drawRawGpsMaxLineLengthLocal = new JTextField(8);
049        private JTextField drawLineWidth = new JTextField(2);
050        private JCheckBox forceRawGpsLines = new JCheckBox(tr("Force lines if no segments imported"));
051        private JCheckBox largeGpsPoints = new JCheckBox(tr("Draw large GPS points"));
052        private JCheckBox hdopCircleGpsPoints = new JCheckBox(tr("Draw a circle from HDOP value"));
053        private ButtonGroup colorGroup;
054        private JRadioButton colorTypeVelocity = new JRadioButton(tr("Velocity (red = slow, green = fast)"));
055        private JRadioButton colorTypeDirection = new JRadioButton(tr("Direction (red = west, yellow = north, green = east, blue = south)"));
056        private JRadioButton colorTypeDilution = new JRadioButton(tr("Dilution of Position (red = high, green = low, if available)"));
057        private JRadioButton colorTypeTime = new JRadioButton(tr("Track date"));
058        private JRadioButton colorTypeNone = new JRadioButton(tr("Single Color (can be customized for named layers)"));
059        private JRadioButton colorTypeGlobal  = new JRadioButton(tr("Use global settings"));
060        private JosmComboBox colorTypeVelocityTune = new JosmComboBox(new String[] {tr("Car"), tr("Bicycle"), tr("Foot")});
061        private JCheckBox makeAutoMarkers = new JCheckBox(tr("Create markers when reading GPX"));
062        private JCheckBox drawGpsArrows = new JCheckBox(tr("Draw Direction Arrows"));
063        private JCheckBox drawGpsArrowsFast = new JCheckBox(tr("Fast drawing (looks uglier)"));
064        private JTextField drawGpsArrowsMinDist = new JTextField(8);
065        private JCheckBox colorDynamic = new JCheckBox(tr("Dynamic color range based on data limits"));
066        private JosmComboBox waypointLabel = new JosmComboBox(LABEL_PATTERN_DESC);
067        private JTextField waypointLabelPattern = new JTextField();
068        private JosmComboBox audioWaypointLabel = new JosmComboBox(LABEL_PATTERN_DESC);
069        private JTextField audioWaypointLabelPattern = new JTextField();
070        private JCheckBox useGpsAntialiasing = new JCheckBox(tr("Smooth GPX graphics (antialiasing)"));
071    
072        private String layerName;
073        private boolean local; // flag to display LocalOnly checkbox
074        private boolean nonlocal; // flag to display AllLines checkbox
075    
076        public GPXSettingsPanel(String layerName, boolean local, boolean nonlocal) {
077            super(new GridBagLayout());
078            this.local=local; this.nonlocal=nonlocal;
079            this.layerName = "layer "+layerName;
080            initComponents();
081            loadPreferences();
082        }
083    
084        public GPXSettingsPanel() {
085            super(new GridBagLayout());
086            initComponents();
087            local=false; nonlocal=false;
088            loadPreferences(); // preferences -> controls
089        }
090    
091        private void initComponents() {
092            setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
093    
094            // makeAutoMarkers
095            makeAutoMarkers.setToolTipText(tr("Automatically make a marker layer from any waypoints when opening a GPX layer."));
096            ExpertToggleAction.addVisibilitySwitcher(makeAutoMarkers);
097            add(makeAutoMarkers, GBC.eol().insets(20,0,0,5));
098    
099            // drawRawGpsLines
100            ButtonGroup gpsLinesGroup = new ButtonGroup();
101            if (layerName!=null) {
102                gpsLinesGroup.add(drawRawGpsLinesGlobal);
103            }
104            gpsLinesGroup.add(drawRawGpsLinesNone);
105            gpsLinesGroup.add(drawRawGpsLinesLocal);
106            gpsLinesGroup.add(drawRawGpsLinesAll);
107    
108            /* ensure that default is in data base */
109    
110            JLabel label = new JLabel(tr("Draw lines between raw GPS points"));
111            add(label, GBC.eol().insets(20,0,0,0));
112            if (layerName!=null) {
113                add(drawRawGpsLinesGlobal, GBC.eol().insets(40,0,0,0));
114            }
115            add(drawRawGpsLinesNone, GBC.eol().insets(40,0,0,0));
116            if (layerName==null || local) {
117                add(drawRawGpsLinesLocal, GBC.eol().insets(40,0,0,0));
118            }
119            if (layerName==null || nonlocal) {
120                add(drawRawGpsLinesAll, GBC.eol().insets(40,0,0,0));
121            }
122            ExpertToggleAction.addVisibilitySwitcher(label);
123            ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesGlobal);
124            ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesNone);
125            ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesLocal);
126            ExpertToggleAction.addVisibilitySwitcher(drawRawGpsLinesAll);
127    
128            drawRawGpsLinesActionListener = new ActionListener(){
129                public void actionPerformed(ActionEvent e) {
130                    boolean f=drawRawGpsLinesNone.isSelected()||drawRawGpsLinesGlobal.isSelected();
131                    forceRawGpsLines.setEnabled(!f);
132                    drawRawGpsMaxLineLength.setEnabled(!(f || drawRawGpsLinesLocal.isSelected()));
133                    drawRawGpsMaxLineLengthLocal.setEnabled(!f);
134                    drawGpsArrows.setEnabled(!f);
135                    drawGpsArrowsFast.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
136                    drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
137                }
138            };
139    
140            drawRawGpsLinesGlobal.addActionListener(drawRawGpsLinesActionListener);
141            drawRawGpsLinesNone.addActionListener(drawRawGpsLinesActionListener);
142            drawRawGpsLinesLocal.addActionListener(drawRawGpsLinesActionListener);
143            drawRawGpsLinesAll.addActionListener(drawRawGpsLinesActionListener);
144    
145            // drawRawGpsMaxLineLengthLocal
146            drawRawGpsMaxLineLengthLocal.setToolTipText(tr("Maximum length (in meters) to draw lines for local files. Set to ''-1'' to draw all lines."));
147            label = new JLabel(tr("Maximum length for local files (meters)"));
148            add(label, GBC.std().insets(40,0,0,0));
149            add(drawRawGpsMaxLineLengthLocal, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
150            ExpertToggleAction.addVisibilitySwitcher(label);
151            ExpertToggleAction.addVisibilitySwitcher(drawRawGpsMaxLineLengthLocal);
152    
153            // drawRawGpsMaxLineLength
154            drawRawGpsMaxLineLength.setToolTipText(tr("Maximum length (in meters) to draw lines. Set to ''-1'' to draw all lines."));
155            label = new JLabel(tr("Maximum length (meters)"));
156            add(label, GBC.std().insets(40,0,0,0));
157            add(drawRawGpsMaxLineLength, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
158            ExpertToggleAction.addVisibilitySwitcher(label);
159            ExpertToggleAction.addVisibilitySwitcher(drawRawGpsMaxLineLength);
160    
161            // forceRawGpsLines
162            forceRawGpsLines.setToolTipText(tr("Force drawing of lines if the imported data contain no line information."));
163            add(forceRawGpsLines, GBC.eop().insets(40,0,0,0));
164            ExpertToggleAction.addVisibilitySwitcher(forceRawGpsLines);
165    
166            // drawGpsArrows
167            drawGpsArrows.addActionListener(new ActionListener(){
168                public void actionPerformed(ActionEvent e) {
169                    drawGpsArrowsFast.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
170                    drawGpsArrowsMinDist.setEnabled(drawGpsArrows.isSelected() && drawGpsArrows.isEnabled());
171                }
172            });
173            drawGpsArrows.setToolTipText(tr("Draw direction arrows for lines, connecting GPS points."));
174            add(drawGpsArrows, GBC.eop().insets(40,0,0,0));
175    
176            // drawGpsArrowsFast
177            drawGpsArrowsFast.setToolTipText(tr("Draw the direction arrows using table lookups instead of complex math."));
178            add(drawGpsArrowsFast, GBC.eop().insets(60,0,0,0));
179            ExpertToggleAction.addVisibilitySwitcher(drawGpsArrowsFast);
180    
181            // drawGpsArrowsMinDist
182            drawGpsArrowsMinDist.setToolTipText(tr("Do not draw arrows if they are not at least this distance away from the last one."));
183            add(new JLabel(tr("Minimum distance (pixels)")), GBC.std().insets(60,0,0,0));
184            add(drawGpsArrowsMinDist, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
185    
186            // hdopCircleGpsPoints
187            hdopCircleGpsPoints.setToolTipText(tr("Draw a circle from HDOP value."));
188            add(hdopCircleGpsPoints, GBC.eop().insets(20,0,0,0));
189            ExpertToggleAction.addVisibilitySwitcher(hdopCircleGpsPoints);
190    
191            // largeGpsPoints
192            largeGpsPoints.setToolTipText(tr("Draw larger dots for the GPS points."));
193            add(largeGpsPoints, GBC.eop().insets(20,0,0,0));
194    
195            // drawLineWidth
196            drawLineWidth.setToolTipText(tr("Width of drawn GPX line (0 for default)"));
197            add(new JLabel(tr("Drawing width of GPX lines")), GBC.std().insets(20,0,0,0));
198            add(drawLineWidth, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
199    
200            // antialiasing
201            useGpsAntialiasing.setToolTipText(tr("Apply antialiasing to the GPX lines resulting in a smoother appearance."));
202            add(useGpsAntialiasing, GBC.eop().insets(20, 0, 0, 0));
203            ExpertToggleAction.addVisibilitySwitcher(useGpsAntialiasing);
204    
205            // colorTracks
206            colorGroup = new ButtonGroup();
207            if (layerName!=null) {
208                colorGroup.add(colorTypeGlobal);
209            }
210            colorGroup.add(colorTypeNone);
211            colorGroup.add(colorTypeVelocity);
212            colorGroup.add(colorTypeDirection);
213            colorGroup.add(colorTypeDilution);
214            colorGroup.add(colorTypeTime);
215    
216            colorTypeVelocity.addChangeListener(new ChangeListener(){
217                public void stateChanged(ChangeEvent e) {
218                    colorTypeVelocityTune.setEnabled(colorTypeVelocity.isSelected());
219                    colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected());
220                }
221            });
222            colorTypeDilution.addChangeListener(new ChangeListener(){
223                public void stateChanged(ChangeEvent e) {
224                    colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected());
225                }
226            });
227    
228            colorTypeNone.setToolTipText(tr("All points and track segments will have the same color. Can be customized in Layer Manager."));
229            colorTypeVelocity.setToolTipText(tr("Colors points and track segments by velocity."));
230            colorTypeDirection.setToolTipText(tr("Colors points and track segments by direction."));
231            colorTypeDilution.setToolTipText(tr("Colors points and track segments by dilution of position (HDOP). Your capture device needs to log that information."));
232            colorTypeTime.setToolTipText(tr("Colors points and track segments by its timestamp."));
233    
234            // color Tracks by Velocity Tune
235            colorTypeVelocityTune.setToolTipText(tr("Allows to tune the track coloring for different average speeds."));
236    
237            add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0));
238    
239            add(new JLabel(tr("Track and Point Coloring")), GBC.eol().insets(20,0,0,0));
240            if (layerName!=null) {
241                add(colorTypeGlobal, GBC.eol().insets(40,0,0,0));
242            }
243            add(colorTypeNone, GBC.eol().insets(40,0,0,0));
244            add(colorTypeVelocity, GBC.std().insets(40,0,0,0));
245            add(colorTypeVelocityTune, GBC.eop().insets(5,0,0,5));
246            add(colorTypeDirection, GBC.eol().insets(40,0,0,0));
247            add(colorTypeDilution, GBC.eol().insets(40,0,0,0));
248            add(colorTypeTime, GBC.eol().insets(40,0,0,0));
249            ExpertToggleAction.addVisibilitySwitcher(colorTypeDirection);
250            ExpertToggleAction.addVisibilitySwitcher(colorTypeDilution);
251    
252            colorDynamic.setToolTipText(tr("Colors points and track segments by data limits."));
253            add(colorDynamic, GBC.eop().insets(40,0,0,0));
254            ExpertToggleAction.addVisibilitySwitcher(colorDynamic);
255    
256            if (layerName == null) {
257                // Setting waypoints for gpx layer doesn't make sense - waypoints are shown in marker layer that has different name - so show
258                // this only for global config
259    
260                // waypointLabel
261                label = new JLabel(tr("Waypoint labelling"));
262                add(label, GBC.std().insets(20,0,0,0));
263                add(waypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
264                waypointLabel.addActionListener(new ActionListener() {
265                    @Override
266                    public void actionPerformed(ActionEvent e) {
267                        updateWaypointPattern(waypointLabel, waypointLabelPattern);
268                    }
269                });
270                updateWaypointLabelCombobox(waypointLabel, waypointLabelPattern, TemplateEntryProperty.forMarker(layerName));
271                add(waypointLabelPattern, GBC.eol().fill(GBC.HORIZONTAL).insets(20,0,0,5));
272                ExpertToggleAction.addVisibilitySwitcher(label);
273                ExpertToggleAction.addVisibilitySwitcher(waypointLabel);
274                ExpertToggleAction.addVisibilitySwitcher(waypointLabelPattern);
275    
276                // audioWaypointLabel
277                Component glue = Box.createVerticalGlue();
278                add(glue, GBC.eol().insets(0, 20, 0, 0));
279                ExpertToggleAction.addVisibilitySwitcher(glue);
280    
281                label = new JLabel(tr("Audio waypoint labelling"));
282                add(label, GBC.std().insets(20,0,0,0));
283                add(audioWaypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
284                audioWaypointLabel.addActionListener(new ActionListener() {
285                    @Override
286                    public void actionPerformed(ActionEvent e) {
287                        updateWaypointPattern(audioWaypointLabel, audioWaypointLabelPattern);
288                    }
289                });
290                updateWaypointLabelCombobox(audioWaypointLabel, audioWaypointLabelPattern, TemplateEntryProperty.forAudioMarker(layerName));
291                add(audioWaypointLabelPattern, GBC.eol().fill(GBC.HORIZONTAL).insets(20,0,0,5));
292                ExpertToggleAction.addVisibilitySwitcher(label);
293                ExpertToggleAction.addVisibilitySwitcher(audioWaypointLabel);
294                ExpertToggleAction.addVisibilitySwitcher(audioWaypointLabelPattern);
295            }
296    
297            add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
298        }
299    
300        /**
301         * Loads preferences to UI controls
302         */
303        public void loadPreferences () {
304            makeAutoMarkers.setSelected(Main.pref.getBoolean("marker.makeautomarkers", true));
305            if(layerName!=null && Main.pref.get("draw.rawgps.lines."+layerName).isEmpty()
306                    && Main.pref.get("draw.rawgps.lines.local."+layerName).isEmpty()){
307                // no line preferences for layer is found
308                drawRawGpsLinesGlobal.setSelected(true);
309            } else {
310                Boolean lf = Main.pref.getBoolean("draw.rawgps.lines.local",layerName, true);
311                if(Main.pref.getBoolean("draw.rawgps.lines",layerName, true)) {
312                    drawRawGpsLinesAll.setSelected(true);
313                } else if (lf) {
314                    drawRawGpsLinesLocal.setSelected(true);
315                } else {
316                    drawRawGpsLinesNone.setSelected(true);
317                }
318            }
319    
320            drawRawGpsMaxLineLengthLocal.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length.local",layerName, -1)));
321            drawRawGpsMaxLineLength.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length",layerName, 200)));
322            drawLineWidth.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.linewidth",layerName, 0)));
323            forceRawGpsLines.setSelected(Main.pref.getBoolean("draw.rawgps.lines.force",layerName, false));
324            drawGpsArrows.setSelected(Main.pref.getBoolean("draw.rawgps.direction",layerName, false));
325            drawGpsArrowsFast.setSelected(Main.pref.getBoolean("draw.rawgps.alternatedirection",layerName, false));
326            drawGpsArrowsMinDist.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.min-arrow-distance",layerName, 40)));
327            hdopCircleGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.hdopcircle",layerName, false));
328            largeGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.large",layerName, false));
329            useGpsAntialiasing.setSelected(Main.pref.getBoolean("mappaint.gpx.use-antialiasing", false));
330            drawRawGpsLinesActionListener.actionPerformed(null);
331    
332            if(layerName!=null && Main.pref.get("draw.rawgps.colors."+layerName).isEmpty()) {
333                colorTypeGlobal.setSelected(true);
334                colorDynamic.setSelected(false);
335                colorDynamic.setEnabled(false);
336            } else {
337                switch(Main.pref.getInteger("draw.rawgps.colors",layerName, 0)) {
338                case 0: colorTypeNone.setSelected(true);   break;
339                case 1: colorTypeVelocity.setSelected(true);  break;
340                case 2: colorTypeDilution.setSelected(true);  break;
341                case 3: colorTypeDirection.setSelected(true); break;
342                case 4: colorTypeTime.setSelected(true);  break;
343                }
344                int ccts = Main.pref.getInteger("draw.rawgps.colorTracksTune",layerName, 45);
345                colorTypeVelocityTune.setSelectedIndex(ccts==10 ? 2 : (ccts==20 ? 1 : 0));
346                colorTypeVelocityTune.setEnabled(colorTypeVelocity.isSelected() && colorTypeVelocity.isEnabled());
347                colorDynamic.setSelected(Main.pref.getBoolean("draw.rawgps.colors.dynamic",layerName, false));
348                colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected());
349            }
350        }
351    
352    
353        /**
354         * Save preferences from UI controls for specified layer
355         * if layerName==null, global preferences are written
356         */
357        public boolean savePreferences (String layerName, boolean locLayer) {
358            String layerNameDot = ".layer "+layerName;
359            if (layerName==null) {
360                layerNameDot="";
361            }
362            Main.pref.put("marker.makeautomarkers"+layerNameDot, makeAutoMarkers.isSelected());
363            if (drawRawGpsLinesGlobal.isSelected()) {
364                Main.pref.put("draw.rawgps.lines" + layerNameDot, null);
365                Main.pref.put("draw.rawgps.max-line-length" + layerNameDot, null);
366                Main.pref.put("draw.rawgps.lines.local" + layerNameDot, null);
367                Main.pref.put("draw.rawgps.max-line-length.local" + layerNameDot, null);
368                Main.pref.put("draw.rawgps.lines.force"+layerNameDot, null);
369                Main.pref.put("draw.rawgps.direction"+layerNameDot, null);
370                Main.pref.put("draw.rawgps.alternatedirection"+layerNameDot, null);
371                Main.pref.put("draw.rawgps.min-arrow-distance"+layerNameDot, null);
372            } else {
373                if (layerName==null || !locLayer) {
374                    Main.pref.put("draw.rawgps.lines" +  layerNameDot, drawRawGpsLinesAll.isSelected());
375                    Main.pref.put("draw.rawgps.max-line-length" + layerNameDot, drawRawGpsMaxLineLength.getText());
376                }
377                if (layerName==null || locLayer) {
378                    Main.pref.put("draw.rawgps.lines.local" + layerNameDot, drawRawGpsLinesAll.isSelected() || drawRawGpsLinesLocal.isSelected());
379                    Main.pref.put("draw.rawgps.max-line-length.local" + layerNameDot, drawRawGpsMaxLineLengthLocal.getText());
380                }
381                Main.pref.put("draw.rawgps.lines.force"+layerNameDot, forceRawGpsLines.isSelected());
382                Main.pref.put("draw.rawgps.direction"+layerNameDot, drawGpsArrows.isSelected());
383                Main.pref.put("draw.rawgps.alternatedirection"+layerNameDot, drawGpsArrowsFast.isSelected());
384                Main.pref.put("draw.rawgps.min-arrow-distance"+layerNameDot, drawGpsArrowsMinDist.getText());
385            }
386    
387            Main.pref.put("draw.rawgps.hdopcircle"+layerNameDot, hdopCircleGpsPoints.isSelected());
388            Main.pref.put("draw.rawgps.large"+layerNameDot, largeGpsPoints.isSelected());
389            Main.pref.put("draw.rawgps.linewidth"+layerNameDot, drawLineWidth.getText());
390            Main.pref.put("mappaint.gpx.use-antialiasing", useGpsAntialiasing.isSelected());
391    
392            TemplateEntryProperty.forMarker(layerName).put(waypointLabelPattern.getText());
393            TemplateEntryProperty.forAudioMarker(layerName).put(audioWaypointLabelPattern.getText());
394    
395            if(colorTypeGlobal.isSelected()) {
396                Main.pref.put("draw.rawgps.colors"+layerNameDot, null);
397                Main.pref.put("draw.rawgps.colors.dynamic"+layerNameDot, null);
398                Main.pref.put("draw.rawgps.colorTracksTunec"+layerNameDot, null);
399                return false;
400            } else if(colorTypeVelocity.isSelected()) {
401                Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 1);
402            } else if(colorTypeDilution.isSelected()) {
403                Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 2);
404            } else if(colorTypeDirection.isSelected()) {
405                Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 3);
406            } else if(colorTypeTime.isSelected()) {
407                Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 4);
408            } else {
409                Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 0);
410            }
411            Main.pref.put("draw.rawgps.colors.dynamic"+layerNameDot, colorDynamic.isSelected());
412            int ccti=colorTypeVelocityTune.getSelectedIndex();
413            Main.pref.putInteger("draw.rawgps.colorTracksTune"+layerNameDot, ccti==2 ? 10 : (ccti==1 ? 20 : 45));
414            return false;
415        }
416    
417        /**
418         * Save preferences from UI controls for initial layer or globally
419         */
420        public void savePreferences() {
421            savePreferences(null, false);
422        }
423    
424        private void updateWaypointLabelCombobox(JosmComboBox cb, JTextField tf, TemplateEntryProperty property) {
425            String labelPattern = property.getAsString();
426            boolean found = false;
427            for (int i=0; i<LABEL_PATTERN_TEMPLATE.length; i++) {
428                if (LABEL_PATTERN_TEMPLATE[i].equals(labelPattern)) {
429                    cb.setSelectedIndex(i);
430                    found = true;
431                    break;
432                }
433            }
434            if (!found) {
435                cb.setSelectedIndex(WAYPOINT_LABEL_CUSTOM);
436                tf.setEnabled(true);
437                tf.setText(labelPattern);
438            }
439        }
440    
441        private void updateWaypointPattern(JosmComboBox cb, JTextField tf) {
442            if (cb.getSelectedIndex() == WAYPOINT_LABEL_CUSTOM) {
443                tf.setEnabled(true);
444            } else {
445                tf.setEnabled(false);
446                tf.setText(LABEL_PATTERN_TEMPLATE[cb.getSelectedIndex()]);
447            }
448        }
449    
450        @Override
451        public boolean validatePreferences() {
452            TemplateParser parser = new TemplateParser(waypointLabelPattern.getText());
453            try {
454                parser.parse();
455            } catch (ParseError e) {
456                JOptionPane.showMessageDialog(Main.parent, tr("Incorrect waypoint label pattern: {0}", e.getMessage()), tr("Incorrect pattern"), JOptionPane.ERROR_MESSAGE);
457                waypointLabelPattern.requestFocus();
458                return false;
459            }
460            parser = new TemplateParser(audioWaypointLabelPattern.getText());
461            try {
462                parser.parse();
463            } catch (ParseError e) {
464                JOptionPane.showMessageDialog(Main.parent, tr("Incorrect audio waypoint label pattern: {0}", e.getMessage()), tr("Incorrect pattern"), JOptionPane.ERROR_MESSAGE);
465                audioWaypointLabelPattern.requestFocus();
466                return false;
467            }
468            return true;
469        }
470    
471    }