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