Changeset 3661 in josm for trunk/src/org/openstreetmap/josm


Ignore:
Timestamp:
2010-11-20T15:10:05+01:00 (13 years ago)
Author:
bastiK
Message:

converted layerlist JList to JTable to allow activate and show/hide with a single click

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java

    r3408 r3661  
    55import java.awt.BorderLayout;
    66import java.awt.Component;
     7import java.awt.Dimension;
     8import java.awt.Font;
    79import java.awt.Point;
    810import java.awt.Rectangle;
    911import java.awt.event.ActionEvent;
    1012import java.awt.event.KeyEvent;
    11 import java.awt.event.MouseAdapter;
    1213import java.awt.event.MouseEvent;
    1314import java.beans.PropertyChangeEvent;
     
    1920
    2021import javax.swing.AbstractAction;
    21 import javax.swing.DefaultListCellRenderer;
    22 import javax.swing.DefaultListModel;
     22import javax.swing.DefaultCellEditor;
    2323import javax.swing.DefaultListSelectionModel;
    24 import javax.swing.Icon;
     24import javax.swing.ImageIcon;
     25import javax.swing.JCheckBox;
    2526import javax.swing.JComponent;
    2627import javax.swing.JLabel;
    27 import javax.swing.JList;
    2828import javax.swing.JMenuItem;
    2929import javax.swing.JPanel;
    3030import javax.swing.JScrollPane;
     31import javax.swing.JTable;
     32import javax.swing.JTextField;
     33import javax.swing.JViewport;
    3134import javax.swing.KeyStroke;
    32 import javax.swing.ListModel;
    3335import javax.swing.ListSelectionModel;
    3436import javax.swing.UIManager;
    3537import javax.swing.event.ListDataEvent;
    36 import javax.swing.event.ListDataListener;
    3738import javax.swing.event.ListSelectionEvent;
    3839import javax.swing.event.ListSelectionListener;
     40import javax.swing.event.TableModelEvent;
     41import javax.swing.event.TableModelListener;
     42import javax.swing.table.AbstractTableModel;
     43import javax.swing.table.DefaultTableCellRenderer;
     44import javax.swing.table.TableCellRenderer;
     45import javax.swing.table.TableModel;
    3946
    4047import org.openstreetmap.josm.Main;
     
    5360import org.openstreetmap.josm.tools.ImageProvider;
    5461import org.openstreetmap.josm.tools.Shortcut;
    55 import org.openstreetmap.josm.tools.ImageProvider.OverlayPosition;
    5662
    5763/**
     
    97103    private DefaultListSelectionModel selectionModel;
    98104
    99     /** the list of layers */
     105    /** the list of layers (technically its a JTable, but appears like a list) */
    100106    private LayerList layerList;
    101107
     
    168174        layerList = new LayerList(model);
    169175        layerList.setSelectionModel(selectionModel);
    170         layerList.addMouseListener(new DblClickAdapter());
    171176        layerList.addMouseListener(new PopupMenuHandler());
    172177        layerList.setBackground(UIManager.getColor("Button.background"));
    173         layerList.setCellRenderer(new LayerListCellRenderer());
     178        layerList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
     179        layerList.setTableHeader(null);
     180        layerList.setShowGrid(false);
     181        layerList.setIntercellSpacing(new Dimension(0, 0));
     182        final int ICON_WIDTH = 16;
     183        layerList.getColumnModel().getColumn(0).setCellRenderer(new ActiveLayerCellRenderer());
     184        layerList.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(new ActiveLayerCheckBox()));
     185        layerList.getColumnModel().getColumn(0).setMaxWidth(ICON_WIDTH);
     186        layerList.getColumnModel().getColumn(0).setPreferredWidth(ICON_WIDTH);
     187        layerList.getColumnModel().getColumn(0).setResizable(false);
     188        layerList.getColumnModel().getColumn(1).setCellRenderer(new LayerVisibleCellRenderer());
     189        layerList.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(new LayerVisibleCheckBox()));
     190        layerList.getColumnModel().getColumn(1).setMaxWidth(ICON_WIDTH);
     191        layerList.getColumnModel().getColumn(1).setPreferredWidth(ICON_WIDTH);
     192        layerList.getColumnModel().getColumn(1).setResizable(false);
     193        layerList.getColumnModel().getColumn(2).setCellRenderer(new LayerNameCellRenderer());
     194        layerList.getColumnModel().getColumn(2).setCellEditor(new LayerNameCellEditor(new JTextField()));
     195
    174196        add(new JScrollPane(layerList), BorderLayout.CENTER);
    175197
     
    181203        model.addLayerListModelListener(
    182204                new LayerListModelListener() {
    183                     public void makeVisible(int index, Layer layer) {
    184                         layerList.ensureIndexIsVisible(index);
     205                    public void makeVisible(int row, Layer layer) {
     206                        System.err.println(Thread.currentThread());
     207                        layerList.scrollToVisible(row, 0);
     208                        layerList.repaint();
    185209                    }
    186210                    public void refresh() {
     
    210234    }
    211235
    212     private interface IEnabledStateUpdating {
     236    protected interface IEnabledStateUpdating {
    213237        void updateEnabledState();
    214238    }
     
    240264     * @param listSelectionModel  the source emitting {@see ListDataEvent}s
    241265     */
    242     protected void adaptTo(final IEnabledStateUpdating listener, ListModel listModel) {
    243         listModel.addListDataListener(
    244                 new ListDataListener() {
    245                     public void contentsChanged(ListDataEvent e) {
    246                         listener.updateEnabledState();
    247                     }
    248 
    249                     public void intervalAdded(ListDataEvent e) {
    250                         listener.updateEnabledState();
    251                     }
    252 
    253                     public void intervalRemoved(ListDataEvent e) {
    254                         listener.updateEnabledState();
    255                     }
    256                 }
     266    protected void adaptTo(final IEnabledStateUpdating listener, LayerListModel listModel) {
     267        listModel.addTableModelListener(
     268            new TableModelListener() {
     269
     270                @Override
     271                public void tableChanged(TableModelEvent e) {
     272                    listener.updateEnabledState();
     273                }
     274            }
    257275        );
    258276    }
     
    577595    }
    578596
    579     /**
    580      * the list cell renderer used to render layer list entries
    581      *
    582      */
    583     static class LayerListCellRenderer extends DefaultListCellRenderer {
     597    private static class ActiveLayerCheckBox extends JCheckBox {
     598        public ActiveLayerCheckBox() {
     599            setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
     600            ImageIcon blank = ImageProvider.get("dialogs/layerlist", "blank");
     601            ImageIcon active = ImageProvider.get("dialogs/layerlist", "active");
     602            setIcon(blank);
     603            setSelectedIcon(active);
     604            setRolloverIcon(blank);
     605            setRolloverSelectedIcon(active);
     606            setPressedIcon(active);
     607        }
     608    }
     609
     610    private static class LayerVisibleCheckBox extends JCheckBox {
     611        public LayerVisibleCheckBox() {
     612            setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
     613            ImageIcon eye = ImageProvider.get("dialogs/layerlist", "eye");
     614            ImageIcon eye_off = ImageProvider.get("dialogs/layerlist", "eye-off");
     615            setIcon(eye_off);
     616            setSelectedIcon(eye);
     617            setRolloverIcon(eye_off);
     618            setRolloverSelectedIcon(eye);
     619            setPressedIcon(ImageProvider.get("dialogs/layerlist", "eye-pressed"));
     620        }
     621    }
     622
     623    private static class ActiveLayerCellRenderer implements TableCellRenderer {
     624        JCheckBox cb;
     625        public ActiveLayerCellRenderer() {
     626            cb = new ActiveLayerCheckBox();
     627        }
     628
     629        @Override
     630        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     631            boolean active = (Boolean) value;
     632            cb.setSelected(active);
     633            cb.setToolTipText(active ? tr("this layer is the active layer") : tr("this layer is not currently active (click to activate)"));
     634            return cb;
     635        }
     636    }
     637
     638    private static class LayerVisibleCellRenderer implements TableCellRenderer {
     639        JCheckBox cb;
     640        public LayerVisibleCellRenderer() {
     641            cb = new LayerVisibleCheckBox();
     642        }
     643
     644        @Override
     645        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
     646            boolean visible = (Boolean) value;
     647            cb.setSelected(visible);
     648            cb.setToolTipText(visible ? tr("layer is currently visible (click to hide layer)") : tr("layer is currently hidden (click to show layer)"));
     649            return cb;
     650        }
     651    }
     652
     653   private static class LayerNameCellRenderer extends DefaultTableCellRenderer {
    584654
    585655        protected boolean isActiveLayer(Layer layer) {
     
    589659        }
    590660
    591         @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
     661        @Override
     662        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    592663            Layer layer = (Layer)value;
    593             JLabel label = (JLabel)super.getListCellRendererComponent(list,
    594                     layer.getName(), index, isSelected, cellHasFocus);
    595             Icon icon = layer.getIcon();
     664            JLabel label = (JLabel)super.getTableCellRendererComponent(table,
     665                    layer.getName(), isSelected, hasFocus, row, column);
    596666            if (isActiveLayer(layer)) {
    597                 icon = ImageProvider.overlay(icon, "overlay/active", OverlayPosition.SOUTHWEST);
    598             }
    599             if (!layer.isVisible()) {
    600                 icon = ImageProvider.overlay(icon, "overlay/invisiblenew", OverlayPosition.SOUTHEAST);
    601             }
    602             label.setIcon(icon);
     667                label.setFont(label.getFont().deriveFont(Font.BOLD));
     668            }
     669            //label.setEnabled(layer.isVisible());
     670            label.setIcon(layer.getIcon());
    603671            label.setToolTipText(layer.getToolTipText());
    604672            return label;
     
    606674    }
    607675
     676    private static class LayerNameCellEditor extends DefaultCellEditor {
     677        public LayerNameCellEditor(JTextField tf) {
     678            super(tf);
     679        }
     680
     681        @Override
     682        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
     683            JTextField tf = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, row, column);
     684            Layer l = (Layer) value;
     685            tf.setText(l.getName());
     686            return tf;
     687        }
     688    }
     689
    608690    class PopupMenuHandler extends PopupMenuLauncher {
    609691        @Override
    610692        public void launch(MouseEvent evt) {
    611693            Point p = evt.getPoint();
    612             int index = layerList.locationToIndex(p);
     694            int index = layerList.rowAtPoint(p);
    613695            if (index < 0) return;
    614             if (!layerList.getCellBounds(index, index).contains(evt.getPoint()))
     696            if (!layerList.getCellRect(index, 2, false).contains(evt.getPoint()))
    615697                return;
    616             if (!layerList.isSelectedIndex(index)) {
    617                 layerList.setSelectedIndex(index);
     698            if (!layerList.isRowSelected(index)) {
     699                layerList.setRowSelectionInterval(index, index);
    618700            }
    619701            Layer layer = model.getLayer(index);
    620702            LayerListPopup menu = new LayerListPopup(getModel().getSelectedLayers(), layer);
    621703            menu.show(LayerListDialog.this, p.x, p.y-3);
    622         }
    623     }
    624 
    625     class DblClickAdapter extends MouseAdapter {
    626         @Override public void mouseClicked(MouseEvent e) {
    627             if (e.getClickCount() == 2) {
    628                 int index = layerList.locationToIndex(e.getPoint());
    629                 if (!layerList.getCellBounds(index, index).contains(e.getPoint()))
    630                     return;
    631                 Layer layer = model.getLayer(index);
    632                 layer.toggleVisible();
    633             }
    634704        }
    635705    }
     
    686756     * moving layers up and down, for toggling their visibility, and for activating a layer.
    687757     *
    688      * The model is a {@see ListModel} and it provides a {@see ListSelectionModel}. It expectes
     758     * The model is a {@see TableModel} and it provides a {@see ListSelectionModel}. It expects
    689759     * to be configured with a {@see DefaultListSelectionModel}. The selection model is used
    690760     * to update the selection state of views depending on messages sent to the model.
     
    696766     * the properties {@see Layer#VISIBLE_PROP} and {@see Layer#NAME_PROP}.
    697767     */
    698     public static class LayerListModel extends DefaultListModel implements MapView.LayerChangeListener, PropertyChangeListener{
    699 
     768    public static class LayerListModel extends AbstractTableModel implements MapView.LayerChangeListener, PropertyChangeListener {
    700769        /** manages list selection state*/
    701770        private DefaultListSelectionModel selectionModel;
     
    768837                layer.addPropertyChangeListener(this);
    769838            }
    770             fireContentsChanged(this, 0, getSize());
     839            fireTableDataChanged();
    771840        }
    772841
     
    784853                selectionModel.setSelectionInterval(idx, idx);
    785854            }
    786             fireContentsChanged(this, 0, getSize());
    787855            ensureSelectedIsVisible();
    788856        }
     
    831899                return;
    832900            layer.removePropertyChangeListener(this);
    833             int size = getSize();
     901            int size = getRowCount();
    834902            List<Integer> rows = getSelectedRows();
    835903            if (rows.isEmpty() && size > 0) {
    836904                selectionModel.setSelectionInterval(size-1, size-1);
    837905            }
     906            fireTableDataChanged();
    838907            fireRefresh();
    839908            ensureActiveSelected();
     
    848917            if (layer == null) return;
    849918            layer.addPropertyChangeListener(this);
    850             fireContentsChanged(this, 0, getSize());
     919            fireTableDataChanged();
    851920            int idx = getLayers().indexOf(layer);
    852921            selectionModel.setSelectionInterval(idx, idx);
     
    860929         */
    861930        public Layer getFirstLayer() {
    862             if (getSize() == 0) return null;
     931            if (getRowCount() == 0) return null;
    863932            return getLayers().get(0);
    864933        }
     
    872941         */
    873942        public Layer getLayer(int index) {
    874             if (index < 0 || index >= getSize())
     943            if (index < 0 || index >= getRowCount())
    875944                return null;
    876945            return getLayers().get(index);
     
    902971                Main.map.mapView.moveLayer(l1, row-1);
    903972            }
    904             fireContentsChanged(this, 0, getSize());
     973            fireTableDataChanged();
    905974            selectionModel.clearSelection();
    906975            for(int row: sel) {
     
    9361005                Main.map.mapView.moveLayer(l2, row);
    9371006            }
    938             fireContentsChanged(this, 0, getSize());
     1007            fireTableDataChanged();
    9391008            selectionModel.clearSelection();
    9401009            for(int row: sel) {
     
    9981067         */
    9991068        protected void ensureActiveSelected() {
    1000             if (getLayers().size() == 0) return;
     1069            if (getLayers().isEmpty())
     1070                return;
    10011071            if (getActiveLayer() != null) {
    10021072                // there's an active layer - select it and make it
     
    10241094
    10251095        /* ------------------------------------------------------------------------------ */
    1026         /* Interface ListModel                                                            */
     1096        /* Interface TableModel                                                           */
    10271097        /* ------------------------------------------------------------------------------ */
    1028         @Override
    1029         public Object getElementAt(int index) {
    1030             return getLayers().get(index);
    1031         }
    1032 
    1033         @Override
    1034         public int getSize() {
     1098
     1099        @Override
     1100        public int getRowCount() {
    10351101            List<Layer> layers = getLayers();
    10361102            if (layers == null) return 0;
     
    10381104        }
    10391105
     1106        @Override
     1107        public int getColumnCount() {
     1108            return 3;
     1109        }
     1110
     1111        @Override
     1112        public Object getValueAt(int row, int col) {
     1113            switch (col) {
     1114            case 0: return getLayers().get(row) == getActiveLayer();
     1115            case 1: return getLayers().get(row).isVisible();
     1116            case 2: return getLayers().get(row);
     1117            default: throw new RuntimeException();
     1118            }
     1119        }
     1120
     1121        public boolean isCellEditable(int row, int col) {
     1122            if (col == 0 && getActiveLayer() == getLayers().get(row))
     1123                return false;
     1124            return true;
     1125        }
     1126
     1127        public void setValueAt(Object value, int row, int col) {
     1128            Layer l = getLayers().get(row);
     1129            switch (col) {
     1130            case 0:
     1131                Main.map.mapView.setActiveLayer(l);
     1132                l.setVisible(true);
     1133                break;
     1134            case 1:
     1135                l.setVisible((Boolean) value);
     1136                break;
     1137            case 2:
     1138                l.setName((String) value);
     1139                break;
     1140                default: throw new RuntimeException();
     1141            }
     1142            fireTableCellUpdated(row, col);
     1143        }
     1144
    10401145        /* ------------------------------------------------------------------------------ */
    10411146        /* Interface LayerChangeListener                                                  */
    10421147        /* ------------------------------------------------------------------------------ */
     1148        @Override
    10431149        public void activeLayerChange(Layer oldLayer, Layer newLayer) {
    10441150            if (oldLayer != null) {
    10451151                int idx = getLayers().indexOf(oldLayer);
    10461152                if (idx >= 0) {
    1047                     fireContentsChanged(this, idx,idx);
     1153                    fireTableRowsUpdated(idx,idx);
    10481154                }
    10491155            }
     
    10521158                int idx = getLayers().indexOf(newLayer);
    10531159                if (idx >= 0) {
    1054                     fireContentsChanged(this, idx,idx);
     1160                    fireTableRowsUpdated(idx,idx);
    10551161                }
    10561162            }
     
    10581164        }
    10591165
     1166        @Override
    10601167        public void layerAdded(Layer newLayer) {
    10611168            onAddLayer(newLayer);
    10621169        }
    10631170
     1171        @Override
    10641172        public void layerRemoved(final Layer oldLayer) {
    10651173            onRemoveLayer(oldLayer);
     
    10691177        /* Interface PropertyChangeListener                                               */
    10701178        /* ------------------------------------------------------------------------------ */
     1179        @Override
    10711180        public void propertyChange(PropertyChangeEvent evt) {
    10721181            if (evt.getSource() instanceof Layer) {
     
    10791188    }
    10801189
    1081     static class LayerList extends JList {
    1082         public LayerList(ListModel dataModel) {
     1190    static class LayerList extends JTable {
     1191        public LayerList(TableModel dataModel) {
    10831192            super(dataModel);
    10841193        }
    10851194
    1086         @Override
    1087         protected void processMouseEvent(MouseEvent e) {
    1088             // if the layer list is embedded in a detached dialog, the last row is
    1089             // selected if a user clicks in the empty space *below* the last row.
    1090             // This mouse event filter prevents this.
    1091             //
    1092             int idx = locationToIndex(e.getPoint());
    1093             // sometimes bounds can be null, see #3539
    1094             Rectangle bounds = getCellBounds(idx,idx);
    1095             if (bounds != null && bounds.contains(e.getPoint())) {
    1096                 super.processMouseEvent(e);
    1097             }
     1195        public void scrollToVisible(int row, int col) {
     1196            if (!(getParent() instanceof JViewport))
     1197                return;
     1198            JViewport viewport = (JViewport) getParent();
     1199            Rectangle rect = getCellRect(row, col, true);
     1200            Point pt = viewport.getViewPosition();
     1201            rect.setLocation(rect.x - pt.x, rect.y - pt.y);
     1202            viewport.scrollRectToVisible(rect);
    10981203        }
    10991204    }
Note: See TracChangeset for help on using the changeset viewer.