Ticket #12642: 12642_updated.patch

File 12642_updated.patch, 20.4 KB (added by Don-vip, 10 years ago)
  • src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java

    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: images\dialogs\layerlist\visibility.png
    ___________________________________________________________________
    Added: svn:mime-type
    ## -0,0 +1 ##
    +application/octet-stream
     
    77import java.awt.Component;
    88import java.awt.Dimension;
    99import java.awt.Font;
     10import java.awt.GridBagLayout;
    1011import java.awt.Point;
    1112import java.awt.Rectangle;
    1213import java.awt.event.ActionEvent;
     
    1819import java.lang.ref.WeakReference;
    1920import java.util.ArrayList;
    2021import java.util.Arrays;
     22import java.util.Collection;
    2123import java.util.Collections;
    2224import java.util.List;
    2325import java.util.concurrent.CopyOnWriteArrayList;
    2426
    2527import javax.swing.AbstractAction;
     28import javax.swing.BorderFactory;
    2629import javax.swing.DefaultCellEditor;
    2730import javax.swing.DefaultListSelectionModel;
    2831import javax.swing.ImageIcon;
     
    3033import javax.swing.JComponent;
    3134import javax.swing.JLabel;
    3235import javax.swing.JMenuItem;
     36import javax.swing.JPanel;
    3337import javax.swing.JPopupMenu;
    3438import javax.swing.JSlider;
    3539import javax.swing.JTable;
     
    6670import org.openstreetmap.josm.gui.widgets.JosmTextField;
    6771import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
    6872import org.openstreetmap.josm.tools.CheckParameterUtil;
     73import org.openstreetmap.josm.tools.GBC;
    6974import org.openstreetmap.josm.tools.ImageProvider;
    7075import org.openstreetmap.josm.tools.InputMapUtils;
    7176import org.openstreetmap.josm.tools.MultikeyActionsHandler;
     
    263268        MultikeyActionsHandler.getInstance().addAction(showHideLayerAction);
    264269        adaptTo(showHideLayerAction, selectionModel);
    265270
    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);
    277275
    278276        // -- delete layer action
    279277        DeleteLayerAction deleteLayerAction = new DeleteLayerAction();
     
    300298                new SideButton(moveUpAction, false),
    301299                new SideButton(moveDownAction, false),
    302300                new SideButton(activateLayerAction, false),
    303                 new SideButton(showHideLayerAction, false),
    304                 opacityButton,
    305                 gammaButton,
     301                visibilityButton,
    306302                new SideButton(deleteLayerAction, false)
    307303        ));
    308304
     
    528524    }
    529525
    530526    /**
    531      * Abstract action which allows to adjust a double value using a slider
     527     * This is a menu that includes all settings for the layer visibility. It combines gamma/opacity sliders and the visible-checkbox.
     528     *
     529     * @author Michael Zangl
    532530     */
    533     public abstract static class AbstractLayerPropertySliderAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
    534         protected final LayerListModel model;
    535         protected final JPopupMenu popup;
    536         protected final JSlider slider;
    537         private final double factor;
     531    public static final class LayerVisibilityAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
     532        protected static final int SLIDER_STEPS = 100;
     533        private static final double MAX_GAMMA_FACTOR = 2;
     534        private final LayerListModel model;
     535        private final JPopupMenu popup;
     536        private JSlider opacitySlider;
     537        private JSlider gammaSlider;
    538538        private SideButton sideButton;
     539        private JCheckBox visibilityCheckbox;
    539540
    540         protected AbstractLayerPropertySliderAction(LayerListModel model, String name, final double factor) {
    541             super(name);
     541        /**
     542         * Creates a new {@link LayerVisibilityAction}
     543         * @param model The list to get the selection from.
     544         */
     545        public LayerVisibilityAction(LayerListModel model) {
    542546            this.model = model;
    543             this.factor = factor;
    544             updateEnabledState();
    545 
    546547            popup = new JPopupMenu();
    547             slider = new JSlider(JSlider.VERTICAL);
    548             slider.addChangeListener(new ChangeListener() {
     548
     549            // just to add a border
     550            JPanel content = new JPanel();
     551            popup.add(content);
     552            content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
     553            content.setLayout(new GridBagLayout());
     554
     555            putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "visibility"));
     556            putValue(SHORT_DESCRIPTION, tr("Change visibility of the selected layer."));
     557
     558            visibilityCheckbox = new JCheckBox(tr("Show layer"));
     559            visibilityCheckbox.addChangeListener(new ChangeListener() {
    549560                @Override
    550561                public void stateChanged(ChangeEvent e) {
    551                     setValue(slider.getValue() / factor);
     562                    setVisible(visibilityCheckbox.isSelected());
    552563                }
    553564            });
    554             popup.add(slider);
     565            content.add(visibilityCheckbox, GBC.eop());
     566
     567            content.add(new JLabel(ImageProvider.get("dialogs/layerlist", "transparency")), GBC.std().span(1, 2).insets(0, 0, 5, 0));
     568            content.add(new JLabel(tr("Opacity")), GBC.eol());
     569            opacitySlider = new JSlider(JSlider.HORIZONTAL);
     570            opacitySlider.setMaximum(SLIDER_STEPS);
     571            opacitySlider.addChangeListener(new ChangeListener() {
     572                @Override
     573                public void stateChanged(ChangeEvent e) {
     574                    setOpacityValue(readOpacityValue(), opacitySlider.getValueIsAdjusting());
     575                }
     576            });
     577            opacitySlider.setToolTipText(tr("Adjust opacity of the layer."));
     578            content.add(opacitySlider, GBC.eop());
     579
     580            content.add(new JLabel(ImageProvider.get("dialogs/layerlist", "gamma")), GBC.std().span(1, 2).insets(0, 0, 5, 0));
     581            content.add(new JLabel(tr("Gamma")), GBC.eol());
     582            gammaSlider = new JSlider(JSlider.HORIZONTAL);
     583            gammaSlider.setMaximum(SLIDER_STEPS);
     584            gammaSlider.addChangeListener(new ChangeListener() {
     585                @Override
     586                public void stateChanged(ChangeEvent e) {
     587                    setGammaValue(readGammaValue());
     588                }
     589            });
     590            gammaSlider.setToolTipText(tr("Adjust gamma value of the layer."));
     591            content.add(gammaSlider, GBC.eol());
    555592        }
    556593
    557         protected abstract void setValue(double value);
     594        protected double readOpacityValue() {
     595            return (double) opacitySlider.getValue() / SLIDER_STEPS;
     596        }
    558597
    559         protected abstract double getValue();
     598        protected double readGammaValue() {
     599            return (double) gammaSlider.getValue() / SLIDER_STEPS * MAX_GAMMA_FACTOR;
     600        }
    560601
    561         /**
    562          * Sets the corresponding side button.
    563          * @param sideButton the corresponding side button
    564          */
    565         final void setCorrespondingSideButton(SideButton sideButton) {
    566             this.sideButton = sideButton;
     602        protected void setVisible(boolean visible) {
     603            for (Layer l : model.getSelectedLayers()) {
     604                l.setVisible(visible);
     605            }
     606            updateValues();
     607        }
     608
     609        protected void setOpacityValue(double value, boolean adjusting) {
     610            if (value <= 0 && !adjusting) {
     611                setVisible(false);
     612            } else {
     613                for (Layer l : model.getSelectedLayers()) {
     614                    l.setOpacity(value);
     615                }
     616            }
     617        }
     618
     619        protected void setGammaValue(double value) {
     620            for (ImageryLayer imageryLayer : Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class)) {
     621                imageryLayer.setGamma(value);
     622            }
    567623        }
    568624
    569625        @Override
    570626        public void actionPerformed(ActionEvent e) {
    571             slider.setValue((int) (getValue() * factor));
     627            updateValues();
    572628            if (e.getSource() == sideButton) {
    573629                popup.show(sideButton, 0, sideButton.getHeight());
    574630            } else {
     
    578634            }
    579635        }
    580636
    581         @Override
    582         public Component createMenuComponent() {
    583             return new JMenuItem(this);
    584         }
    585     }
     637        protected void updateValues() {
     638            List<Layer> layers = model.getSelectedLayers();
    586639
    587     /**
    588      * Action which allows to change the opacity of one or more layers.
    589      */
    590     public static final class LayerOpacityAction extends AbstractLayerPropertySliderAction {
    591         private transient Layer layer;
     640            visibilityCheckbox.setEnabled(!layers.isEmpty());
     641            boolean allVisible = true;
     642            boolean allHidden = true;
     643            for (Layer l : layers) {
     644                allVisible &= l.isVisible();
     645                allHidden &= !l.isVisible();
     646            }
     647            // TODO: Indicate tristate.
     648            visibilityCheckbox.setSelected(allVisible && !allHidden);
    592649
    593         /**
    594          * Creates a {@link LayerOpacityAction} which allows to change the opacity of one or more layers.
    595          *
    596          * @param model layer list model
    597          * @param layer  the layer. Must not be null.
    598          * @throws IllegalArgumentException if layer is null
    599          */
    600         public LayerOpacityAction(LayerListModel model, Layer layer) {
    601             this(model);
    602             CheckParameterUtil.ensureParameterNotNull(layer, "layer");
    603             this.layer = layer;
    604             updateEnabledState();
    605         }
     650            updateOpacitySlider(layers, allHidden);
    606651
    607         /**
    608          * Creates a {@link ShowHideLayerAction} which will toggle the visibility of the currently selected layers
    609          * @param model layer list model
    610          */
    611         public LayerOpacityAction(LayerListModel model) {
    612             super(model, tr("Opacity"), 100);
    613             putValue(SHORT_DESCRIPTION, tr("Adjust opacity of the layer."));
    614             putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "transparency"));
     652            updateGammaSlider(layers, allHidden);
    615653        }
    616654
    617         @Override
    618         protected void setValue(double value) {
    619             if (!isEnabled()) return;
    620             if (layer != null) {
    621                 layer.setOpacity(value);
     655        private void updateGammaSlider(List<Layer> layers, boolean allHidden) {
     656            Collection<ImageryLayer> gammaLayers = Utils.filteredCollection(layers, ImageryLayer.class);
     657            if (gammaLayers.isEmpty() || allHidden) {
     658                gammaSlider.setEnabled(false);
    622659            } else {
    623                 for (Layer l : model.getSelectedLayers()) {
    624                     l.setOpacity(value);
    625                 }
     660                gammaSlider.setEnabled(true);
     661                double gamma = gammaLayers.iterator().next().getGamma();
     662                gammaSlider.setValue((int) (gamma * SLIDER_STEPS / MAX_GAMMA_FACTOR));
    626663            }
    627664        }
    628665
    629         @Override
    630         protected double getValue() {
    631             if (layer != null)
    632                 return layer.getOpacity();
    633             else {
     666        private void updateOpacitySlider(List<Layer> layers, boolean allHidden) {
     667            if (layers.isEmpty() || allHidden) {
     668                opacitySlider.setEnabled(false);
     669            } else {
     670                opacitySlider.setEnabled(true);
    634671                double opacity = 0;
    635                 List<Layer> layers = model.getSelectedLayers();
    636672                for (Layer l : layers) {
    637673                    opacity += l.getOpacity();
    638674                }
    639                 return opacity / layers.size();
    640             }
    641         }
    642 
    643         @Override
    644         public void updateEnabledState() {
    645             if (layer == null) {
    646                 setEnabled(!model.getSelectedLayers().isEmpty());
    647             } else {
    648                 setEnabled(true);
     675                opacity /= layers.size();
     676                if (opacity == 0) {
     677                    opacity = 1;
     678                    setOpacityValue(opacity, false);
     679                }
     680                opacitySlider.setValue((int) (opacity * SLIDER_STEPS));
    649681            }
    650682        }
    651683
    652684        @Override
    653685        public boolean supportLayers(List<Layer> layers) {
    654             return true;
    655         }
    656     }
    657 
    658     /**
    659      * Action which allows to change the gamma of one imagery layer.
    660      */
    661     public static final class LayerGammaAction extends AbstractLayerPropertySliderAction {
    662 
    663         /**
    664          * Constructs a new {@code LayerGammaAction}.
    665          * @param model layer list model
    666          */
    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"));
    671         }
    672 
    673         @Override
    674         protected void setValue(double value) {
    675             for (ImageryLayer imageryLayer : Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class)) {
    676                 imageryLayer.setGamma(value);
    677             }
     686            return !layers.isEmpty();
    678687        }
    679688
    680689        @Override
    681         protected double getValue() {
    682             return Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).iterator().next().getGamma();
     690        public Component createMenuComponent() {
     691            return new JMenuItem(this);
    683692        }
    684693
    685694        @Override
    686695        public void updateEnabledState() {
    687             setEnabled(!Utils.filteredCollection(model.getSelectedLayers(), ImageryLayer.class).isEmpty());
     696            setEnabled(!model.getSelectedLayers().isEmpty());
    688697        }
    689698
    690         @Override
    691         public boolean supportLayers(List<Layer> layers) {
    692             return !Utils.filteredCollection(layers, ImageryLayer.class).isEmpty();
     699        /**
     700         * Sets the corresponding side button.
     701         * @param sideButton the corresponding side button
     702         */
     703        void setCorrespondingSideButton(SideButton sideButton) {
     704            this.sideButton = sideButton;
    693705        }
    694706    }
    695707
  • src/org/openstreetmap/josm/gui/layer/Layer.java

     
    360360        return visible && opacity != 0;
    361361    }
    362362
     363    /**
     364     * Gets the opacity of the layer, in range 0...1
     365     * @return The opacity
     366     */
    363367    public double getOpacity() {
    364368        return opacity;
    365369    }
    366370
     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     */
    367376    public void setOpacity(double opacity) {
    368377        if (!(opacity >= 0 && opacity <= 1))
    369378            throw new IllegalArgumentException("Opacity value must be between 0 and 1");
  • test/unit/org/openstreetmap/josm/gui/dialogs/LayerListDialogTest.java

     
    22package org.openstreetmap.josm.gui.dialogs;
    33
    44import static org.junit.Assert.assertEquals;
     5import static org.junit.Assert.assertFalse;
    56import static org.junit.Assert.assertTrue;
    67
    78import org.junit.BeforeClass;
    89import org.junit.Test;
    910import org.openstreetmap.josm.JOSMFixture;
    1011import org.openstreetmap.josm.Main;
    11 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerGammaAction;
    1212import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerListModel;
    13 import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerOpacityAction;
     13import org.openstreetmap.josm.gui.dialogs.LayerListDialog.LayerVisibilityAction;
    1414import org.openstreetmap.josm.gui.layer.TMSLayer;
    1515import org.openstreetmap.josm.gui.layer.TMSLayerTest;
    1616
     
    2828    }
    2929
    3030    /**
    31      * Unit test of {@link LayerGammaAction} class.
     31     * Unit test of {@link LayerVisibilityAction} class.
    3232     */
    3333    @Test
    34     public void testLayerGammaAction() {
     34    public void testLayerVisibilityAction() {
    3535        TMSLayer layer = TMSLayerTest.createTmsLayer();
    3636        try {
    37             Main.map.mapView.addLayer(layer);
    3837            LayerListModel model = LayerListDialog.getInstance().getModel();
    39             LayerGammaAction action = new LayerGammaAction(model);
     38            LayerVisibilityAction action = new LayerVisibilityAction(model);
    4039            action.updateEnabledState();
    41             assertTrue(action.isEnabled());
    42             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);
    46         } finally {
    47             Main.map.mapView.removeLayer(layer);
    48         }
    49     }
     40            assertFalse(action.isEnabled());
    5041
    51     /**
    52      * Unit test of {@link LayerOpacityAction} class.
    53      */
    54     @Test
    55     public void testLayerOpacityAction() {
    56         TMSLayer layer = TMSLayerTest.createTmsLayer();
    57         try {
    5842            Main.map.mapView.addLayer(layer);
    59             LayerListModel model = LayerListDialog.getInstance().getModel();
    60             LayerOpacityAction action = new LayerOpacityAction(model);
    6143            action.updateEnabledState();
    6244            assertTrue(action.isEnabled());
    6345            assertTrue(action.supportLayers(model.getSelectedLayers()));
    64             assertEquals(1.0, action.getValue(), 1e-15);
    65             action.setValue(0.5);
    66             assertEquals(0.5, action.getValue(), 1e-15);
     46
     47            // now check values
     48            action.updateValues();
     49            assertEquals(1.0, action.readOpacityValue(), 1e-15);
     50            assertEquals(1.0, action.readGammaValue(), 1e-15);
     51
     52            action.setOpacityValue(.5, false);
     53            action.setGammaValue(1.5);
     54            action.updateValues();
     55
     56            assertEquals(0.5, action.readOpacityValue(), 1e-15);
     57            assertEquals(1.5, action.readGammaValue(), 1e-15);
     58
     59            action.setVisible(false);
     60            action.updateValues();
     61            assertFalse(layer.isVisible());
     62
     63            action.setVisible(true);
     64            action.updateValues();
     65            assertTrue(layer.isVisible());
     66
     67            // layer stays visible during adjust
     68            action.setOpacityValue(0, true);
     69            assertEquals(0, layer.getOpacity(), 1e-15);
     70            layer.setOpacity(.1); // to make layer.isVisible work
     71            assertTrue(layer.isVisible());
     72            layer.setOpacity(0);
     73
     74            action.setOpacityValue(0, false);
     75            assertEquals(0, layer.getOpacity(), 1e-15);
     76            layer.setOpacity(.1); // to make layer.isVisible work
     77            assertFalse(layer.isVisible());
     78            layer.setOpacity(0);
     79            action.updateValues();
     80
     81            // Opacity reset when it was 0 and user set layer to visible.
     82            action.setVisible(true);
     83            action.updateValues();
     84            assertEquals(1.0, action.readOpacityValue(), 1e-15);
     85            assertEquals(1.0, layer.getOpacity(), 1e-15);
     86
    6787        } finally {
    6888            Main.map.mapView.removeLayer(layer);
    6989        }