Ticket #12642: patch-layer-filter-settings.patch
File patch-layer-filter-settings.patch, 19.1 KB (added by , 8 years ago) |
---|
-
src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
diff --git a/images/dialogs/layerlist/visibility.png b/images/dialogs/layerlist/visibility.png new file mode 100644 index 0000000..dd019e8 Binary files /dev/null and b/images/dialogs/layerlist/visibility.png differ diff --git a/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java b/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java index af5f61c..793abfb 100644
a b import java.awt.Color; 7 7 import java.awt.Component; 8 8 import java.awt.Dimension; 9 9 import java.awt.Font; 10 import java.awt.GridBagLayout; 10 11 import java.awt.Point; 11 12 import java.awt.Rectangle; 12 13 import java.awt.event.ActionEvent; … … import java.beans.PropertyChangeListener; 18 19 import java.lang.ref.WeakReference; 19 20 import java.util.ArrayList; 20 21 import java.util.Arrays; 22 import java.util.Collection; 21 23 import java.util.Collections; 22 24 import java.util.List; 23 25 import java.util.concurrent.CopyOnWriteArrayList; 24 26 25 27 import javax.swing.AbstractAction; 28 import javax.swing.BorderFactory; 26 29 import javax.swing.DefaultCellEditor; 27 30 import javax.swing.DefaultListSelectionModel; 28 31 import javax.swing.ImageIcon; … … import javax.swing.JCheckBox; 30 33 import javax.swing.JComponent; 31 34 import javax.swing.JLabel; 32 35 import javax.swing.JMenuItem; 36 import javax.swing.JPanel; 33 37 import javax.swing.JPopupMenu; 34 38 import javax.swing.JSlider; 35 39 import javax.swing.JTable; … … import org.openstreetmap.josm.gui.widgets.DisableShortcutsOnFocusGainedTextField 66 70 import org.openstreetmap.josm.gui.widgets.JosmTextField; 67 71 import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher; 68 72 import org.openstreetmap.josm.tools.CheckParameterUtil; 73 import org.openstreetmap.josm.tools.GBC; 69 74 import org.openstreetmap.josm.tools.ImageProvider; 70 75 import org.openstreetmap.josm.tools.InputMapUtils; 71 76 import org.openstreetmap.josm.tools.MultikeyActionsHandler; … … public class LayerListDialog extends ToggleDialog { 263 268 MultikeyActionsHandler.getInstance().addAction(showHideLayerAction); 264 269 adaptTo(showHideLayerAction, selectionModel); 265 270 266 // -- layer opacity action 267 LayerOpacityAction layerOpacityAction = new LayerOpacityAction(model); 268 adaptTo(layerOpacityAction, selectionModel); 269 SideButton opacityButton = new SideButton(layerOpacityAction, false); 270 layerOpacityAction.setCorrespondingSideButton(opacityButton); 271 272 // -- layer gamma action 273 LayerGammaAction layerGammaAction = new LayerGammaAction(model); 274 adaptTo(layerGammaAction, selectionModel); 275 SideButton gammaButton = new SideButton(layerGammaAction, false); 276 layerGammaAction.setCorrespondingSideButton(gammaButton); 271 LayerVisibilityAction visibilityAction = new LayerVisibilityAction(model); 272 adaptTo(visibilityAction, selectionModel); 273 SideButton visibilityButton = new SideButton(visibilityAction, false); 274 visibilityAction.setCorrespondingSideButton(visibilityButton); 277 275 278 276 // -- delete layer action 279 277 DeleteLayerAction deleteLayerAction = new DeleteLayerAction(); … … public class LayerListDialog extends ToggleDialog { 300 298 new SideButton(moveUpAction, false), 301 299 new SideButton(moveDownAction, false), 302 300 new SideButton(activateLayerAction, false), 303 new SideButton(showHideLayerAction, false), 304 opacityButton, 305 gammaButton, 301 visibilityButton, 306 302 new SideButton(deleteLayerAction, false) 307 303 )); 308 304 … … public class LayerListDialog extends ToggleDialog { 605 601 } 606 602 607 603 /** 608 * Creates a {@link ShowHideLayerAction} which will toggle the visibility of the currently selectedlayers604 * Creates a {@link LayerOpacityAction} which will toggle the visibility of layers 609 605 * @param model layer list model 610 606 */ 611 p ublicLayerOpacityAction(LayerListModel model) {607 private LayerOpacityAction(LayerListModel model) { 612 608 super(model, tr("Opacity"), 100); 613 609 putValue(SHORT_DESCRIPTION, tr("Adjust opacity of the layer.")); 614 610 putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "transparency")); … … public class LayerListDialog extends ToggleDialog { 616 612 617 613 @Override 618 614 protected void setValue(double value) { 619 if (!isEnabled()) return; 620 if (layer != null) { 621 layer.setOpacity(value); 622 } else { 623 for (Layer l : model.getSelectedLayers()) { 624 l.setOpacity(value); 625 } 626 } 615 layer.setOpacity(value); 627 616 } 628 617 629 618 @Override 630 619 protected double getValue() { 631 if (layer != null) 632 return layer.getOpacity(); 633 else { 634 double opacity = 0; 635 List<Layer> layers = model.getSelectedLayers(); 636 for (Layer l : layers) { 637 opacity += l.getOpacity(); 638 } 639 return opacity / layers.size(); 640 } 620 return layer.getOpacity(); 641 621 } 642 622 643 623 @Override 644 624 public void updateEnabledState() { 645 if (layer == null) { 646 setEnabled(!model.getSelectedLayers().isEmpty()); 647 } else { 648 setEnabled(true); 649 } 625 setEnabled(true); 650 626 } 651 627 652 628 @Override … … public class LayerListDialog extends ToggleDialog { 656 632 } 657 633 658 634 /** 659 * Action which allows to change the gamma of one imagery layer. 635 * This is a menu that includes all settings for the layer visibility. It combines gamma/opacity sliders and the visible-checkbox. 636 * 637 * @author Michael Zangl 660 638 */ 661 public static final class LayerGammaAction extends AbstractLayerPropertySliderAction { 639 public static final class LayerVisibilityAction extends AbstractAction implements IEnabledStateUpdating, LayerAction { 640 protected static final int SLIDER_STEPS = 100; 641 private static final double MAX_GAMMA_FACTOR = 2; 642 private final LayerListModel model; 643 private final JPopupMenu popup; 644 private JSlider opacitySlider; 645 private JSlider gammaSlider; 646 private SideButton sideButton; 647 private JCheckBox visibilityCheckbox; 662 648 663 649 /** 664 * C onstructs a new {@code LayerGammaAction}.665 * @param model layer list model650 * Creates a new {@link LayerVisibilityAction} 651 * @param model The list to get the selection from. 666 652 */ 667 public LayerGammaAction(LayerListModel model) { 668 super(model, tr("Gamma"), 50); 669 putValue(SHORT_DESCRIPTION, tr("Adjust gamma value of the layer.")); 670 putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "gamma")); 653 public LayerVisibilityAction(LayerListModel model) { 654 this.model = model; 655 popup = new JPopupMenu(); 656 657 // just to add a border 658 JPanel content = new JPanel(); 659 popup.add(content); 660 content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 661 content.setLayout(new GridBagLayout()); 662 663 putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "visibility")); 664 putValue(SHORT_DESCRIPTION, tr("Change visibility of the selected layer.")); 665 666 visibilityCheckbox = new JCheckBox(tr("Show layer")); 667 visibilityCheckbox.addChangeListener(new ChangeListener() { 668 @Override 669 public void stateChanged(ChangeEvent e) { 670 setVisible(visibilityCheckbox.isSelected()); 671 } 672 }); 673 content.add(visibilityCheckbox, GBC.eop()); 674 675 content.add(new JLabel(ImageProvider.get("dialogs/layerlist", "transparency")), GBC.std().span(1, 2).insets(0, 0, 5, 0)); 676 content.add(new JLabel(tr("Opacity")), GBC.eol()); 677 opacitySlider = new JSlider(JSlider.HORIZONTAL); 678 opacitySlider.setMaximum(SLIDER_STEPS); 679 opacitySlider.addChangeListener(new ChangeListener() { 680 @Override 681 public void stateChanged(ChangeEvent e) { 682 setOpacityValue(readOpacityValue(), opacitySlider.getValueIsAdjusting()); 683 } 684 }); 685 opacitySlider.setToolTipText(tr("Adjust opacity of the layer.")); 686 content.add(opacitySlider, GBC.eop()); 687 688 content.add(new JLabel(ImageProvider.get("dialogs/layerlist", "gamma")), GBC.std().span(1, 2).insets(0, 0, 5, 0)); 689 content.add(new JLabel(tr("Gamma")), GBC.eol()); 690 gammaSlider = new JSlider(JSlider.HORIZONTAL); 691 gammaSlider.setMaximum(SLIDER_STEPS); 692 gammaSlider.addChangeListener(new ChangeListener() { 693 @Override 694 public void stateChanged(ChangeEvent e) { 695 setGammaValue(readGammaValue()); 696 } 697 }); 698 gammaSlider.setToolTipText(tr("Adjust gamma value of the layer.")); 699 content.add(gammaSlider, GBC.eol()); 671 700 } 672 701 673 @Override 674 protected void setValue(double value) { 702 protected double readOpacityValue() { 703 return (double) opacitySlider.getValue() / SLIDER_STEPS; 704 } 705 706 protected double readGammaValue() { 707 return (double) gammaSlider.getValue() / SLIDER_STEPS * MAX_GAMMA_FACTOR; 708 } 709 710 protected void setVisible(boolean visible) { 711 for (Layer l : model.getSelectedLayers()) { 712 l.setVisible(visible); 713 } 714 updateValues(); 715 } 716 717 protected void setOpacityValue(double value, boolean adjusting) { 718 if (value <= 0 && !adjusting) { 719 setVisible(false); 720 } else { 721 for (Layer l : model.getSelectedLayers()) { 722 l.setOpacity(value); 723 } 724 } 725 } 726 727 protected void setGammaValue(double value) { 675 728 for (ImageryLayer imageryLayer : Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class)) { 676 729 imageryLayer.setGamma(value); 677 730 } 678 731 } 679 732 680 733 @Override 681 protected double getValue() { 682 return Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).iterator().next().getGamma(); 734 public void actionPerformed(ActionEvent e) { 735 updateValues(); 736 if (e.getSource() == sideButton) { 737 popup.show(sideButton, 0, sideButton.getHeight()); 738 } else { 739 // Action can be trigger either by opacity button or by popup menu (in case toggle buttons are hidden). 740 // In that case, show it in the middle of screen (because opacityButton is not visible) 741 popup.show(Main.parent, Main.parent.getWidth() / 2, (Main.parent.getHeight() - popup.getHeight()) / 2); 742 } 683 743 } 684 744 685 @Override 686 public void updateEnabledState() { 687 setEnabled(!Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).isEmpty()); 745 protected void updateValues() { 746 List<Layer> layers = model.getSelectedLayers(); 747 748 visibilityCheckbox.setEnabled(!layers.isEmpty()); 749 boolean allVisible = true; 750 boolean allHidden = true; 751 for (Layer l : layers) { 752 allVisible &= l.isVisible(); 753 allHidden &= !l.isVisible(); 754 } 755 // TODO: Indicate tristate. 756 visibilityCheckbox.setSelected(allVisible && !allHidden); 757 758 updateOpacitySlider(layers, allHidden); 759 760 updateGammaSlider(layers, allHidden); 761 } 762 763 private void updateGammaSlider(List<Layer> layers, boolean allHidden) { 764 Collection<ImageryLayer> gammaLayers = Utils.filteredCollection(layers, ImageryLayer.class); 765 if (gammaLayers.isEmpty() || allHidden) { 766 gammaSlider.setEnabled(false); 767 } else { 768 gammaSlider.setEnabled(true); 769 double gamma = gammaLayers.iterator().next().getGamma(); 770 gammaSlider.setValue((int) (gamma * SLIDER_STEPS / MAX_GAMMA_FACTOR)); 771 } 772 } 773 774 private void updateOpacitySlider(List<Layer> layers, boolean allHidden) { 775 if (layers.isEmpty() || allHidden) { 776 opacitySlider.setEnabled(false); 777 } else { 778 opacitySlider.setEnabled(true); 779 double opacity = 0; 780 for (Layer l : layers) { 781 opacity += l.getOpacity(); 782 } 783 opacity /= layers.size(); 784 if (opacity == 0) { 785 opacity = 1; 786 setOpacityValue(opacity, false); 787 } 788 opacitySlider.setValue((int) (opacity * SLIDER_STEPS)); 789 } 688 790 } 689 791 690 792 @Override 691 793 public boolean supportLayers(List<Layer> layers) { 692 return !Utils.filteredCollection(layers, ImageryLayer.class).isEmpty(); 794 return !layers.isEmpty(); 795 } 796 797 @Override 798 public Component createMenuComponent() { 799 return new JMenuItem(this); 800 } 801 802 @Override 803 public void updateEnabledState() { 804 setEnabled(!model.getSelectedLayers().isEmpty()); 805 } 806 807 /** 808 * Sets the corresponding side button. 809 * @param sideButton the corresponding side button 810 */ 811 void setCorrespondingSideButton(SideButton sideButton) { 812 this.sideButton = sideButton; 693 813 } 694 814 } 695 815 -
src/org/openstreetmap/josm/gui/layer/Layer.java
diff --git a/src/org/openstreetmap/josm/gui/layer/Layer.java b/src/org/openstreetmap/josm/gui/layer/Layer.java index 26842aa..d8fdd5c 100644
a b public abstract class Layer implements Destroyable, MapViewPaintable, Projection 360 360 return visible && opacity != 0; 361 361 } 362 362 363 /** 364 * Gets the opacity of the layer, in range 0...1 365 * @return The opacity 366 */ 363 367 public double getOpacity() { 364 368 return opacity; 365 369 } 366 370 371 /** 372 * Sets the opacity of the layer, in range 0...1 373 * @param opacity The opacity 374 * @throws IllegalArgumentException if the opacity is out of range 375 */ 367 376 public void setOpacity(double opacity) { 368 377 if (!(opacity >= 0 && opacity <= 1)) 369 378 throw new IllegalArgumentException("Opacity value must be between 0 and 1"); -
test/unit/org/openstreetmap/josm/gui/dialogs/LayerListDialogTest.java
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/LayerListDialogTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/LayerListDialogTest.java index 74100c7..33b7e6f 100644
a b 2 2 package org.openstreetmap.josm.gui.dialogs; 3 3 4 4 import static org.junit.Assert.assertEquals; 5 import static org.junit.Assert.assertFalse; 5 6 import static org.junit.Assert.assertTrue; 6 7 7 8 import org.junit.BeforeClass; 8 9 import org.junit.Test; 9 10 import org.openstreetmap.josm.JOSMFixture; 10 11 import org.openstreetmap.josm.Main; 11 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerGammaAction;12 12 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerListModel; 13 13 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerOpacityAction; 14 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerVisibilityAction; 14 15 import org.openstreetmap.josm.gui.layer.TMSLayer; 15 16 import org.openstreetmap.josm.gui.layer.TMSLayerTest; 16 17 … … public class LayerListDialogTest { 28 29 } 29 30 30 31 /** 31 * Unit test of {@link Layer GammaAction} class.32 * Unit test of {@link LayerVisibilityAction} class. 32 33 */ 33 34 @Test 34 public void testLayer GammaAction() {35 public void testLayerVisibilityAction() { 35 36 TMSLayer layer = TMSLayerTest.createTmsLayer(); 36 37 try { 37 Main.map.mapView.addLayer(layer);38 38 LayerListModel model = LayerListDialog.getInstance().getModel(); 39 LayerGammaAction action = new LayerGammaAction(model); 39 LayerVisibilityAction action = new LayerVisibilityAction(model); 40 action.updateEnabledState(); 41 assertFalse(action.isEnabled()); 42 43 Main.map.mapView.addLayer(layer); 40 44 action.updateEnabledState(); 41 45 assertTrue(action.isEnabled()); 42 46 assertTrue(action.supportLayers(model.getSelectedLayers())); 43 assertEquals(1.0, action.getValue(), 1e-15); 44 action.setValue(0.5); 45 assertEquals(0.5, action.getValue(), 1e-15); 47 48 // now check values 49 action.updateValues(); 50 assertEquals(1.0, action.readOpacityValue(), 1e-15); 51 assertEquals(1.0, action.readGammaValue(), 1e-15); 52 53 action.setOpacityValue(.5, false); 54 action.setGammaValue(1.5); 55 action.updateValues(); 56 57 assertEquals(0.5, action.readOpacityValue(), 1e-15); 58 assertEquals(1.5, action.readGammaValue(), 1e-15); 59 60 action.setVisible(false); 61 action.updateValues(); 62 assertFalse(layer.isVisible()); 63 64 action.setVisible(true); 65 action.updateValues(); 66 assertTrue(layer.isVisible()); 67 68 // layer stays visible during adjust 69 action.setOpacityValue(0, true); 70 assertEquals(0, layer.getOpacity(), 1e-15); 71 layer.setOpacity(.1); // to make layer.isVisible work 72 assertTrue(layer.isVisible()); 73 layer.setOpacity(0); 74 75 action.setOpacityValue(0, false); 76 assertEquals(0, layer.getOpacity(), 1e-15); 77 layer.setOpacity(.1); // to make layer.isVisible work 78 assertFalse(layer.isVisible()); 79 layer.setOpacity(0); 80 action.updateValues(); 81 82 // Opacity reset when it was 0 and user set layer to visible. 83 action.setVisible(true); 84 action.updateValues(); 85 assertEquals(1.0, action.readOpacityValue(), 1e-15); 86 assertEquals(1.0, layer.getOpacity(), 1e-15); 87 46 88 } finally { 47 89 Main.map.mapView.removeLayer(layer); 48 90 } 49 91 } 50 92 51 93 /** 52 * Unit test of {@link LayerOpacityAction} class .94 * Unit test of {@link LayerOpacityAction} class for single layer. 53 95 */ 54 96 @Test 55 97 public void testLayerOpacityAction() { … … public class LayerListDialogTest { 57 99 try { 58 100 Main.map.mapView.addLayer(layer); 59 101 LayerListModel model = LayerListDialog.getInstance().getModel(); 60 LayerOpacityAction action = new LayerOpacityAction(model );102 LayerOpacityAction action = new LayerOpacityAction(model, layer); 61 103 action.updateEnabledState(); 62 104 assertTrue(action.isEnabled()); 63 105 assertTrue(action.supportLayers(model.getSelectedLayers()));