001    /*
002     * Copyright 2002-2006 the original author or authors.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy
006     * of the License at
007     * 
008     * http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations
014     * under the License.
015     */
016    package org.springframework.richclient.list;
017    
018    import java.awt.BorderLayout;
019    import java.awt.Component;
020    import java.awt.Rectangle;
021    
022    import javax.swing.DefaultListCellRenderer;
023    import javax.swing.JComboBox;
024    import javax.swing.JList;
025    import javax.swing.JPanel;
026    import javax.swing.JTable;
027    import javax.swing.ListCellRenderer;
028    import javax.swing.ListSelectionModel;
029    import javax.swing.UIManager;
030    import javax.swing.border.Border;
031    import javax.swing.border.EmptyBorder;
032    import javax.swing.event.TableModelListener;
033    import javax.swing.table.JTableHeader;
034    import javax.swing.table.TableColumnModel;
035    import javax.swing.table.TableModel;
036    
037    import org.springframework.util.Assert;
038    
039    /**
040     * ListCellRenderer which renders table cells in a list cell.
041     * <p>
042     * can be used in a {@link JComboBox} to render a table as a popup.
043     * 
044     * @author Mathias Broekelmann
045     * 
046     */
047    public class TableListCellRenderer extends JTable implements ListCellRenderer {
048    
049        protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
050    
051        private static final Border SAFE_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
052    
053        private ListCellRenderer cellRenderer = new DefaultListCellRenderer();
054    
055        private final JPanel headerPanel = new JPanel(new BorderLayout(0, 0));
056    
057        private static class TableListCellRendererModel implements TableModel {
058    
059            private int row;
060    
061            private TableListModel listModel;
062    
063            public TableListCellRendererModel(TableListModel model) {
064                listModel = model;
065            }
066    
067            /**
068             * @return the listModel
069             */
070            public TableListModel getListModel() {
071                return listModel;
072            }
073    
074            public void setListModel(TableListModel model) {
075                listModel = model;
076            }
077    
078            public int getRowCount() {
079                return 1;
080            }
081    
082            public void setRow(int row) {
083                this.row = row;
084            }
085    
086            public Object getValueAt(int aRow, int aColumn) {
087                return listModel.getValueAt(row, aColumn);
088            }
089    
090            public boolean isCellEditable(int row, int column) {
091                return false;
092            }
093    
094            public int getColumnCount() {
095                return listModel.getColumnCount();
096            }
097    
098            public void addTableModelListener(TableModelListener l) {
099            }
100    
101            public Class getColumnClass(int columnIndex) {
102                return listModel.getColumnClass(columnIndex);
103            }
104    
105            public String getColumnName(int columnIndex) {
106                return listModel.getColumnName(columnIndex);
107            }
108    
109            public void removeTableModelListener(TableModelListener l) {
110            }
111    
112            public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
113            }
114    
115        }
116    
117        public TableListCellRenderer() {
118            this(new DefaultTableListModel());
119        }
120    
121        public TableListCellRenderer(TableListModel model) {
122            this(model, null);
123        }
124    
125        public TableListCellRenderer(TableListModel model, TableColumnModel columnModel) {
126            super(new TableListCellRendererModel(model), columnModel);
127            setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
128            setOpaque(true);
129            setBorder(getNoFocusBorder());
130            headerPanel.add(getTableHeader(), BorderLayout.NORTH);
131        }
132    
133        public TableListModel getTableListModel() {
134            return getTableListCellRendererModel().getListModel();
135        }
136    
137        public void setTableListModel(TableListModel model) {
138            getTableListCellRendererModel().setListModel(model);
139        }
140    
141        public void setModel(TableModel dataModel) {
142            Assert.isInstanceOf(TableListCellRendererModel.class, dataModel);
143            super.setModel(dataModel);
144        }
145    
146        private TableListCellRendererModel getTableListCellRendererModel() {
147            return (TableListCellRendererModel) super.getModel();
148        }
149    
150        private static Border getNoFocusBorder() {
151            if (System.getSecurityManager() != null) {
152                return SAFE_NO_FOCUS_BORDER;
153            } else {
154                return noFocusBorder;
155            }
156        }
157    
158        public void setTableHeader(JTableHeader tableHeader) {
159            super.setTableHeader(tableHeader);
160            if (headerPanel != null) {
161                if (tableHeader == null)
162                    headerPanel.removeAll();
163                else
164                    headerPanel.add(tableHeader, BorderLayout.NORTH);
165            }
166        }
167    
168        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
169                boolean cellHasFocus) {
170            if (index == -1) {
171                Component comp = cellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
172                return comp;
173            }
174            getTableListCellRendererModel().setRow(index);
175    
176            setComponentOrientation(list.getComponentOrientation());
177            if (isSelected) {
178                setBackground(list.getSelectionBackground());
179                setForeground(list.getSelectionForeground());
180            } else {
181                setBackground(list.getBackground());
182                setForeground(list.getForeground());
183            }
184    
185            setEnabled(list.isEnabled());
186            setFont(list.getFont());
187    
188            Border border = null;
189            if (cellHasFocus) {
190                if (isSelected) {
191                    border = UIManager.getBorder("List.focusSelectedCellHighlightBorder");
192                }
193                if (border == null) {
194                    border = UIManager.getBorder("List.focusCellHighlightBorder");
195                }
196            } else {
197                border = getNoFocusBorder();
198            }
199            setBorder(border);
200    
201            if (index == 0) {
202                headerPanel.add(this);
203                return headerPanel;
204            }
205    
206            return this;
207        }
208    
209        /**
210         * Overridden for performance reasons.
211         */
212        public void validate() {
213        }
214        
215        /**
216         * Overridden for performance reasons.
217         */
218        protected void validateTree() {
219        }
220    
221        /**
222         * Overridden for performance reasons.
223         */
224        public void revalidate() {
225        }
226    
227        /**
228         * Overridden for performance reasons.
229         */
230        public void repaint(long tm, int x, int y, int width, int height) {
231        }
232    
233        /**
234         * Overridden for performance reasons.
235         */
236        public void repaint(Rectangle r) {
237        }
238    
239        /**
240         * Overridden for performance reasons.
241         */
242        protected void firePropertyChange(String propertyName, Object oldValue,
243            Object newValue) {
244        }
245    
246        /**
247         * Overridden for performance reasons.
248         */
249        public void firePropertyChange(String propertyName, byte oldValue,
250            byte newValue) {
251        }
252    
253        /**
254         * Overridden for performance reasons.
255         */
256        public void firePropertyChange(String propertyName, char oldValue,
257            char newValue) {
258        }
259    
260        /**
261         * Overridden for performance reasons.
262         */
263        public void firePropertyChange(String propertyName, short oldValue,
264            short newValue) {
265        }
266    
267        /**
268         * Overridden for performance reasons.
269         */
270        public void firePropertyChange(String propertyName, int oldValue,
271            int newValue) {
272        }
273    
274        /**
275         * Overridden for performance reasons.
276         */
277        public void firePropertyChange(String propertyName, long oldValue,
278            long newValue) {
279        }
280    
281        /**
282         * Overridden for performance reasons.
283         */
284        public void firePropertyChange(String propertyName, float oldValue,
285            float newValue) {
286        }
287    
288        /**
289         * Overridden for performance reasons.
290         */
291        public void firePropertyChange(String propertyName, double oldValue,
292            double newValue) {
293        }
294    
295        /**
296         * Overridden for performance reasons.
297         */
298        public void firePropertyChange(String propertyName, boolean oldValue,
299            boolean newValue) {
300        }
301    }