Index: trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 3660)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 3661)
@@ -5,9 +5,10 @@
 import java.awt.BorderLayout;
 import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.beans.PropertyChangeEvent;
@@ -19,22 +20,28 @@
 
 import javax.swing.AbstractAction;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.DefaultListModel;
+import javax.swing.DefaultCellEditor;
 import javax.swing.DefaultListSelectionModel;
-import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBox;
 import javax.swing.JComponent;
 import javax.swing.JLabel;
-import javax.swing.JList;
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.JViewport;
 import javax.swing.KeyStroke;
-import javax.swing.ListModel;
 import javax.swing.ListSelectionModel;
 import javax.swing.UIManager;
 import javax.swing.event.ListDataEvent;
-import javax.swing.event.ListDataListener;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableModel;
 
 import org.openstreetmap.josm.Main;
@@ -53,5 +60,4 @@
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Shortcut;
-import org.openstreetmap.josm.tools.ImageProvider.OverlayPosition;
 
 /**
@@ -97,5 +103,5 @@
     private DefaultListSelectionModel selectionModel;
 
-    /** the list of layers */
+    /** the list of layers (technically its a JTable, but appears like a list) */
     private LayerList layerList;
 
@@ -168,8 +174,24 @@
         layerList = new LayerList(model);
         layerList.setSelectionModel(selectionModel);
-        layerList.addMouseListener(new DblClickAdapter());
         layerList.addMouseListener(new PopupMenuHandler());
         layerList.setBackground(UIManager.getColor("Button.background"));
-        layerList.setCellRenderer(new LayerListCellRenderer());
+        layerList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        layerList.setTableHeader(null);
+        layerList.setShowGrid(false);
+        layerList.setIntercellSpacing(new Dimension(0, 0));
+        final int ICON_WIDTH = 16;
+        layerList.getColumnModel().getColumn(0).setCellRenderer(new ActiveLayerCellRenderer());
+        layerList.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(new ActiveLayerCheckBox()));
+        layerList.getColumnModel().getColumn(0).setMaxWidth(ICON_WIDTH);
+        layerList.getColumnModel().getColumn(0).setPreferredWidth(ICON_WIDTH);
+        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).setMaxWidth(ICON_WIDTH);
+        layerList.getColumnModel().getColumn(1).setPreferredWidth(ICON_WIDTH);
+        layerList.getColumnModel().getColumn(1).setResizable(false);
+        layerList.getColumnModel().getColumn(2).setCellRenderer(new LayerNameCellRenderer());
+        layerList.getColumnModel().getColumn(2).setCellEditor(new LayerNameCellEditor(new JTextField()));
+
         add(new JScrollPane(layerList), BorderLayout.CENTER);
 
@@ -181,6 +203,8 @@
         model.addLayerListModelListener(
                 new LayerListModelListener() {
-                    public void makeVisible(int index, Layer layer) {
-                        layerList.ensureIndexIsVisible(index);
+                    public void makeVisible(int row, Layer layer) {
+                        System.err.println(Thread.currentThread());
+                        layerList.scrollToVisible(row, 0);
+                        layerList.repaint();
                     }
                     public void refresh() {
@@ -210,5 +234,5 @@
     }
 
-    private interface IEnabledStateUpdating {
+    protected interface IEnabledStateUpdating {
         void updateEnabledState();
     }
@@ -240,19 +264,13 @@
      * @param listSelectionModel  the source emitting {@see ListDataEvent}s
      */
-    protected void adaptTo(final IEnabledStateUpdating listener, ListModel listModel) {
-        listModel.addListDataListener(
-                new ListDataListener() {
-                    public void contentsChanged(ListDataEvent e) {
-                        listener.updateEnabledState();
-                    }
-
-                    public void intervalAdded(ListDataEvent e) {
-                        listener.updateEnabledState();
-                    }
-
-                    public void intervalRemoved(ListDataEvent e) {
-                        listener.updateEnabledState();
-                    }
-                }
+    protected void adaptTo(final IEnabledStateUpdating listener, LayerListModel listModel) {
+        listModel.addTableModelListener(
+            new TableModelListener() {
+
+                @Override
+                public void tableChanged(TableModelEvent e) {
+                    listener.updateEnabledState();
+                }
+            }
         );
     }
@@ -577,9 +595,61 @@
     }
 
-    /**
-     * the list cell renderer used to render layer list entries
-     *
-     */
-    static class LayerListCellRenderer extends DefaultListCellRenderer {
+    private static class ActiveLayerCheckBox extends JCheckBox {
+        public ActiveLayerCheckBox() {
+            setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+            ImageIcon blank = ImageProvider.get("dialogs/layerlist", "blank");
+            ImageIcon active = ImageProvider.get("dialogs/layerlist", "active");
+            setIcon(blank);
+            setSelectedIcon(active);
+            setRolloverIcon(blank);
+            setRolloverSelectedIcon(active);
+            setPressedIcon(active);
+        }
+    }
+
+    private static class LayerVisibleCheckBox extends JCheckBox {
+        public LayerVisibleCheckBox() {
+            setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+            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);
+            setPressedIcon(ImageProvider.get("dialogs/layerlist", "eye-pressed"));
+        }
+    }
+
+    private static class ActiveLayerCellRenderer implements TableCellRenderer {
+        JCheckBox cb;
+        public ActiveLayerCellRenderer() {
+            cb = new ActiveLayerCheckBox();
+        }
+
+        @Override
+        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+            boolean active = (Boolean) value;
+            cb.setSelected(active);
+            cb.setToolTipText(active ? tr("this layer is the active layer") : tr("this layer is not currently active (click to activate)"));
+            return cb;
+        }
+    }
+
+    private static class LayerVisibleCellRenderer implements TableCellRenderer {
+        JCheckBox cb;
+        public LayerVisibleCellRenderer() {
+            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)"));
+            return cb;
+        }
+    }
+
+   private static class LayerNameCellRenderer extends DefaultTableCellRenderer {
 
         protected boolean isActiveLayer(Layer layer) {
@@ -589,16 +659,14 @@
         }
 
-        @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+        @Override
+        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
             Layer layer = (Layer)value;
-            JLabel label = (JLabel)super.getListCellRendererComponent(list,
-                    layer.getName(), index, isSelected, cellHasFocus);
-            Icon icon = layer.getIcon();
+            JLabel label = (JLabel)super.getTableCellRendererComponent(table,
+                    layer.getName(), isSelected, hasFocus, row, column);
             if (isActiveLayer(layer)) {
-                icon = ImageProvider.overlay(icon, "overlay/active", OverlayPosition.SOUTHWEST);
-            }
-            if (!layer.isVisible()) {
-                icon = ImageProvider.overlay(icon, "overlay/invisiblenew", OverlayPosition.SOUTHEAST);
-            }
-            label.setIcon(icon);
+                label.setFont(label.getFont().deriveFont(Font.BOLD));
+            }
+            //label.setEnabled(layer.isVisible());
+            label.setIcon(layer.getIcon());
             label.setToolTipText(layer.getToolTipText());
             return label;
@@ -606,30 +674,32 @@
     }
 
+    private static class LayerNameCellEditor extends DefaultCellEditor {
+        public LayerNameCellEditor(JTextField tf) {
+            super(tf);
+        }
+
+        @Override
+        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+            JTextField tf = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, row, column);
+            Layer l = (Layer) value;
+            tf.setText(l.getName());
+            return tf;
+        }
+    }
+
     class PopupMenuHandler extends PopupMenuLauncher {
         @Override
         public void launch(MouseEvent evt) {
             Point p = evt.getPoint();
-            int index = layerList.locationToIndex(p);
+            int index = layerList.rowAtPoint(p);
             if (index < 0) return;
-            if (!layerList.getCellBounds(index, index).contains(evt.getPoint()))
+            if (!layerList.getCellRect(index, 2, false).contains(evt.getPoint()))
                 return;
-            if (!layerList.isSelectedIndex(index)) {
-                layerList.setSelectedIndex(index);
+            if (!layerList.isRowSelected(index)) {
+                layerList.setRowSelectionInterval(index, index);
             }
             Layer layer = model.getLayer(index);
             LayerListPopup menu = new LayerListPopup(getModel().getSelectedLayers(), layer);
             menu.show(LayerListDialog.this, p.x, p.y-3);
-        }
-    }
-
-    class DblClickAdapter extends MouseAdapter {
-        @Override public void mouseClicked(MouseEvent e) {
-            if (e.getClickCount() == 2) {
-                int index = layerList.locationToIndex(e.getPoint());
-                if (!layerList.getCellBounds(index, index).contains(e.getPoint()))
-                    return;
-                Layer layer = model.getLayer(index);
-                layer.toggleVisible();
-            }
         }
     }
@@ -686,5 +756,5 @@
      * moving layers up and down, for toggling their visibility, and for activating a layer.
      *
-     * The model is a {@see ListModel} and it provides a {@see ListSelectionModel}. It expectes
+     * The model is a {@see TableModel} and it provides a {@see ListSelectionModel}. It expects
      * to be configured with a {@see DefaultListSelectionModel}. The selection model is used
      * to update the selection state of views depending on messages sent to the model.
@@ -696,6 +766,5 @@
      * the properties {@see Layer#VISIBLE_PROP} and {@see Layer#NAME_PROP}.
      */
-    public static class LayerListModel extends DefaultListModel implements MapView.LayerChangeListener, PropertyChangeListener{
-
+    public static class LayerListModel extends AbstractTableModel implements MapView.LayerChangeListener, PropertyChangeListener {
         /** manages list selection state*/
         private DefaultListSelectionModel selectionModel;
@@ -768,5 +837,5 @@
                 layer.addPropertyChangeListener(this);
             }
-            fireContentsChanged(this, 0, getSize());
+            fireTableDataChanged();
         }
 
@@ -784,5 +853,4 @@
                 selectionModel.setSelectionInterval(idx, idx);
             }
-            fireContentsChanged(this, 0, getSize());
             ensureSelectedIsVisible();
         }
@@ -831,9 +899,10 @@
                 return;
             layer.removePropertyChangeListener(this);
-            int size = getSize();
+            int size = getRowCount();
             List<Integer> rows = getSelectedRows();
             if (rows.isEmpty() && size > 0) {
                 selectionModel.setSelectionInterval(size-1, size-1);
             }
+            fireTableDataChanged();
             fireRefresh();
             ensureActiveSelected();
@@ -848,5 +917,5 @@
             if (layer == null) return;
             layer.addPropertyChangeListener(this);
-            fireContentsChanged(this, 0, getSize());
+            fireTableDataChanged();
             int idx = getLayers().indexOf(layer);
             selectionModel.setSelectionInterval(idx, idx);
@@ -860,5 +929,5 @@
          */
         public Layer getFirstLayer() {
-            if (getSize() == 0) return null;
+            if (getRowCount() == 0) return null;
             return getLayers().get(0);
         }
@@ -872,5 +941,5 @@
          */
         public Layer getLayer(int index) {
-            if (index < 0 || index >= getSize())
+            if (index < 0 || index >= getRowCount())
                 return null;
             return getLayers().get(index);
@@ -902,5 +971,5 @@
                 Main.map.mapView.moveLayer(l1, row-1);
             }
-            fireContentsChanged(this, 0, getSize());
+            fireTableDataChanged();
             selectionModel.clearSelection();
             for(int row: sel) {
@@ -936,5 +1005,5 @@
                 Main.map.mapView.moveLayer(l2, row);
             }
-            fireContentsChanged(this, 0, getSize());
+            fireTableDataChanged();
             selectionModel.clearSelection();
             for(int row: sel) {
@@ -998,5 +1067,6 @@
          */
         protected void ensureActiveSelected() {
-            if (getLayers().size() == 0) return;
+            if (getLayers().isEmpty())
+                return;
             if (getActiveLayer() != null) {
                 // there's an active layer - select it and make it
@@ -1024,13 +1094,9 @@
 
         /* ------------------------------------------------------------------------------ */
-        /* Interface ListModel                                                            */
+        /* Interface TableModel                                                           */
         /* ------------------------------------------------------------------------------ */
-        @Override
-        public Object getElementAt(int index) {
-            return getLayers().get(index);
-        }
-
-        @Override
-        public int getSize() {
+
+        @Override
+        public int getRowCount() {
             List<Layer> layers = getLayers();
             if (layers == null) return 0;
@@ -1038,12 +1104,52 @@
         }
 
+        @Override
+        public int getColumnCount() {
+            return 3;
+        }
+
+        @Override
+        public Object getValueAt(int row, int col) {
+            switch (col) {
+            case 0: return getLayers().get(row) == getActiveLayer();
+            case 1: return getLayers().get(row).isVisible();
+            case 2: return getLayers().get(row);
+            default: throw new RuntimeException();
+            }
+        }
+
+        public boolean isCellEditable(int row, int col) {
+            if (col == 0 && getActiveLayer() == getLayers().get(row))
+                return false;
+            return true;
+        }
+
+        public void setValueAt(Object value, int row, int col) {
+            Layer l = getLayers().get(row);
+            switch (col) {
+            case 0:
+                Main.map.mapView.setActiveLayer(l);
+                l.setVisible(true);
+                break;
+            case 1:
+                l.setVisible((Boolean) value);
+                break;
+            case 2:
+                l.setName((String) value);
+                break;
+                default: throw new RuntimeException();
+            }
+            fireTableCellUpdated(row, col);
+        }
+
         /* ------------------------------------------------------------------------------ */
         /* Interface LayerChangeListener                                                  */
         /* ------------------------------------------------------------------------------ */
+        @Override
         public void activeLayerChange(Layer oldLayer, Layer newLayer) {
             if (oldLayer != null) {
                 int idx = getLayers().indexOf(oldLayer);
                 if (idx >= 0) {
-                    fireContentsChanged(this, idx,idx);
+                    fireTableRowsUpdated(idx,idx);
                 }
             }
@@ -1052,5 +1158,5 @@
                 int idx = getLayers().indexOf(newLayer);
                 if (idx >= 0) {
-                    fireContentsChanged(this, idx,idx);
+                    fireTableRowsUpdated(idx,idx);
                 }
             }
@@ -1058,8 +1164,10 @@
         }
 
+        @Override
         public void layerAdded(Layer newLayer) {
             onAddLayer(newLayer);
         }
 
+        @Override
         public void layerRemoved(final Layer oldLayer) {
             onRemoveLayer(oldLayer);
@@ -1069,4 +1177,5 @@
         /* Interface PropertyChangeListener                                               */
         /* ------------------------------------------------------------------------------ */
+        @Override
         public void propertyChange(PropertyChangeEvent evt) {
             if (evt.getSource() instanceof Layer) {
@@ -1079,21 +1188,17 @@
     }
 
-    static class LayerList extends JList {
-        public LayerList(ListModel dataModel) {
+    static class LayerList extends JTable {
+        public LayerList(TableModel dataModel) {
             super(dataModel);
         }
 
-        @Override
-        protected void processMouseEvent(MouseEvent e) {
-            // if the layer list is embedded in a detached dialog, the last row is
-            // selected if a user clicks in the empty space *below* the last row.
-            // This mouse event filter prevents this.
-            //
-            int idx = locationToIndex(e.getPoint());
-            // sometimes bounds can be null, see #3539
-            Rectangle bounds = getCellBounds(idx,idx);
-            if (bounds != null && bounds.contains(e.getPoint())) {
-                super.processMouseEvent(e);
-            }
+        public void scrollToVisible(int row, int col) {
+            if (!(getParent() instanceof JViewport))
+                return;
+            JViewport viewport = (JViewport) getParent();
+            Rectangle rect = getCellRect(row, col, true);
+            Point pt = viewport.getViewPosition();
+            rect.setLocation(rect.x - pt.x, rect.y - pt.y);
+            viewport.scrollRectToVisible(rect);
         }
     }
