001    package nl.cwi.sen1.visplugin.table.model;
002    
003    import javax.swing.table.DefaultTableModel;
004    
005    import nl.cwi.sen1.relationstores.types.IdCon;
006    import nl.cwi.sen1.relationstores.types.RElem;
007    import nl.cwi.sen1.relationstores.types.RElemElements;
008    import nl.cwi.sen1.relationstores.types.RTuple;
009    import nl.cwi.sen1.relationstores.types.RType;
010    import nl.cwi.sen1.relationstores.types.RTypeColumnTypes;
011    
012    /**
013     * Table model supporting column sortings. This model is able to work directly
014     * with RTuples and its data should be set using the setRTupleData() function.
015     * The original RElems can then be retrieved for every table row using the
016     * getRElemForRow() function.
017     * 
018     * @author Anton Gerdessen
019     * @date 12-03-2007
020     */
021    public class SortableTableModel extends DefaultTableModel {
022    
023            private static final long serialVersionUID = 1L;
024    
025            private int[] m_indexes;
026    
027            private TableSorter m_sorter;
028    
029            private RTuple m_data;
030    
031            private IdCon m_rTupleVariable;
032    
033            private RType m_rTupleRType;
034    
035            public SortableTableModel() {
036                    super();
037    
038                    m_data = null;
039            }
040    
041            /**
042             * Retrieve the value for a given postion (row,col).
043             * 
044             * @param row
045             *            The (row,col) combination
046             * @param col
047             *            The (row,col) combination
048             * @author Anton Gerdessen
049             * @date 12-03-2007
050             */
051            public Object getValueAt(int row, int col) {
052                    int rowIndex = row;
053                    if (m_indexes != null) {
054                            rowIndex = m_indexes[row];
055                    }
056                    return super.getValueAt(rowIndex, col);
057            }
058    
059            /**
060             * Set the value for a given postion (row,col).
061             * 
062             * @param value
063             *            The value to set at the (row,col) combination
064             * @param row
065             *            The (row,col) combination
066             * @param col
067             *            The (row,col) combination
068             * @author Anton Gerdessen
069             * @date 12-03-2007
070             */
071            public void setValueAt(Object value, int row, int col) {
072                    int rowIndex = row;
073                    if (m_indexes != null) {
074                            rowIndex = m_indexes[row];
075                    }
076                    super.setValueAt(value, rowIndex, col);
077            }
078    
079            /**
080             * Retrieve the value for a given postion (row,col).
081             * 
082             * @param column
083             *            the column to base the sort on
084             * @param isAscent
085             *            ascending (true) or or decending (false) order
086             * @author Anton Gerdessen
087             * @date 12-03-2007
088             */
089            public void sortByColumn(int column, boolean isAscent) {
090                    if (m_sorter == null) {
091                            m_sorter = new TableSorter(this);
092                    }
093                    m_sorter.sort(column, isAscent);
094                    fireTableDataChanged();
095            }
096    
097            /**
098             * Returns the index mapping on which the current sort is based.
099             * 
100             * @return The index mapping as an array.
101             * 
102             * @author Anton Gerdessen
103             * @date 12-03-2007
104             */
105            public int[] getIndexes() {
106                    int n = getRowCount();
107                    if (m_indexes != null) {
108                            if (m_indexes.length == n) {
109                                    return m_indexes;
110                            }
111                    }
112                    m_indexes = new int[n];
113                    for (int i = 0; i < n; i++) {
114                            m_indexes[i] = i;
115                    }
116                    return m_indexes;
117            }
118    
119            /**
120             * Return the type which is displayed in the given column.
121             * 
122             * @param column
123             *            The column to retrieve the type from
124             * @author Anton Gerdessen
125             * @date 12-03-2007
126             */
127            @SuppressWarnings("unchecked")
128            public Class getColumnClass(int column) {
129                    // Retrieve the first item of the column and base the type on that.
130                    return getValueAt(0, column).getClass();
131            }
132    
133            /**
134             * Sets the data of the table model to the data contained in the RTuple.
135             * 
136             * @param data
137             *            The RTuple data to put in the table.
138             * 
139             */
140            public void setRTupleData(RTuple data) {
141                    try {
142                            m_rTupleVariable = data.getVariable();
143                            m_rTupleRType = data.getRtype();
144                            RElem value = data.getValue();
145                            Object[][] dataVector = null;
146                            String[] columnIdentifiers = null;
147    
148                            if (value.isBool() || value.isInt() || value.isLoc()
149                                            || value.isStr()) {
150                                    columnIdentifiers = new String[] { "value" };
151                                    dataVector = new Object[1][1];
152                                    dataVector[0][0] = getValueFromRElem(value);
153                            } else if (value.isSet() || value.isBag()) {
154                                    if (m_rTupleRType.hasColumnTypes()) {
155                                            RElemElements es = value.getElements();
156                                            RTypeColumnTypes columnTypes = m_rTupleRType
157                                                            .getColumnTypes();
158                                            columnIdentifiers = convertColumnTypesToStrings(columnTypes);
159    
160                                            int numRows = es.getLength();
161                                            int numColumns = columnTypes.getLength();
162    
163                                            // copies each of the values of the RTuple to the dataVector
164                                            dataVector = new Object[numRows][numColumns];
165                                            for (int r = 0; !es.isEmpty(); es = es.getTail(), r++) {
166                                                    RElem tuple = es.getHead();
167                                                    RElemElements fs = tuple.getElements();
168    
169                                                    for (int c = 0; !fs.isEmpty(); fs = fs.getTail(), c++) {
170                                                            RElem elem = fs.getHead();
171                                                            dataVector[r][c] = getValueFromRElem(elem);
172                                                    }
173                                            }
174                                    } else if (value.hasElements()) {
175                                            RElemElements es = value.getElements();
176                                            dataVector = new Object[es.getLength()][1];
177                                            columnIdentifiers = new String[] { "values" };
178    
179                                            for (int i = 0; !es.isEmpty(); es = es.getTail(), i++) {
180                                                    RElem val = es.getHead();
181                                                    dataVector[i][0] = getValueFromRElem(val);
182                                            }
183                                    } else {
184                                            System.err
185                                                            .println("Apparently forgot to implement mapping for "
186                                                                            + m_rTupleRType.toTerm().toString());
187                                    }
188                            } else {
189                                    System.err
190                                                    .println("Apparently forgot to implement mapping for "
191                                                                    + m_rTupleRType.toTerm().toString());
192                                    return;
193                            }
194    
195                            setDataVector(dataVector, columnIdentifiers);
196                            m_data = data;
197                    } catch (Exception exception) {
198                            System.err.print(exception.getMessage());
199                            exception.printStackTrace();
200                    }
201            }
202    
203            /**
204             * Returns the variable of the set RTuple data.
205             * 
206             * @return The RTuple variable.
207             * 
208             * @sa setRTupleData()
209             * 
210             * @author Anton Gerdessen
211             * @author Arend van Beelen
212             * @data 13-03-2007
213             */
214            public IdCon getRTupleVariable() {
215                    return m_rTupleVariable;
216            }
217    
218            /**
219             * Returns the RType of the set RTuple data.
220             * 
221             * @return The RTuple RType.
222             * 
223             * @sa setRTupleData()
224             * 
225             * @author Anton Gerdessen
226             * @author Arend van Beelen
227             * @data 13-03-2007
228             */
229            public RType getRTupleRType() {
230                    return m_rTupleRType;
231            }
232    
233            /**
234             * Returns an RElem containing the data for a row.
235             * 
236             * @param rowIndex
237             *            Index of the row. If sorting is enabled, the index will
238             *            automatically adjusted.
239             * @return An RElem from the RTuple data.
240             * 
241             * @author Anton Gerdessen
242             * @author Arend van Beelen
243             * @data 13-03-2007
244             */
245            public RElem getRElemForRow(int rowIndex) {
246                    if (m_indexes != null) {
247                            rowIndex = m_indexes[rowIndex];
248                    }
249                    RElem value = m_data.getValue();
250                    RElemElements valueElements = value.getElements();
251                    return valueElements.getRElemAt(rowIndex);
252            }
253    
254            /**
255             * Converts RElem value to an object. It supports only four types (str, int,
256             * bool, loc ) now.
257             * 
258             * @param element
259             * @return Object
260             * 
261             * @exception Exception
262             *                Throws and unknown RElem exception when the element is of
263             *                an unknown type.
264             * 
265             * @author Srinivasan Tharmarajah
266             * @date 08-03-2007
267             */
268            private static Object getValueFromRElem(RElem element) throws Exception {
269                    Object value = null;
270    
271                    if (element.isStr()) {
272                            value = element.getStrCon();
273                    } else if (element.isInt()) {
274                            value = new Integer(element.getInteger().getNatCon());
275                    } else if (element.isBool()) {
276                            value = element.getBoolCon();
277                    } else if (element.isLoc()) {
278                            value = element.getLocation();
279                    } else {
280                            value = element.toTerm().toString();
281                    }
282    
283                    return value;
284            }
285    
286            /**
287             * Converts RTypeColumnTypes to an array of Strings
288             * 
289             * @param columnTypes
290             * @return
291             * @author Antoine Savelkoul
292             * @date 08-03-2007
293             */
294            private static String[] convertColumnTypesToStrings(
295                            RTypeColumnTypes columnTypes) {
296                    int numColumns = columnTypes.getLength();
297                    String[] columnNames = new String[numColumns];
298    
299                    // copies each of the type names to the array
300                    for (int columnNum = 0; columnNum < numColumns; columnNum++) {
301                            RType columnType = columnTypes.getRTypeAt(columnNum);
302                            columnNames[columnNum] = columnType.toString() + " [" + columnNum
303                                            + "]";
304                    }
305    
306                    return columnNames;
307            }
308    
309            /**
310             * Returns
311             * 
312             * @c false so that the table cells are not editable.
313             * 
314             * @param rowIndex
315             *            Row index of the cell, ignored.
316             * @param columnIndex
317             *            Column index of the cell, ignored.
318             * 
319             * @return
320             * @c false.
321             * 
322             * @author Arend van Beelen
323             * @date 12-03-2007
324             */
325            public boolean isCellEditable(int rowIndex, int columnIndex) {
326                    return false;
327            }
328    }