001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.preferences.display;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.GridBagLayout;
007
008import javax.swing.BorderFactory;
009import javax.swing.Box;
010import javax.swing.JCheckBox;
011import javax.swing.JLabel;
012import javax.swing.JPanel;
013import javax.swing.JScrollPane;
014
015import org.openstreetmap.josm.actions.ExpertToggleAction;
016import org.openstreetmap.josm.data.preferences.BooleanProperty;
017import org.openstreetmap.josm.gui.autofilter.AutoFilterManager;
018import org.openstreetmap.josm.gui.autofilter.AutoFilterRule;
019import org.openstreetmap.josm.gui.layer.OsmDataLayer;
020import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
021import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
022import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
023import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
024import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
025import org.openstreetmap.josm.gui.util.GuiHelper;
026import org.openstreetmap.josm.gui.widgets.JosmComboBox;
027import org.openstreetmap.josm.spi.preferences.Config;
028import org.openstreetmap.josm.tools.GBC;
029
030/**
031 * Map drawing preferences.
032 */
033public class DrawingPreference implements SubPreferenceSetting {
034
035    /**
036     * Factory used to create a new {@code DrawingPreference}.
037     */
038    public static class Factory implements PreferenceSettingFactory {
039        @Override
040        public PreferenceSetting createPreferenceSetting() {
041            return new DrawingPreference();
042        }
043    }
044
045    /**
046     * Property controlling whether to draw boundaries of downloaded data
047     * @since 14648
048     */
049    public static final BooleanProperty SOURCE_BOUNDS_PROP = new BooleanProperty("draw.data.downloaded_area", true);
050
051    private GPXSettingsPanel gpxPanel;
052    private final JCheckBox directionHint = new JCheckBox(tr("Draw Direction Arrows"));
053    private final JCheckBox headArrow = new JCheckBox(tr("Only on the head of a way."));
054    private final JCheckBox onewayArrow = new JCheckBox(tr("Draw oneway arrows."));
055    private final JCheckBox segmentOrderNumber = new JCheckBox(tr("Draw segment order numbers"));
056    private final JCheckBox segmentOrderNumberOnSelectedWay = new JCheckBox(tr("Draw segment order numbers on selected way"));
057    private final JCheckBox sourceBounds = new JCheckBox(tr("Draw boundaries of downloaded data"));
058    private final JCheckBox virtualNodes = new JCheckBox(tr("Draw virtual nodes in select mode"));
059    private final JCheckBox inactive = new JCheckBox(tr("Draw inactive layers in other color"));
060    private final JCheckBox discardableKeys = new JCheckBox(tr("Display discardable keys"));
061    private final JCheckBox autoFilters = new JCheckBox(tr("Use auto filters"));
062    private final JLabel lblRule = new JLabel(tr("Rule"));
063    private final JosmComboBox<AutoFilterRule> autoFilterRules = new JosmComboBox<>(
064            AutoFilterManager.getInstance().getAutoFilterRules().toArray(new AutoFilterRule[] {}));
065
066    // Options that affect performance
067    private final JCheckBox useHighlighting = new JCheckBox(tr("Highlight target ways and nodes"));
068    private final JCheckBox drawHelperLine = new JCheckBox(tr("Draw rubber-band helper line"));
069    private final JCheckBox useAntialiasing = new JCheckBox(tr("Smooth map graphics (antialiasing)"));
070    private final JCheckBox useWireframeAntialiasing = new JCheckBox(tr("Smooth map graphics in wireframe mode (antialiasing)"));
071    private final JCheckBox outlineOnly = new JCheckBox(tr("Draw only outlines of areas"));
072    private final JCheckBox hideLabelsWhileDragging = new JCheckBox(tr("Hide labels while dragging the map"));
073
074    @Override
075    public void addGui(PreferenceTabbedPane gui) {
076        gpxPanel = new GPXSettingsPanel();
077        gui.addValidationListener(gpxPanel);
078        JPanel panel = gpxPanel;
079
080        JScrollPane scrollpane = new JScrollPane(panel);
081        scrollpane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
082        GuiHelper.setDefaultIncrement(scrollpane);
083        gui.getDisplayPreference().addSubTab(this, tr("GPS Points"), scrollpane);
084        panel = new JPanel(new GridBagLayout());
085        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
086
087        // directionHint
088        directionHint.addActionListener(e -> {
089            if (directionHint.isSelected()) {
090                headArrow.setSelected(Config.getPref().getBoolean("draw.segment.head_only", false));
091            } else {
092                headArrow.setSelected(false);
093            }
094            headArrow.setEnabled(directionHint.isSelected());
095        });
096        directionHint.setToolTipText(tr("Draw direction hints for way segments."));
097        directionHint.setSelected(Config.getPref().getBoolean("draw.segment.direction", false));
098
099        // only on the head of a way
100        headArrow.setToolTipText(tr("Only on the head of a way."));
101        headArrow.setSelected(Config.getPref().getBoolean("draw.segment.head_only", false));
102        headArrow.setEnabled(directionHint.isSelected());
103
104        // draw oneway arrows
105        onewayArrow.setToolTipText(tr("Draw arrows in the direction of oneways and other directed features."));
106        onewayArrow.setSelected(Config.getPref().getBoolean("draw.oneway", true));
107
108        // segment order number
109        segmentOrderNumber.setToolTipText(tr("Draw the order numbers of all segments within their way."));
110        segmentOrderNumber.setSelected(Config.getPref().getBoolean("draw.segment.order_number", false));
111        segmentOrderNumberOnSelectedWay.setToolTipText(tr("Draw the order numbers of all segments within their way."));
112        segmentOrderNumberOnSelectedWay.setSelected(Config.getPref().getBoolean("draw.segment.order_number.on_selected", false));
113
114        // downloaded area
115        sourceBounds.setToolTipText(tr("Draw the boundaries of data loaded from the server."));
116        sourceBounds.setSelected(SOURCE_BOUNDS_PROP.get());
117
118        // virtual nodes
119        virtualNodes.setToolTipText(tr("Draw virtual nodes in select mode for easy way modification."));
120        virtualNodes.setSelected(Config.getPref().getInt("mappaint.node.virtual-size", 8) != 0);
121
122        // background layers in inactive color
123        inactive.setToolTipText(tr("Draw the inactive data layers in a different color."));
124        inactive.setSelected(Config.getPref().getBoolean("draw.data.inactive_color", true));
125
126        // antialiasing
127        useAntialiasing.setToolTipText(tr("Apply antialiasing to the map view resulting in a smoother appearance."));
128        useAntialiasing.setSelected(Config.getPref().getBoolean("mappaint.use-antialiasing", true));
129
130        // wireframe mode antialiasing
131        useWireframeAntialiasing.setToolTipText(tr("Apply antialiasing to the map view in wireframe mode resulting in a smoother appearance."));
132        useWireframeAntialiasing.setSelected(Config.getPref().getBoolean("mappaint.wireframe.use-antialiasing", false));
133
134        // highlighting
135        useHighlighting.setToolTipText(tr("Hightlight target nodes and ways while drawing or selecting"));
136        useHighlighting.setSelected(Config.getPref().getBoolean("draw.target-highlight", true));
137
138        drawHelperLine.setToolTipText(tr("Draw rubber-band helper line"));
139        drawHelperLine.setSelected(Config.getPref().getBoolean("draw.helper-line", true));
140
141        // outlineOnly
142        outlineOnly.setToolTipText(tr("This option suppresses the filling of areas, overriding anything specified in the selected style."));
143        outlineOnly.setSelected(Config.getPref().getBoolean("draw.data.area_outline_only", false));
144
145        // hideLabelsWhileDragging
146        hideLabelsWhileDragging.setToolTipText(tr("This option hides the textual labels of OSM objects while dragging the map."));
147        hideLabelsWhileDragging.setSelected(OsmDataLayer.PROPERTY_HIDE_LABELS_WHILE_DRAGGING.get());
148
149        // discardable keys
150        discardableKeys.setToolTipText(tr("Display keys which have been deemed uninteresting to the point that they can be silently removed."));
151        discardableKeys.setSelected(Config.getPref().getBoolean("display.discardable-keys", false));
152
153        // auto filters
154        autoFilters.setToolTipText(tr("Display buttons to automatically filter numeric values of a predefined tag"));
155        autoFilters.setSelected(AutoFilterManager.PROP_AUTO_FILTER_ENABLED.get());
156        autoFilters.addActionListener(e -> {
157            lblRule.setEnabled(autoFilters.isSelected());
158            autoFilterRules.setEnabled(autoFilters.isSelected());
159        });
160        autoFilterRules.setToolTipText("Rule defining which tag will provide automatic filters, below a certain zoom level");
161        autoFilterRules.setSelectedItem(AutoFilterManager.getInstance().getAutoFilterRule(AutoFilterManager.PROP_AUTO_FILTER_RULE.get()));
162
163        JLabel performanceLabel = new JLabel(tr("Options that affect drawing performance"));
164
165        panel.add(new JLabel(tr("Segment drawing options")),
166                GBC.eop().insets(5, 10, 0, 0));
167        panel.add(directionHint, GBC.eop().insets(20, 0, 0, 0));
168        panel.add(headArrow, GBC.eop().insets(40, 0, 0, 0));
169        panel.add(onewayArrow, GBC.eop().insets(20, 0, 0, 0));
170        panel.add(segmentOrderNumber, GBC.eop().insets(20, 0, 0, 0));
171        panel.add(segmentOrderNumberOnSelectedWay, GBC.eop().insets(20, 0, 0, 0));
172
173        panel.add(new JLabel(tr("Select and draw mode options")),
174                GBC.eop().insets(5, 10, 0, 0));
175        panel.add(virtualNodes, GBC.eop().insets(20, 0, 0, 0));
176        panel.add(drawHelperLine, GBC.eop().insets(20, 0, 0, 0));
177
178        panel.add(performanceLabel, GBC.eop().insets(5, 10, 0, 0));
179        panel.add(useAntialiasing, GBC.eop().insets(20, 0, 0, 0));
180        panel.add(useWireframeAntialiasing, GBC.eop().insets(20, 0, 0, 0));
181        panel.add(useHighlighting, GBC.eop().insets(20, 0, 0, 0));
182        panel.add(outlineOnly, GBC.eol().insets(20, 0, 0, 0));
183        panel.add(hideLabelsWhileDragging, GBC.eol().insets(20, 0, 0, 0));
184
185        panel.add(new JLabel(tr("Other options")),
186                GBC.eop().insets(5, 10, 0, 0));
187        panel.add(sourceBounds, GBC.eop().insets(20, 0, 0, 0));
188        panel.add(inactive, GBC.eop().insets(20, 0, 0, 0));
189        panel.add(discardableKeys, GBC.eop().insets(20, 0, 0, 0));
190        panel.add(autoFilters, GBC.eop().insets(20, 0, 0, 0));
191        panel.add(lblRule, GBC.std().insets(40, 0, 0, 0));
192        panel.add(autoFilterRules, GBC.eop().fill(GBC.HORIZONTAL).insets(5, 0, 0, 0));
193
194        ExpertToggleAction.addVisibilitySwitcher(performanceLabel);
195        ExpertToggleAction.addVisibilitySwitcher(useAntialiasing);
196        ExpertToggleAction.addVisibilitySwitcher(useWireframeAntialiasing);
197        ExpertToggleAction.addVisibilitySwitcher(useHighlighting);
198        ExpertToggleAction.addVisibilitySwitcher(outlineOnly);
199        ExpertToggleAction.addVisibilitySwitcher(hideLabelsWhileDragging);
200        ExpertToggleAction.addVisibilitySwitcher(discardableKeys);
201
202        panel.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
203        scrollpane = new JScrollPane(panel);
204        scrollpane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
205        GuiHelper.setDefaultIncrement(scrollpane);
206        gui.getDisplayPreference().addSubTab(this, tr("OSM Data"), scrollpane);
207    }
208
209    @Override
210    public boolean ok() {
211        boolean restart = gpxPanel.savePreferences();
212        OsmDataLayer.PROPERTY_HIDE_LABELS_WHILE_DRAGGING.put(hideLabelsWhileDragging.isSelected());
213        Config.getPref().putBoolean("draw.data.area_outline_only", outlineOnly.isSelected());
214        Config.getPref().putBoolean("draw.segment.direction", directionHint.isSelected());
215        Config.getPref().putBoolean("draw.segment.head_only", headArrow.isSelected());
216        Config.getPref().putBoolean("draw.oneway", onewayArrow.isSelected());
217        Config.getPref().putBoolean("draw.segment.order_number", segmentOrderNumber.isSelected());
218        Config.getPref().putBoolean("draw.segment.order_number.on_selected", segmentOrderNumberOnSelectedWay.isSelected());
219        SOURCE_BOUNDS_PROP.put(sourceBounds.isSelected());
220        Config.getPref().putBoolean("draw.data.inactive_color", inactive.isSelected());
221        Config.getPref().putBoolean("mappaint.use-antialiasing", useAntialiasing.isSelected());
222        Config.getPref().putBoolean("mappaint.wireframe.use-antialiasing", useWireframeAntialiasing.isSelected());
223        Config.getPref().putBoolean("draw.target-highlight", useHighlighting.isSelected());
224        Config.getPref().putBoolean("draw.helper-line", drawHelperLine.isSelected());
225        Config.getPref().putBoolean("display.discardable-keys", discardableKeys.isSelected());
226        AutoFilterManager.PROP_AUTO_FILTER_ENABLED.put(autoFilters.isSelected());
227        AutoFilterManager.PROP_AUTO_FILTER_RULE.put(((AutoFilterRule) autoFilterRules.getSelectedItem()).getKey());
228        int vn = Config.getPref().getInt("mappaint.node.virtual-size", 8);
229        if (virtualNodes.isSelected()) {
230            if (vn < 1) {
231                vn = 8;
232            }
233        } else {
234            vn = 0;
235        }
236        Config.getPref().putInt("mappaint.node.virtual-size", vn);
237        return restart;
238    }
239
240    @Override
241    public boolean isExpert() {
242        return false;
243    }
244
245    @Override
246    public TabPreferenceSetting getTabPreferenceSetting(final PreferenceTabbedPane gui) {
247        return gui.getDisplayPreference();
248    }
249}