source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java@ 10144

Last change on this file since 10144 was 10144, checked in by Don-vip, 8 years ago

code refactoring - strip actions from LayerListDialog to new package gui.dialogs.layer

  • Property svn:eol-style set to native
File size: 13.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs.layer;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.GridBagLayout;
8import java.awt.event.ActionEvent;
9import java.util.ArrayList;
10import java.util.Collection;
11import java.util.List;
12
13import javax.swing.AbstractAction;
14import javax.swing.BorderFactory;
15import javax.swing.ImageIcon;
16import javax.swing.JCheckBox;
17import javax.swing.JLabel;
18import javax.swing.JMenuItem;
19import javax.swing.JPanel;
20import javax.swing.JPopupMenu;
21import javax.swing.JSlider;
22import javax.swing.event.ChangeEvent;
23import javax.swing.event.ChangeListener;
24
25import org.openstreetmap.josm.Main;
26import org.openstreetmap.josm.gui.SideButton;
27import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerListModel;
28import org.openstreetmap.josm.gui.layer.ImageryLayer;
29import org.openstreetmap.josm.gui.layer.Layer;
30import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
31import org.openstreetmap.josm.tools.GBC;
32import org.openstreetmap.josm.tools.ImageProvider;
33import org.openstreetmap.josm.tools.Utils;
34
35/**
36 * This is a menu that includes all settings for the layer visibility. It combines gamma/opacity sliders and the visible-checkbox.
37 *
38 * @author Michael Zangl
39 */
40public final class LayerVisibilityAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
41 protected static final int SLIDER_STEPS = 100;
42 private static final double MAX_GAMMA_FACTOR = 2;
43 private static final double MAX_SHARPNESS_FACTOR = 2;
44 private static final double MAX_COLORFUL_FACTOR = 2;
45 private final LayerListModel model;
46 private final JPopupMenu popup;
47 private SideButton sideButton;
48 private JCheckBox visibilityCheckbox;
49 final OpacitySlider opacitySlider = new OpacitySlider();
50 private final ArrayList<FilterSlider<?>> sliders = new ArrayList<>();
51
52 /**
53 * Creates a new {@link LayerVisibilityAction}
54 * @param model The list to get the selection from.
55 */
56 public LayerVisibilityAction(LayerListModel model) {
57 this.model = model;
58 popup = new JPopupMenu();
59
60 // just to add a border
61 JPanel content = new JPanel();
62 popup.add(content);
63 content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
64 content.setLayout(new GridBagLayout());
65
66 putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "visibility"));
67 putValue(SHORT_DESCRIPTION, tr("Change visibility of the selected layer."));
68
69 visibilityCheckbox = new JCheckBox(tr("Show layer"));
70 visibilityCheckbox.addChangeListener(new ChangeListener() {
71 @Override
72 public void stateChanged(ChangeEvent e) {
73 setVisibleFlag(visibilityCheckbox.isSelected());
74 }
75 });
76 content.add(visibilityCheckbox, GBC.eop());
77
78 addSlider(content, opacitySlider);
79 addSlider(content, new ColorfulnessSlider());
80 addSlider(content, new GammaFilterSlider());
81 addSlider(content, new SharpnessSlider());
82 }
83
84 private void addSlider(JPanel content, FilterSlider<?> slider) {
85 content.add(new JLabel(slider.getIcon()), GBC.std().span(1, 2).insets(0, 0, 5, 0));
86 content.add(new JLabel(slider.getLabel()), GBC.eol());
87 content.add(slider, GBC.eop());
88 sliders.add(slider);
89 }
90
91 protected void setVisibleFlag(boolean visible) {
92 for (Layer l : model.getSelectedLayers()) {
93 l.setVisible(visible);
94 }
95 updateValues();
96 }
97
98 @Override
99 public void actionPerformed(ActionEvent e) {
100 updateValues();
101 if (e.getSource() == sideButton) {
102 popup.show(sideButton, 0, sideButton.getHeight());
103 } else {
104 // Action can be trigger either by opacity button or by popup menu (in case toggle buttons are hidden).
105 // In that case, show it in the middle of screen (because opacityButton is not visible)
106 popup.show(Main.parent, Main.parent.getWidth() / 2, (Main.parent.getHeight() - popup.getHeight()) / 2);
107 }
108 }
109
110 protected void updateValues() {
111 List<Layer> layers = model.getSelectedLayers();
112
113 visibilityCheckbox.setEnabled(!layers.isEmpty());
114 boolean allVisible = true;
115 boolean allHidden = true;
116 for (Layer l : layers) {
117 allVisible &= l.isVisible();
118 allHidden &= !l.isVisible();
119 }
120 // TODO: Indicate tristate.
121 visibilityCheckbox.setSelected(allVisible && !allHidden);
122
123 for (FilterSlider<?> slider : sliders) {
124 slider.updateSlider(layers, allHidden);
125 }
126 }
127
128 @Override
129 public boolean supportLayers(List<Layer> layers) {
130 return !layers.isEmpty();
131 }
132
133 @Override
134 public Component createMenuComponent() {
135 return new JMenuItem(this);
136 }
137
138 @Override
139 public void updateEnabledState() {
140 setEnabled(!model.getSelectedLayers().isEmpty());
141 }
142
143 /**
144 * Sets the corresponding side button.
145 * @param sideButton the corresponding side button
146 */
147 public void setCorrespondingSideButton(SideButton sideButton) {
148 this.sideButton = sideButton;
149 }
150
151 /**
152 * This is a slider for a filter value.
153 * @author Michael Zangl
154 *
155 * @param <T> The layer type.
156 */
157 private abstract class FilterSlider<T extends Layer> extends JSlider {
158 private final double minValue;
159 private final double maxValue;
160 private final Class<T> layerClassFilter;
161
162 /**
163 * Create a new filter slider.
164 * @param minValue The minimum value to map to the left side.
165 * @param maxValue The maximum value to map to the right side.
166 * @param layerClassFilter The type of layer influenced by this filter.
167 */
168 FilterSlider(double minValue, double maxValue, Class<T> layerClassFilter) {
169 super(JSlider.HORIZONTAL);
170 this.minValue = minValue;
171 this.maxValue = maxValue;
172 this.layerClassFilter = layerClassFilter;
173 setMaximum(SLIDER_STEPS);
174 int tick = convertFromRealValue(1);
175 setMinorTickSpacing(tick);
176 setMajorTickSpacing(tick);
177 setPaintTicks(true);
178
179 addChangeListener(new ChangeListener() {
180 @Override
181 public void stateChanged(ChangeEvent e) {
182 onStateChanged();
183 }
184 });
185 }
186
187 /**
188 * Called whenever the state of the slider was changed.
189 * @see #getValueIsAdjusting()
190 * @see #getRealValue()
191 */
192 protected void onStateChanged() {
193 Collection<T> layers = filterLayers(model.getSelectedLayers());
194 for (T layer : layers) {
195 applyValueToLayer(layer);
196 }
197 }
198
199 protected void applyValueToLayer(T layer) {
200 }
201
202 protected double getRealValue() {
203 return convertToRealValue(getValue());
204 }
205
206 protected double convertToRealValue(int value) {
207 double s = (double) value / SLIDER_STEPS;
208 return s * maxValue + (1-s) * minValue;
209 }
210
211 protected void setRealValue(double value) {
212 setValue(convertFromRealValue(value));
213 }
214
215 protected int convertFromRealValue(double value) {
216 int i = (int) ((value - minValue) / (maxValue - minValue) * SLIDER_STEPS + .5);
217 if (i < getMinimum()) {
218 return getMinimum();
219 } else if (i > getMaximum()) {
220 return getMaximum();
221 } else {
222 return i;
223 }
224 }
225
226 public abstract ImageIcon getIcon();
227
228 public abstract String getLabel();
229
230 public void updateSlider(List<Layer> layers, boolean allHidden) {
231 Collection<? extends Layer> usedLayers = filterLayers(layers);
232 if (usedLayers.isEmpty() || allHidden) {
233 setEnabled(false);
234 } else {
235 setEnabled(true);
236 updateSliderWhileEnabled(usedLayers, allHidden);
237 }
238 }
239
240 protected Collection<T> filterLayers(List<Layer> layers) {
241 return Utils.filteredCollection(layers, layerClassFilter);
242 }
243
244 protected abstract void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden);
245 }
246
247 /**
248 * This slider allows you to change the opacity of a layer.
249 *
250 * @author Michael Zangl
251 * @see Layer#setOpacity(double)
252 */
253 class OpacitySlider extends FilterSlider<Layer> {
254 /**
255 * Creaate a new {@link OpacitySlider}.
256 */
257 OpacitySlider() {
258 super(0, 1, Layer.class);
259 setToolTipText(tr("Adjust opacity of the layer."));
260 }
261
262 @Override
263 protected void onStateChanged() {
264 if (getRealValue() <= 0.001 && !getValueIsAdjusting()) {
265 setVisibleFlag(false);
266 } else {
267 super.onStateChanged();
268 }
269 }
270
271 @Override
272 protected void applyValueToLayer(Layer layer) {
273 layer.setOpacity(getRealValue());
274 }
275
276 @Override
277 protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) {
278 double opacity = 0;
279 for (Layer l : usedLayers) {
280 opacity += l.getOpacity();
281 }
282 opacity /= usedLayers.size();
283 if (opacity == 0) {
284 opacity = 1;
285 setVisibleFlag(true);
286 }
287 setRealValue(opacity);
288 }
289
290 @Override
291 public String getLabel() {
292 return tr("Opacity");
293 }
294
295 @Override
296 public ImageIcon getIcon() {
297 return ImageProvider.get("dialogs/layerlist", "transparency");
298 }
299
300 @Override
301 public String toString() {
302 return "OpacitySlider [getRealValue()=" + getRealValue() + "]";
303 }
304 }
305
306 /**
307 * This slider allows you to change the gamma value of a layer.
308 *
309 * @author Michael Zangl
310 * @see ImageryLayer#setGamma(double)
311 */
312 private class GammaFilterSlider extends FilterSlider<ImageryLayer> {
313
314 /**
315 * Create a new {@link GammaFilterSlider}
316 */
317 GammaFilterSlider() {
318 super(0, MAX_GAMMA_FACTOR, ImageryLayer.class);
319 setToolTipText(tr("Adjust gamma value of the layer."));
320 }
321
322 @Override
323 protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) {
324 double gamma = ((ImageryLayer) usedLayers.iterator().next()).getGamma();
325 setRealValue(gamma);
326 }
327
328 @Override
329 protected void applyValueToLayer(ImageryLayer layer) {
330 layer.setGamma(getRealValue());
331 }
332
333 @Override
334 public ImageIcon getIcon() {
335 return ImageProvider.get("dialogs/layerlist", "gamma");
336 }
337
338 @Override
339 public String getLabel() {
340 return tr("Gamma");
341 }
342 }
343
344 /**
345 * This slider allows you to change the sharpness of a layer.
346 *
347 * @author Michael Zangl
348 * @see ImageryLayer#setSharpenLevel(double)
349 */
350 private class SharpnessSlider extends FilterSlider<ImageryLayer> {
351
352 /**
353 * Creates a new {@link SharpnessSlider}
354 */
355 SharpnessSlider() {
356 super(0, MAX_SHARPNESS_FACTOR, ImageryLayer.class);
357 setToolTipText(tr("Adjust sharpness/blur value of the layer."));
358 }
359
360 @Override
361 protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) {
362 setRealValue(((ImageryLayer) usedLayers.iterator().next()).getSharpenLevel());
363 }
364
365 @Override
366 protected void applyValueToLayer(ImageryLayer layer) {
367 layer.setSharpenLevel(getRealValue());
368 }
369
370 @Override
371 public ImageIcon getIcon() {
372 return ImageProvider.get("dialogs/layerlist", "sharpness");
373 }
374
375 @Override
376 public String getLabel() {
377 return tr("Sharpness");
378 }
379 }
380
381 /**
382 * This slider allows you to change the colorfulness of a layer.
383 *
384 * @author Michael Zangl
385 * @see ImageryLayer#setColorfulness(double)
386 */
387 private class ColorfulnessSlider extends FilterSlider<ImageryLayer> {
388
389 /**
390 * Create a new {@link ColorfulnessSlider}
391 */
392 ColorfulnessSlider() {
393 super(0, MAX_COLORFUL_FACTOR, ImageryLayer.class);
394 setToolTipText(tr("Adjust colorfulness of the layer."));
395 }
396
397 @Override
398 protected void updateSliderWhileEnabled(Collection<? extends Layer> usedLayers, boolean allHidden) {
399 setRealValue(((ImageryLayer) usedLayers.iterator().next()).getColorfulness());
400 }
401
402 @Override
403 protected void applyValueToLayer(ImageryLayer layer) {
404 layer.setColorfulness(getRealValue());
405 }
406
407 @Override
408 public ImageIcon getIcon() {
409 return ImageProvider.get("dialogs/layerlist", "colorfulness");
410 }
411
412 @Override
413 public String getLabel() {
414 return tr("Colorfulness");
415 }
416 }
417}
Note: See TracBrowser for help on using the repository browser.