Changeset 3661 in josm


Ignore:
Timestamp:
Nov 20, 2010 3:10:05 PM (3 years ago)
Author:
bastiK
Message:

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

Location:
trunk
Files:
6 added
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.