001: package org.acm.seguin.pmd.swingui;
002:
003: import org.acm.seguin.pmd.swingui.event.DirectoryTableEvent;
004: import org.acm.seguin.pmd.swingui.event.DirectoryTableEventListener;
005: import org.acm.seguin.pmd.swingui.event.ListenerList;
006:
007: import javax.swing.JLabel;
008: import javax.swing.JTable;
009: import javax.swing.ListSelectionModel;
010: import javax.swing.SwingConstants;
011: import javax.swing.UIManager;
012: import javax.swing.border.BevelBorder;
013: import javax.swing.border.Border;
014: import javax.swing.border.CompoundBorder;
015: import javax.swing.border.EtchedBorder;
016: import javax.swing.event.ListSelectionEvent;
017: import javax.swing.event.ListSelectionListener;
018: import javax.swing.table.DefaultTableCellRenderer;
019: import javax.swing.table.JTableHeader;
020: import javax.swing.table.TableColumn;
021: import javax.swing.table.TableColumnModel;
022: import java.awt.Color;
023: import java.awt.Component;
024: import java.awt.Font;
025: import java.awt.Point;
026: import java.awt.Rectangle;
027: import java.awt.event.MouseAdapter;
028: import java.awt.event.MouseEvent;
029: import java.io.File;
030: import java.util.Arrays;
031: import java.util.Comparator;
032: import java.util.Vector;
033:
034: /**
035: *
036: * @author Donald A. Leckie
037: * @since August 25, 2002
038: * @version $Revision: 1.1 $, $Date: 2003/07/29 20:51:59 $
039: */
040: class DirectoryTable extends JTable {
041:
042: private boolean m_sortAscending = true;
043:
044: /**
045: ********************************************************************************
046: *
047: * @param directoryTree
048: */
049: protected DirectoryTable(DirectoryTree directoryTree,
050: String fileExtension) {
051: super (new DirectoryTableModel(directoryTree, fileExtension));
052:
053: setShowGrid(false);
054: setRowSelectionAllowed(false);
055: setColumnSelectionAllowed(false);
056: setCellSelectionEnabled(true);
057: getSelectionModel().setSelectionMode(
058: ListSelectionModel.SINGLE_SELECTION);
059: setBackground(UIManager.getColor("pmdTableBackground"));
060: setRowHeight(20);
061: setSelectionBackground(Color.blue);
062: setSelectionForeground(Color.white);
063: getSelectionModel().addListSelectionListener(
064: new ListSelectionHandler());
065:
066: TableColumnModel columnModel = getColumnModel();
067: JTableHeader tableHeader = getTableHeader();
068:
069: columnModel.setColumnMargin(2);
070: tableHeader.addMouseListener(new TableHeaderMouseListener());
071:
072: //
073: // Create the column renderers.
074: //
075: ColumnHeaderRenderer headerRenderer;
076: DefaultTableCellRenderer cellRenderer;
077: TableColumn column;
078:
079: //
080: // Create renderers for the file name column.
081: //
082: column = columnModel
083: .getColumn(DirectoryTableModel.FILE_NAME_COLUMN);
084: headerRenderer = new ColumnHeaderRenderer();
085: cellRenderer = new DefaultTableCellRenderer();
086:
087: cellRenderer.setIcon(UIManager.getIcon("document"));
088: headerRenderer.setHorizontalAlignment(JLabel.LEFT);
089: column.setHeaderRenderer(headerRenderer);
090: cellRenderer.setHorizontalAlignment(JLabel.LEFT);
091: column.setCellRenderer(cellRenderer);
092:
093: //
094: // Create a cell renderer for the file size column.
095: //
096: column = columnModel
097: .getColumn(DirectoryTableModel.FILE_SIZE_COLUMN);
098: headerRenderer = new ColumnHeaderRenderer();
099: cellRenderer = new DefaultTableCellRenderer();
100:
101: headerRenderer.setHorizontalAlignment(JLabel.RIGHT);
102: column.setHeaderRenderer(headerRenderer);
103: cellRenderer.setHorizontalAlignment(JLabel.RIGHT);
104: column.setCellRenderer(cellRenderer);
105:
106: //
107: // Create a cell renderer for the file last modified date column.
108: //
109: column = columnModel
110: .getColumn(DirectoryTableModel.FILE_LAST_MODIFIED_COLUMN);
111: headerRenderer = new ColumnHeaderRenderer();
112: cellRenderer = new DefaultTableCellRenderer();
113:
114: headerRenderer.setHorizontalAlignment(JLabel.LEFT);
115: column.setHeaderRenderer(headerRenderer);
116: cellRenderer.setHorizontalAlignment(JLabel.LEFT);
117: column.setCellRenderer(cellRenderer);
118:
119: //
120: // Listeners
121: //
122: ListenerList
123: .addListener((DirectoryTableEventListener) new DirectoryTableEventHandler());
124: }
125:
126: /**
127: ********************************************************************************
128: *
129: * @return
130: */
131: protected File getSelectedFile() {
132: ListSelectionModel selectionModel = getSelectionModel();
133: int row = selectionModel.getAnchorSelectionIndex();
134: DirectoryTableModel tableModel = (DirectoryTableModel) getModel();
135:
136: return tableModel.getFile(row);
137: }
138:
139: /**
140: ********************************************************************************
141: ********************************************************************************
142: ********************************************************************************
143: */
144: private class ColumnHeaderRenderer extends DefaultTableCellRenderer {
145:
146: private Font m_boldFont;
147: private Border m_border;
148: private Color m_background;
149: private Color m_foreground;
150:
151: /**
152: *********************************************************************************
153: *
154: */
155: protected ColumnHeaderRenderer() {
156: super ();
157:
158: Font oldFont;
159: BevelBorder bevelBorder;
160: EtchedBorder etchedBorder;
161:
162: oldFont = getFont();
163: m_boldFont = new Font(oldFont.getName(), Font.BOLD, oldFont
164: .getSize());
165: bevelBorder = new BevelBorder(BevelBorder.RAISED);
166: etchedBorder = new EtchedBorder(EtchedBorder.RAISED);
167: m_border = new CompoundBorder(etchedBorder, bevelBorder);
168: m_background = UIManager
169: .getColor("pmdTableHeaderBackground");
170: m_foreground = UIManager
171: .getColor("pmdTableHeaderForeground");
172: }
173:
174: /**
175: *********************************************************************************
176: *
177: * @param table
178: * @param value
179: * @param isSelected
180: * @param hasFocus
181: * @param row
182: * @param column
183: *
184: * @return
185: */
186: public Component getTableCellRendererComponent(JTable table,
187: Object value, boolean isSelected, boolean hasFocus,
188: int row, int column) {
189: super .getTableCellRendererComponent(table, value,
190: isSelected, hasFocus, row, column);
191:
192: setFont(m_boldFont);
193: setBorder(m_border);
194: setBackground(m_background);
195: setForeground(m_foreground);
196: setHorizontalAlignment(SwingConstants.CENTER);
197:
198: return this ;
199: }
200: }
201:
202: /**
203: ********************************************************************************
204: ********************************************************************************
205: ********************************************************************************
206: */
207: private class TableHeaderMouseListener extends MouseAdapter {
208:
209: /**
210: ****************************************************************************
211: *
212: * @param event
213: */
214: public void mouseReleased(MouseEvent event) {
215: int sortColumn;
216: JTableHeader tableHeader;
217: Point mouseLocation;
218: Rectangle columnHeaderArea;
219:
220: m_sortAscending = !m_sortAscending;
221: mouseLocation = event.getPoint();
222: tableHeader = getTableHeader();
223: sortColumn = tableHeader.columnAtPoint(mouseLocation);
224:
225: if (sortColumn >= 0) {
226: // When the cursor is resizing a column, the mouse released event will
227: // reach here. To prevent sorting happening during resizing, the column
228: // header area is inset on the left and right by 10 pixels each.
229: columnHeaderArea = tableHeader
230: .getHeaderRect(sortColumn);
231: columnHeaderArea.x -= 10;
232: columnHeaderArea.width -= 20;
233:
234: if (columnHeaderArea.contains(mouseLocation)) {
235: sort(sortColumn, m_sortAscending);
236: }
237: }
238: }
239:
240: /**
241: ****************************************************************************
242: *
243: * @param sortColumn
244: */
245: protected void sort(int sortColumn, boolean sortAscending) {
246: TableSortComparator comparator;
247: DirectoryTableModel tableModel;
248: Vector tableData;
249: int rowCount;
250: Vector[] rows;
251:
252: comparator = new TableSortComparator(sortColumn,
253: sortAscending);
254: tableModel = (DirectoryTableModel) getModel();
255: tableData = tableModel.getDataVector();
256: rowCount = tableData.size();
257: rows = new Vector[rowCount];
258: rows = (Vector[]) tableData.toArray(rows);
259:
260: Arrays.sort(rows, comparator);
261:
262: for (int n = 0; n < rowCount; n++) {
263: tableData.set(n, rows[n]);
264: }
265:
266: tableModel.fireTableDataChanged();
267: }
268: }
269:
270: /**
271: ********************************************************************************
272: ********************************************************************************
273: ********************************************************************************
274: */
275: private class TableSortComparator implements Comparator {
276:
277: private int m_sortColumn;
278: private boolean m_sortAscending;
279:
280: /**
281: ****************************************************************************
282: *
283: * @param sortColumn
284: * @param sortAscending
285: */
286: private TableSortComparator(int sortColumn,
287: boolean sortAscending) {
288: m_sortColumn = sortColumn;
289: m_sortAscending = sortAscending;
290: }
291:
292: /**
293: ****************************************************************************
294: *
295: * @param keyA
296: * @param keyB
297: *
298: * @int result
299: */
300: public int compare(Object rowA, Object rowB) {
301: String keyA = (String) ((Vector) rowA).get(m_sortColumn);
302: String keyB = (String) ((Vector) rowB).get(m_sortColumn);
303:
304: if (m_sortAscending) {
305: return keyA.compareTo(keyB);
306: }
307:
308: return keyB.compareTo(keyA);
309: }
310:
311: /**
312: ****************************************************************************
313: *
314: * @param object
315: */
316: public boolean equals(Object object) {
317: return (object == this );
318: }
319: }
320:
321: /**
322: ********************************************************************************
323: ********************************************************************************
324: ********************************************************************************
325: */
326: private class ListSelectionHandler implements ListSelectionListener {
327:
328: /**
329: ****************************************************************************
330: *
331: * @param event
332: */
333: public void valueChanged(ListSelectionEvent event) {
334: // Swing may generate a change event more than once. All change events, except
335: // the last event, will have the "value is adjusting" flag set true. We want only
336: // the last event.
337: if (event.getValueIsAdjusting() == false) {
338: File file = getSelectedFile();
339:
340: if (file != null) {
341: DirectoryTableEvent.notifyFileSelectionChanged(
342: this , file);
343: }
344: }
345: }
346: }
347:
348: /**
349: ********************************************************************************
350: ********************************************************************************
351: ********************************************************************************
352: */
353: private class DirectoryTableEventHandler implements
354: DirectoryTableEventListener {
355:
356: /**
357: ******************************************************************************
358: *
359: * @param event
360: */
361: public void requestSelectedFile(DirectoryTableEvent event) {
362: File file = getSelectedFile();
363:
364: if (file != null) {
365: DirectoryTableEvent.notifySelectedFile(this , file);
366: }
367: }
368:
369: /**
370: ******************************************************************************
371: *
372: * @param event
373: */
374: public void fileSelectionChanged(DirectoryTableEvent event) {
375:
376: }
377:
378: /**
379: ******************************************************************************
380: *
381: * @param event
382: */
383: public void fileSelected(DirectoryTableEvent event) {
384: }
385: }
386: }
|