Index: trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 3704)
+++ trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 3705)
@@ -4,4 +4,5 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.AlphaComposite;
 import java.awt.Color;
 import java.awt.Graphics;
@@ -184,4 +185,5 @@
     // Layers that wasn't changed since last paint
     private final List<Layer> nonChangedLayers = new ArrayList<Layer>();
+    private Layer changedLayer;
     private int lastViewID;
     private boolean paintPreferencesChanged = true;
@@ -440,4 +442,12 @@
     }
 
+    private void paintLayer(Layer layer, Graphics2D g, Bounds box) {
+        if (layer.getOpacity() < 1) {
+            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,(float)layer.getOpacity()));
+        }
+        layer.paint(g, this, box);
+        g.setPaintMode();
+    }
+
     /**
      * Draw the component.
@@ -454,5 +464,5 @@
         int nonChangedLayersCount = 0;
         for (Layer l: visibleLayers) {
-            if (l.isChanged()) {
+            if (l.isChanged() || l == changedLayer) {
                 break;
             } else {
@@ -490,5 +500,5 @@
 
             for (int i=0; i<nonChangedLayersCount; i++) {
-                visibleLayers.get(i).paint(g2, this, box);
+                paintLayer(visibleLayers.get(i),g2, box);
             }
         } else {
@@ -498,5 +508,5 @@
                 g2.setClip(g.getClip());
                 for (int i=nonChangedLayers.size(); i<nonChangedLayersCount; i++) {
-                    visibleLayers.get(i).paint(g2, this, box);
+                    paintLayer(visibleLayers.get(i),g2, box);
                 }
             }
@@ -504,4 +514,5 @@
 
         nonChangedLayers.clear();
+        changedLayer = null;
         for (int i=0; i<nonChangedLayersCount; i++) {
             nonChangedLayers.add(visibleLayers.get(i));
@@ -514,5 +525,5 @@
 
         for (int i=nonChangedLayersCount; i<visibleLayers.size(); i++) {
-            visibleLayers.get(i).paint(tempG, this, box);
+            paintLayer(visibleLayers.get(i),tempG, box);
         }
 
@@ -783,4 +794,10 @@
         if (evt.getPropertyName().equals(Layer.VISIBLE_PROP)) {
             repaint();
+        } else if (evt.getPropertyName().equals(Layer.OPACITY_PROP)) {
+            Layer l = (Layer)evt.getSource();
+            if (l.isVisible()) {
+                changedLayer = l;
+                repaint();
+            }
         } else if (evt.getPropertyName().equals(OsmDataLayer.REQUIRES_SAVE_TO_DISK_PROP)
                 || evt.getPropertyName().equals(OsmDataLayer.REQUIRES_UPLOAD_TO_SERVER_PROP)) {
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 3704)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 3705)
@@ -31,5 +31,7 @@
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
 import javax.swing.JScrollPane;
+import javax.swing.JSlider;
 import javax.swing.JTable;
 import javax.swing.JTextField;
@@ -38,4 +40,6 @@
 import javax.swing.ListSelectionModel;
 import javax.swing.UIManager;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
@@ -108,4 +112,6 @@
     private LayerList layerList;
 
+    private SideButton opacityButton;
+
     ActivateLayerAction activateLayerAction;
 
@@ -152,4 +158,10 @@
         adaptTo(deleteLayerAction, selectionModel);
         buttonPanel.add(new SideButton(deleteLayerAction, false));
+
+        //-- layer opacity action
+        LayerOpacityAction layerOpacityAction = new LayerOpacityAction();
+        adaptTo(layerOpacityAction, selectionModel);
+        opacityButton = new SideButton(layerOpacityAction);
+        buttonPanel.add(opacityButton);
 
         return buttonPanel;
@@ -185,5 +197,5 @@
         layerList.getColumnModel().getColumn(0).setResizable(false);
         layerList.getColumnModel().getColumn(1).setCellRenderer(new LayerVisibleCellRenderer());
-        layerList.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(new LayerVisibleCheckBox()));
+        layerList.getColumnModel().getColumn(1).setCellEditor(new LayerVisibleCellEditor(new LayerVisibleCheckBox()));
         layerList.getColumnModel().getColumn(1).setMaxWidth(16);
         layerList.getColumnModel().getColumn(1).setPreferredWidth(16);
@@ -200,5 +212,5 @@
                 KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0),
                 KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
-                })
+        })
         {
             layerList.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, new Object());
@@ -279,11 +291,11 @@
     protected void adaptTo(final IEnabledStateUpdating listener, LayerListModel listModel) {
         listModel.addTableModelListener(
-            new TableModelListener() {
-
-                @Override
-                public void tableChanged(TableModelEvent e) {
-                    listener.updateEnabledState();
-                }
-            }
+                new TableModelListener() {
+
+                    @Override
+                    public void tableChanged(TableModelEvent e) {
+                        listener.updateEnabledState();
+                    }
+                }
         );
     }
@@ -438,4 +450,104 @@
         public boolean equals(Object obj) {
             return obj instanceof ShowHideLayerAction;
+        }
+
+        @Override
+        public int hashCode() {
+            return getClass().hashCode();
+        }
+    }
+
+    public final class LayerOpacityAction extends AbstractAction implements IEnabledStateUpdating, LayerAction {
+        private Layer layer;
+        private JPopupMenu popup;
+        private JSlider slider = new JSlider(JSlider.VERTICAL);
+
+        /**
+         * Creates a {@see LayerOpacityAction} which allows to chenge the
+         * opacity of one or more layers.
+         *
+         * @param layer  the layer. Must not be null.
+         * @exception IllegalArgumentException thrown, if layer is null
+         */
+        public LayerOpacityAction(Layer layer) throws IllegalArgumentException {
+            this();
+            putValue(NAME, tr("Opacity"));
+            CheckParameterUtil.ensureParameterNotNull(layer, "layer");
+            this.layer = layer;
+            updateEnabledState();
+        }
+
+        /**
+         * Creates a {@see ShowHideLayerAction} which will toggle the visibility of
+         * the currently selected layers
+         *
+         */
+        public LayerOpacityAction() {
+            putValue(SHORT_DESCRIPTION, tr("Adjust opacity of the layer."));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "transparency"));
+            updateEnabledState();
+
+            popup = new JPopupMenu();
+            slider.addChangeListener(new ChangeListener() {
+                @Override
+                public void stateChanged(ChangeEvent e) {
+                    setOpacity((double)slider.getValue()/100);
+                }
+            });
+            popup.add(slider);
+        }
+
+        private void setOpacity(double value) {
+            if (!isEnabled()) return;
+            if (layer != null) {
+                layer.setOpacity(value);
+            } else {
+                for(Layer layer: model.getSelectedLayers()) {
+                    layer.setOpacity(value);
+                }
+            }
+        }
+
+        private double getOpacity() {
+            if (layer != null)
+                return layer.getOpacity();
+            else {
+                double opacity = 0;
+                List<Layer> layers = model.getSelectedLayers();
+                for(Layer layer: layers) {
+                    opacity += layer.getOpacity();
+                }
+                return opacity / layers.size();
+            }
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            slider.setValue((int)Math.round(getOpacity()*100));
+            popup.show(opacityButton, 0, opacityButton.getHeight());
+        }
+
+        @Override
+        public void updateEnabledState() {
+            if (layer == null) {
+                setEnabled(! getModel().getSelectedLayers().isEmpty());
+            } else {
+                setEnabled(true);
+            }
+        }
+
+        @Override
+        public Component createMenuComponent() {
+            return new JMenuItem(this);
+        }
+
+        @Override
+        public boolean supportLayers(List<Layer> layers) {
+            return true;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof LayerOpacityAction;
         }
 
@@ -635,13 +747,32 @@
 
     private static class LayerVisibleCheckBox extends JCheckBox {
+        private final ImageIcon icon_eye;
+        private final ImageIcon icon_eye_translucent;
+        private boolean isTranslucent;
         public LayerVisibleCheckBox() {
             setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
-            ImageIcon eye = ImageProvider.get("dialogs/layerlist", "eye");
-            ImageIcon eye_off = ImageProvider.get("dialogs/layerlist", "eye-off");
-            setIcon(eye_off);
-            setSelectedIcon(eye);
-            setRolloverIcon(eye_off);
-            setRolloverSelectedIcon(eye);
+            icon_eye = ImageProvider.get("dialogs/layerlist", "eye");
+            icon_eye_translucent = ImageProvider.get("dialogs/layerlist", "eye-translucent");
+            setIcon(ImageProvider.get("dialogs/layerlist", "eye-off"));
             setPressedIcon(ImageProvider.get("dialogs/layerlist", "eye-pressed"));
+            setSelectedIcon(icon_eye);
+            isTranslucent = false;
+        }
+
+        public void setTranslucent(boolean isTranslucent) {
+            if (this.isTranslucent == isTranslucent) return;
+            if (isTranslucent) {
+                setSelectedIcon(icon_eye_translucent);
+            } else {
+                setSelectedIcon(icon_eye);
+            }
+            this.isTranslucent = isTranslucent;
+        }
+
+        public void updateStatus(Layer layer) {
+            boolean visible = layer.isVisible();
+            setSelected(visible);
+            setTranslucent(layer.getOpacity()<1.0);
+            setToolTipText(visible ? tr("layer is currently visible (click to hide layer)") : tr("layer is currently hidden (click to show layer)"));
         }
     }
@@ -663,19 +794,31 @@
 
     private static class LayerVisibleCellRenderer implements TableCellRenderer {
-        JCheckBox cb;
+        LayerVisibleCheckBox cb;
         public LayerVisibleCellRenderer() {
-            cb = new LayerVisibleCheckBox();
+            this.cb = new LayerVisibleCheckBox();
         }
 
         @Override
         public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-            boolean visible = (Boolean) value;
-            cb.setSelected(visible);
-            cb.setToolTipText(visible ? tr("layer is currently visible (click to hide layer)") : tr("layer is currently hidden (click to show layer)"));
+            cb.updateStatus((Layer)value);
             return cb;
         }
     }
 
-   private static class LayerNameCellRenderer extends DefaultTableCellRenderer {
+    private static class LayerVisibleCellEditor extends DefaultCellEditor {
+        LayerVisibleCheckBox cb;
+        public LayerVisibleCellEditor(LayerVisibleCheckBox cb) {
+            super(cb);
+            this.cb = cb;
+        }
+
+        @Override
+        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+            cb.updateStatus((Layer)value);
+            return cb;
+        }
+    }
+
+    private static class LayerNameCellRenderer extends DefaultTableCellRenderer {
 
         protected boolean isActiveLayer(Layer layer) {
@@ -1142,5 +1285,5 @@
             switch (col) {
             case 0: return getLayers().get(row) == getActiveLayer();
-            case 1: return getLayers().get(row).isVisible();
+            case 1: return getLayers().get(row);
             case 2: return getLayers().get(row);
             default: throw new RuntimeException();
@@ -1169,5 +1312,5 @@
                 l.setName((String) value);
                 break;
-                default: throw new RuntimeException();
+            default: throw new RuntimeException();
             }
             fireTableCellUpdated(row, col);
Index: trunk/src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 3704)
+++ trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 3705)
@@ -70,4 +70,5 @@
 
     static public final String VISIBLE_PROP = Layer.class.getName() + ".visible";
+    static public final String OPACITY_PROP = Layer.class.getName() + ".opacity";
     static public final String NAME_PROP = Layer.class.getName() + ".name";
 
@@ -81,4 +82,10 @@
      */
     private boolean visible = true;
+
+    /**
+     * The opacity of the layer.
+     *
+     */
+    private double opacity = 1;
 
     /**
@@ -111,4 +118,5 @@
      * @param mv The object that can translate GeoPoints to screen coordinates.
      */
+    @Override
     abstract public void paint(Graphics2D g, MapView mv, Bounds box);
     /**
@@ -160,4 +168,5 @@
      * via command line parameter).
      */
+    @Override
     public void destroy() {}
 
@@ -216,8 +225,10 @@
      */
     public void setVisible(boolean visible) {
-        boolean oldValue = this.visible;
+        boolean oldValue = isVisible();
         this.visible  = visible;
-        if (oldValue != this.visible) {
-            fireVisibleChanged(oldValue, this.visible);
+        if (visible && opacity == 0) {
+            setOpacity(1);
+        } else if (oldValue != isVisible()) {
+            fireVisibleChanged(oldValue, isVisible());
         }
     }
@@ -228,5 +239,23 @@
      */
     public boolean isVisible() {
-        return visible;
+        return visible && opacity != 0;
+    }
+
+    public double getOpacity() {
+        return opacity;
+    }
+
+    public void setOpacity(double opacity) {
+        if (!(opacity >= 0 && opacity <= 1))
+            throw new IllegalArgumentException("Opacity value must be between 0 and 1");
+        double oldOpacity = getOpacity();
+        boolean oldVisible = isVisible();
+        this.opacity = opacity;
+        if (oldOpacity != getOpacity()) {
+            fireOpacityChanged(oldOpacity, getOpacity());
+        }
+        if (oldVisible != isVisible()) {
+            fireVisibleChanged(oldVisible, isVisible());
+        }
     }
 
@@ -264,4 +293,14 @@
     protected void fireVisibleChanged(boolean oldValue, boolean newValue) {
         propertyChangeSupport.firePropertyChange(VISIBLE_PROP, oldValue, newValue);
+    }
+
+    /**
+     * fires a property change for the property {@see #OPACITY_PROP}
+     *
+     * @param oldValue the old value
+     * @param newValue the new value
+     */
+    protected void fireOpacityChanged(double oldValue, double newValue) {
+        propertyChangeSupport.firePropertyChange(OPACITY_PROP, oldValue, newValue);
     }
 
