001: /*
002: * SwingML Copyright (C) 2002 Ezequiel Cuellar.
003: *
004: * This library is free software; you can redistribute it and/or modify it under
005: * the terms of the GNU Lesser General Public License as published by the Free
006: * Software Foundation; either version 2 of the License, or (at your option) any
007: * later version.
008: *
009: * This library is distributed in the hope that it will be useful, but WITHOUT
010: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011: * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012: * details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with this library; if not, write to the Free Software Foundation, Inc.,
016: * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: *
018: * Authors: Ezequiel Cuellar <ecuellar@crosslogic.com>
019: *
020: */
021: package org.swingml.tablebrowser.ext;
022:
023: import java.awt.*;
024: import java.util.*;
025: import java.util.List;
026:
027: import javax.swing.*;
028: import javax.swing.event.*;
029: import javax.swing.table.*;
030:
031: import org.swingml.*;
032: import org.swingml.system.*;
033: import org.swingml.tablebrowser.rowheader.*;
034: import org.swingml.view.*;
035:
036: public class TableBrowserRenderer extends RendererUtil implements
037: org.swingml.view.Renderer {
038:
039: private class SelectionListener implements ListSelectionListener {
040:
041: private JTable header;
042: private JTable table;
043: private boolean updating = false;
044:
045: SelectionListener(JTable aTable, JTable rowHeader) {
046: this .table = aTable;
047: this .header = rowHeader;
048: }
049:
050: private void deselectRow(ListSelectionModel source, int row) {
051: source.removeSelectionInterval(row, row);
052: }
053:
054: private void selectRow(ListSelectionModel source, int row) {
055: source.addSelectionInterval(row, row);
056: }
057:
058: private void toggleRows(ListSelectionModel source,
059: ListSelectionModel target, int first, int last) {
060: // System.out.println("selecting rows:" + first + " to " + last);
061: if (source != null && target != null) {
062: // loop through selections and add/remove them as necessary
063: for (int x = first; x <= last; x++) {
064: if (source.isSelectedIndex(x)) {
065: selectRow(target, x);
066: } else {
067: deselectRow(target, x);
068: }
069: }
070: }
071: }
072:
073: public void valueChanged(ListSelectionEvent e) {
074: if (!updating) {
075: updating = true;
076: int first = e.getFirstIndex();
077: int last = e.getLastIndex();
078:
079: ListSelectionModel local = table.getSelectionModel();
080: ListSelectionModel remote = header.getSelectionModel();
081: if (e.getSource().equals(header.getSelectionModel())) {
082: local = header.getSelectionModel();
083: remote = table.getSelectionModel();
084: }
085:
086: if (e.getSource().equals(header.getSelectionModel())
087: && table.getCellSelectionEnabled()) {
088: if (table.getSelectedRow() != -1) {
089: toggleRows(local, remote, first, last);
090: } else {
091: deselectRow(header.getSelectionModel(), header
092: .getSelectedRow());
093: }
094: } else {
095: toggleRows(local, remote, first, last);
096: }
097: updating = false;
098: }
099: }
100: }
101:
102: private void applyColumnEditors(TableBrowserComponent table,
103: TableBrowserModel model) {
104: for (int i = 0; i < model.getColumnCount(); i++) {
105: TableBrowserColumnModel m = (TableBrowserColumnModel) model
106: .getColumns().get(i);
107: if (m.getCustomEditor() != null) {
108: table.setColumnEditor(i, m.getCustomEditor());
109: }
110: }
111: }
112:
113: private void applyColumnOrder(TableBrowserComponent component,
114: TableBrowserModel model) {
115: List columns = model.getColumns();
116: for (int index = 0; index < columns.size(); index++) {
117: TableBrowserColumnModel columnModel = (TableBrowserColumnModel) columns
118: .get(index);
119: String columnName = columnModel.getText();
120: int currentIndex = component.getColumnModel()
121: .getColumnIndex(columnName);
122: if (columnModel.getColumnOrder() >= 0) {
123: component.getColumnModel().moveColumn(currentIndex,
124: columnModel.getColumnOrder());
125: } else if (currentIndex != index) {
126: component.getColumnModel().moveColumn(currentIndex,
127: columns.size() - 1);
128: }
129: }
130: }
131:
132: private void applyColumnWidths(TableBrowserComponent component,
133: TableBrowserModel model) {
134: List columns = model.getColumns();
135: if (model != null) {
136: if (model.isAutoFit()) {
137:
138: TableBrowserColumnModel columnModel = null;
139: // iterate over all columns
140: for (int column = 0; column < columns.size(); column++) {
141: columnModel = (TableBrowserColumnModel) columns
142: .get(column);
143: // is column hidden? if so, skip and set to zero.
144: if (!columnModel.isHidden()
145: && columnModel.getWidth() > 0) {
146: int cellWidth = 0;
147: // iterate over all rows
148: for (int row = 0; row < component.getRowCount(); row++) {
149: // get this row's rendered component.
150: Object value = component.getValueAt(row,
151: column);
152: TableCellRenderer renderer = component
153: .getCellRenderer(row, column);
154: Component cell = renderer
155: .getTableCellRendererComponent(
156: component, value, false,
157: false, row, column);
158:
159: // get the component's preffered width.
160: double currentWidth = cell
161: .getPreferredSize().getWidth();
162: cellWidth = (int) Math.max(cellWidth,
163: currentWidth);
164: }
165:
166: // compare to the column's header label preffered width.
167: TableColumn tableColumn = component
168: .getColumnModel().getColumn(column);
169: TableCellRenderer headerRenderer = tableColumn
170: .getHeaderRenderer();
171: Component headerLabel = headerRenderer
172: .getTableCellRendererComponent(
173: component, tableColumn
174: .getHeaderValue(),
175: false, false, 0, column);
176: cellWidth = (int) Math.max(cellWidth,
177: headerLabel.getPreferredSize()
178: .getWidth());
179:
180: // compare to the width set in the model.
181: int customWidth = columnModel.getWidth();
182: cellWidth = Math.max(customWidth, cellWidth);
183:
184: // now set the width for this column
185: if (cellWidth == 0) {
186: component.setColumnWidth(column,
187: columnModel.getWidth());
188: } else {
189: component.setColumnWidth(column, cellWidth);
190: }
191: } else {
192: component.setColumnWidth(column, 0);
193: }
194: }
195:
196: } else {
197: // apply column widths normally (from the model)
198: for (int column = 0; column < columns.size(); column++) {
199: TableBrowserColumnModel columnModel = (TableBrowserColumnModel) columns
200: .get(column);
201: if (columnModel.isHidden()) {
202: component.setColumnWidth(column, 0);
203: } else {
204: component.setColumnWidth(column, columnModel
205: .getWidth());
206: }
207: }
208:
209: }
210: }
211: }
212:
213: private void applyDefaultSortOrder(TableBrowserComponent theComp,
214: TableBrowserModel theModel) {
215: TreeMap map = new TreeMap();
216: List columns = theModel.getColumns();
217: TableBrowserColumnModel theColumnModel = null;
218: for (int i = 0; i < columns.size(); i++) {
219: theColumnModel = (TableBrowserColumnModel) columns.get(i);
220: if (theColumnModel.getSortOrder() > 0) {
221: int type = theColumnModel.getSortType() == 0 ? 1 : -1;
222: map.put(new Integer(theColumnModel.getSortOrder()),
223: new Integer(i * type));
224: }
225: }
226: if (map.size() > 0) {
227: Iterator itr = map.values().iterator();
228: while (itr.hasNext()) {
229: Integer col = (Integer) itr.next();
230: // add default sort to browser
231: theComp.getBrowser().getSort().addColumn(
232: Math.abs(col.intValue()));
233: if (col.intValue() < 0) {
234: theComp.getBrowser().getSort().setSortDirection(
235: col.intValue() * -1);
236: }
237: }
238: }
239: }
240:
241: public Container render(AbstractSwingMLModel aModel,
242: Container aParent) {
243: TableBrowserModel theModel = (TableBrowserModel) aModel;
244: TableBrowserComponent theTable = new TableBrowserComponent(
245: theModel);
246:
247: new TableBrowserCellLabelDecorator(theTable);
248: new TableBrowserCellIconDecorator(theTable);
249:
250: // apply default sort order(s)
251: applyDefaultSortOrder(theTable, theModel);
252: applyColumnEditors(theTable, theModel);
253: theTable.refresh();
254: applyColumnWidths(theTable, theModel);
255: applyColumnOrder(theTable, theModel);
256:
257: JScrollPane theScroll = new JScrollPane(theTable);
258: if (theModel.getWidth() > 0 && theModel.getHeight() > 0) {
259: Dimension d = new Dimension(theModel.getWidth(), theModel
260: .getHeight());
261: theScroll.setPreferredSize(d);
262: }
263: String theOrientation = theModel.getOrientation();
264: if (theOrientation != null) {
265: aParent.add(theScroll, theOrientation);
266: } else {
267: aParent.add(theScroll);
268: }
269:
270: if (theModel.isRowHeaderVisible()) {
271: // create row header data
272: RowHeaderTableModel rowHeaderData = new RowHeaderTableModel(
273: 0, 1);
274: for (int x = 1; x <= theTable.getRowCount(); x++) {
275: // create row labels
276: rowHeaderData.addRow(new Object[] { x + "" });
277: }
278:
279: // create the table and set selection mode/colors/sizes
280: RowHeaderTable rowHeader = new RowHeaderTable(theTable,
281: rowHeaderData);
282: rowHeader.setSelectionMode(theTable.getSelectionModel()
283: .getSelectionMode());
284: setupSelectionListener(theTable, rowHeader);
285:
286: LookAndFeel.installColorsAndFont(rowHeader,
287: "TableHeader.background", "TableHeader.foreground",
288: "TableHeader.font");
289: rowHeader.setIntercellSpacing(new Dimension(0, 0));
290: Dimension size = rowHeader
291: .getPreferredScrollableViewportSize();
292: int width = SwingMLTextUtilities.getStringWidth(theTable
293: .getRowCount()
294: + "");
295: size.width = width + 7;
296: rowHeader.setPreferredScrollableViewportSize(size);
297: rowHeader.setRowHeight(theTable.getRowHeight());
298: rowHeader.setDefaultRenderer(Object.class,
299: new RowHeaderRenderer());
300: theScroll.setRowHeaderView(rowHeader);
301:
302: JTableHeader corner = rowHeader.getTableHeader();
303: corner.setReorderingAllowed(false);
304: corner.setResizingAllowed(false);
305: theScroll.setCorner(JScrollPane.UPPER_LEFT_CORNER, corner);
306:
307: new RowHeaderScrollPaneAdjuster(theScroll);
308: new RowHeaderResizer(theScroll).setEnabled(true);
309:
310: theTable.setRowHeaderTable(rowHeader);
311: }
312: if (theModel.hasStartEditCell()) {
313: theTable.setColumnSelectionInterval(theTable
314: .convertColumnIndexToView(theModel
315: .getStartEditCellColumn()), theTable
316: .convertColumnIndexToView(theModel
317: .getStartEditCellColumn()));
318: theTable.setRowSelectionInterval(theModel
319: .getStartEditCellRow(), theModel
320: .getStartEditCellRow());
321: theTable.editCellAt(theModel.getStartEditCellRow(),
322: theTable.convertColumnIndexToView(theModel
323: .getStartEditCellColumn()));
324: }
325:
326: // CellEditorManager
327: String managerClassName = theModel.getCellManager();
328: if (managerClassName != null
329: && managerClassName.trim().length() > 0) {
330: try {
331: Class managerClass = Class.forName(managerClassName);
332: Object manager = managerClass.newInstance();
333: if (manager instanceof ITableBrowserCellNavigationManager) {
334: final ITableBrowserCellNavigationManager cellEditorManager = (ITableBrowserCellNavigationManager) manager;
335: theTable.applylCellManager(cellEditorManager);
336: theTable.setSurrendersFocusOnKeystroke(true);
337: }
338: } catch (ClassNotFoundException e) {
339: SwingMLLogger.getInstance().log(
340: SwingMLLogger.ERROR,
341: "Unable to locate custom TableBrowserCellEditorManager class ("
342: + theModel.getCellManager() + ") for "
343: + theModel.getName());
344: } catch (InstantiationException e) {
345: SwingMLLogger.getInstance().log(
346: SwingMLLogger.ERROR,
347: "Unable to instantiate custom TableBrowserCellEditorManager class ("
348: + theModel.getCellManager() + ") for "
349: + theModel.getName());
350: SwingMLLogger.getInstance().log(SwingMLLogger.ERROR, e);
351: } catch (IllegalAccessException e) {
352: SwingMLLogger.getInstance().log(SwingMLLogger.ERROR, e);
353: }
354: }
355:
356: super .iterate(theModel, theTable);
357:
358: return theTable;
359: }
360:
361: private void setupSelectionListener(JTable table, JTable rowHeader) {
362: SelectionListener listener = new SelectionListener(table,
363: rowHeader);
364: table.getSelectionModel().addListSelectionListener(listener);
365: rowHeader.getSelectionModel()
366: .addListSelectionListener(listener);
367: rowHeader.addMouseListener((TableBrowserComponent) table);
368: }
369:
370: }
|