001    package util.swing;
002    
003    import javax.swing.*;
004    import javax.swing.event.*;
005    import javax.swing.table.*;
006    import java.awt.Dimension;
007    
008    import data.Value;
009    import data.NumberValue;
010    
011    import resource.util.ResourceManager;
012    
013    /**
014     * A {@link JTable} that prefers models that are lists of records. A <code>JAbstractTable</code> always must
015     * be used together with an {@link util.swing.AbstractTableModel}.
016     *
017     * <p>Also <code>JAbstractTable</code> supports one selection observer which is basically an int value that
018             * will always contain the index of the currently selected record in the table. Setting up such an observer is
019     * quite straightforward:</p>
020     *
021     * <pre>
022     * int[] anSelection = new int[1];
023     *
024     * JAbstractTable jat = new JAbstractTable (...);
025     * jat.{@link #setSelectionObserver setSelectionObserver} (anSelection);
026     * </pre>
027     *
028     * <p>To use this observer write code like the following:</p>
029     *
030     * <pre>
031     * ...
032     * Object oSelectedRecord = ((util.swing.AbstractTableModel) jat.getModel()).getRecord (anSelection[0]);
033     * if (oSelectedRecord != null) {
034     *   ...
035     * }
036     * </pre>
037     *
038     * <p>Note that although you only use the actual int value, you still have to set up an array of int values.
039     * The current selection will always be written to the first element in this array, no matter how long the
040     * actual array is.</p>
041     *
042     * <p><b>Note:</b> This class is not meant to be serialized!</p>
043     *
044     * @author Steffen Zschaler
045     * @version 2.0 28/07/1999
046     * @since v2.0
047     *
048     * @see util.swing.AbstractTableModel
049     * @see TableEntryDescriptor
050     */
051    public class JAbstractTable extends JTable {
052    
053        /**
054             * ID for serialization.
055             */
056            private static final long serialVersionUID = -8313046263856698229L;
057    
058            /**
059         * The current selection observer.
060         *
061         * @serial This class is not meant to be serialized!
062         */
063        private int[] m_anSelection;
064    
065        /**
066         * The monitor that synchronizes access to the selection observer. As this class is not meant to be
067         * serialized, no care needs to be taken.
068         */
069        private final transient Object m_oSelectionLock = new Object();
070    
071        /**
072         * Holds the currently selected Column in Header
073         */
074        private Object[] m_aoSelectedColumn = new Object[2];
075    
076        /**
077         * The current {@link util.swing.AbstractTableModel}
078         */
079        private AbstractTableModel atm;
080    
081        /**
082         * Creates the TableHeader and enables it to display sorting icons (arrows up and down)
083         */
084        public DefaultTableCellRenderer createHeader() {
085            return new DefaultTableCellRenderer() {
086                            private static final long serialVersionUID = -6074623494188498875L;
087    
088                            public java.awt.Component getTableCellRendererComponent(JTable table, Object value,
089                        boolean isSelected, boolean hasFocus, int row, int column) {
090    
091                    JLabel label = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
092                            row, column);
093                    label.setBorder(new javax.swing.border.EtchedBorder());
094                    label.setHorizontalAlignment(JLabel.CENTER);
095                    label.setPreferredSize(new Dimension(0, 20));
096                    label.setBackground(java.awt.Color.lightGray);
097                    label.setFont(new java.awt.Font("SansSerif", java.awt.Font.BOLD, 12));
098                    if (m_aoSelectedColumn[0] != null) {
099                        if (column == ((Integer)m_aoSelectedColumn[0]).intValue()) {
100                            if (((Boolean)m_aoSelectedColumn[1]).booleanValue()) {
101                                setIcon(DOWN);
102                            } else {
103                                setIcon(UP);
104                            }
105                        } else {
106                            setIcon(null);
107                        }
108                    }
109    
110                    setValue(value.toString());
111                    return label;
112                }
113            };
114        }
115    
116        /**
117         * Construct a new JAbstractTable that is based on an {@link util.swing.AbstractTableModel}.
118         *
119         * @param atm the TableModel to be used with this table.
120         */
121        public JAbstractTable(AbstractTableModel atm) {
122            super();
123            this.atm = atm;
124            getTableHeader().setReorderingAllowed(false);
125    
126            TableSorter sorter = new TableSorter(atm);
127            sorter.addMouseListenerToHeaderInTable(this, m_aoSelectedColumn);
128            setModel(sorter);
129    
130            // Rendering the TableHeader
131            getTableHeader().setDefaultRenderer(createHeader());
132    
133            setDefaultRenderer(String.class, new DefaultTableCellRenderer());
134            setDefaultRenderer(Value.class, new DefaultTableCellRenderer());
135    
136            TableCellRenderer tcr = new DefaultTableCellRenderer();
137            ((JLabel)tcr).setHorizontalAlignment(JLabel.RIGHT);
138    
139            setDefaultRenderer(NumberValue.class, tcr);
140    
141            setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
142    
143            m_anSelection = new int[] {
144                     -1};
145            getSelectionModel().addListSelectionListener(new ListSelectionListener() {
146                public void valueChanged(ListSelectionEvent lse) {
147                    synchronized (m_oSelectionLock) {
148                        m_anSelection[0] = getSelectedRow();
149                    }
150                }
151            });
152    
153            TableEntryDescriptor ted = atm.getEntryDescriptor();
154            TableColumnModel tcm = getColumnModel();
155    
156            for (int i = 0; i < ted.getColumnCount(); i++) {
157                TableColumn tc = tcm.getColumn(i);
158    
159                tc.setCellRenderer(ted.getCellRenderer(i));
160                tc.setCellEditor(ted.getCellEditor(i));
161            }
162    
163        }
164    
165        public void initialize() {
166            m_aoSelectedColumn = new Object[2];
167            getTableHeader().setDefaultRenderer(createHeader());
168            ((TableSorter)getModel()).addMouseListenerToHeaderInTable(this, m_aoSelectedColumn);
169    
170            TableEntryDescriptor ted = atm.getEntryDescriptor();
171            TableColumnModel tcm = getColumnModel();
172    
173            for (int i = 0; i < ted.getColumnCount(); i++) {
174                TableColumn tc = tcm.getColumn(i);
175    
176                tc.setCellRenderer(ted.getCellRenderer(i));
177                tc.setCellEditor(ted.getCellEditor(i));
178            }
179        }
180    
181        /**
182         * Set a selection observer for this table. The first element of the given array will henceforward
183         * contain the index of the currently selected record.
184         *
185         * @param anSelection the selection observer
186         *
187         * @override Never
188         */
189        public void setSelectionObserver(int[] anSelection) {
190            synchronized (m_oSelectionLock) {
191                anSelection[0] = getSelectedRow();
192                m_anSelection = anSelection;
193            }
194        }
195    
196        /**
197         * Icon "Down"
198         */
199        private static final ImageIcon DOWN = new ImageIcon(ResourceManager.getInstance().getResource(
200                ResourceManager.RESOURCE_GIF, "icon.icon_down_16x16"));
201    
202        /**
203         * Icon "Up"
204         */
205        private static final ImageIcon UP = new ImageIcon(ResourceManager.getInstance().getResource(
206                ResourceManager.RESOURCE_GIF, "icon.icon_up_16x16"));
207        
208        /**
209         * return the {@link util.swing.AbstractTableModel}
210         * @return atm the current AbstractTableModel
211         */
212        public AbstractTableModel getAbstractTableModel() {
213            return atm;
214        }
215    }