001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.ui.components;
042:
043: import org.netbeans.lib.profiler.ui.components.table.*;
044: import java.awt.*;
045: import java.awt.event.*;
046: import java.util.LinkedList;
047: import java.util.List;
048: import javax.swing.*;
049: import javax.swing.table.*;
050:
051: /**
052: * This class implements JTable with extended CellTip support.
053: * Added support for handling Home & End keys.
054: *
055: * @author Tomas Hurka
056: * @author Jiri Sedlacek
057: */
058: public class JExtendedTable extends JTable implements CellTipAware,
059: MouseListener, MouseMotionListener, MouseWheelListener {
060: //~ Instance fields ----------------------------------------------------------------------------------------------------------
061:
062: protected JToolTip cellTip;
063: protected Rectangle rendererRect;
064: protected int lastColumn = -1;
065: protected int lastRow = -1;
066: private String internalFindString;
067:
068: //------------------------------------
069: // Find functionality stuff
070: private String userFindString;
071: private int userFindColumn;
072:
073: //~ Constructors -------------------------------------------------------------------------------------------------------------
074:
075: public JExtendedTable(TableModel model) {
076: super (model);
077:
078: cellTip = createCellTip();
079: cellTip.setBorder(BorderFactory
080: .createLineBorder(getGridColor()));
081: cellTip.setLayout(new BorderLayout());
082:
083: initListeners();
084:
085: CellTipManager.sharedInstance().registerComponent(this );
086: }
087:
088: //~ Methods ------------------------------------------------------------------------------------------------------------------
089:
090: public JToolTip getCellTip() {
091: return cellTip;
092: }
093:
094: public Point getCellTipLocation() {
095: if (rendererRect == null) {
096: return null;
097: }
098:
099: return new Point(rendererRect.getLocation().x - 1, rendererRect
100: .getLocation().y - 1);
101: }
102:
103: public int getFindColumn() {
104: return userFindColumn;
105: }
106:
107: public boolean isFindColumnValid() {
108: return ((userFindColumn >= 0) && (userFindColumn < getColumnCount()));
109: }
110:
111: public void setFindParameters(String findString, int findColumn) {
112: userFindString = findString;
113: userFindColumn = findColumn;
114: internalFindString = getInternalFindString(userFindString);
115: }
116:
117: public String getFindString() {
118: return userFindString;
119: }
120:
121: public boolean isFindStringDefined() {
122: return ((userFindString != null) && (userFindString.trim()
123: .length() > 0));
124: }
125:
126: public void setGridColor(Color gridColor) {
127: super .setGridColor(gridColor);
128:
129: if ((gridColor == null) || (cellTip == null)) {
130: return;
131: }
132:
133: cellTip.setBorder(BorderFactory.createLineBorder(gridColor));
134: }
135:
136: public boolean canFindBePerformed() {
137: return (getRowCount() > 0) && isFindColumnValid()
138: && isFindStringDefined();
139: }
140:
141: public void ensureRowVisible(int row) {
142: scrollRectToVisible(getCellRect(row, 0, true));
143: }
144:
145: public boolean findFirst() {
146: if (!canFindBePerformed()) {
147: return false;
148: }
149:
150: if (matchesFindCriterion(0)) {
151: return selectFoundNode(0);
152: } else {
153: return doFindNext(0);
154: }
155: }
156:
157: public boolean findNext() {
158: if (!canFindBePerformed()) {
159: return false;
160: }
161:
162: return doFindNext(getSearchRoot());
163: }
164:
165: public boolean findPrevious() {
166: if (!canFindBePerformed()) {
167: return false;
168: }
169:
170: return doFindPrevious(getSearchRoot());
171: }
172:
173: public void mouseClicked(MouseEvent e) {
174: }
175:
176: public void mouseDragged(MouseEvent event) {
177: }
178:
179: public void mouseEntered(MouseEvent e) {
180: CellTipManager.sharedInstance().setEnabled(false);
181: }
182:
183: public void mouseExited(MouseEvent e) {
184: // Return if mouseExit occured because of showing heavyweight celltip
185: if (contains(e.getPoint()) && cellTip.isShowing()) {
186: return;
187: }
188:
189: CellTipManager.sharedInstance().setEnabled(false);
190: lastRow = -1;
191: lastColumn = -1;
192: }
193:
194: public void mouseMoved(MouseEvent event) {
195: // Identify table row and column at cursor
196: int row = rowAtPoint(event.getPoint());
197: int column = columnAtPoint(event.getPoint());
198:
199: // Return if table cell is the same as in previous event
200: if ((row == lastRow) && (column == lastColumn)) {
201: return;
202: }
203:
204: lastRow = row;
205: lastColumn = column;
206:
207: if ((row < 0) || (column < 0)) {
208: CellTipManager.sharedInstance().setEnabled(false);
209:
210: return;
211: }
212:
213: TableCellRenderer tableCellRenderer = getCellRenderer(row,
214: column);
215:
216: if (!(tableCellRenderer instanceof TableCellRendererPersistent)) {
217: return;
218: }
219:
220: Component cellRenderer = ((TableCellRendererPersistent) tableCellRenderer)
221: .getTableCellRendererComponentPersistent(this ,
222: getValueAt(row, column), false, false, row,
223: column);
224: Rectangle cellRect = getCellRect(row, column, false);
225:
226: // Return if celltip is not supported for the cell
227: if (cellRenderer == null) {
228: CellTipManager.sharedInstance().setEnabled(false);
229:
230: return;
231: }
232:
233: int horizontalAlignment = ((EnhancedTableCellRenderer) cellRenderer)
234: .getHorizontalAlignment();
235:
236: if ((horizontalAlignment == SwingConstants.TRAILING)
237: || (horizontalAlignment == SwingConstants.RIGHT)) {
238: rendererRect = new Rectangle((cellRect.x + cellRect.width)
239: - cellRenderer.getPreferredSize().width,
240: cellRect.y, cellRenderer.getPreferredSize().width,
241: cellRenderer.getPreferredSize().height);
242: } else {
243: rendererRect = new Rectangle(cellRect.x, cellRect.y,
244: cellRenderer.getPreferredSize().width, cellRenderer
245: .getPreferredSize().height);
246: }
247:
248: // Return if cell contents is fully visible
249: if ((rendererRect.x >= cellRect.x)
250: && ((rendererRect.x + rendererRect.width) <= (cellRect.x + cellRect.width))) {
251: CellTipManager.sharedInstance().setEnabled(false);
252:
253: return;
254: }
255:
256: while (cellTip.getComponentCount() > 0) {
257: cellTip.remove(0);
258: }
259:
260: cellTip.add(cellRenderer, BorderLayout.CENTER);
261: cellTip.setPreferredSize(new Dimension(rendererRect.width + 2,
262: getRowHeight(row) + 2));
263:
264: CellTipManager.sharedInstance().setEnabled(true);
265: }
266:
267: public void mousePressed(MouseEvent e) {
268: }
269:
270: public void mouseReleased(MouseEvent e) {
271: }
272:
273: public void mouseWheelMoved(MouseWheelEvent e) {
274: mouseMoved(e);
275: CellTipManager.sharedInstance().setEnabled(false);
276: }
277:
278: public void processMouseEvent(MouseEvent e) {
279: super .processMouseEvent(e);
280: }
281:
282: public void selectRowByContents(String rowString, int columnIndex,
283: boolean setVisible) {
284: for (int i = 0; i < getRowCount(); i++) {
285: if (getValueAt(i, columnIndex).toString().equals(rowString)) {
286: getSelectionModel().setSelectionInterval(i, i);
287:
288: if (setVisible) {
289: ensureRowVisible(i);
290: }
291:
292: return;
293: }
294: }
295:
296: getSelectionModel().clearSelection();
297: }
298:
299: public void selectRowByInstance(Object instance, int columnIndex,
300: boolean setVisible) {
301: for (int i = 0; i < getRowCount(); i++) {
302: if (getValueAt(i, columnIndex) == instance) {
303: getSelectionModel().setSelectionInterval(i, i);
304:
305: if (setVisible) {
306: ensureRowVisible(i);
307: }
308:
309: return;
310: }
311: }
312:
313: getSelectionModel().clearSelection();
314: }
315:
316: public void selectRowsByInstances(Object[] instances,
317: int columnIndex, boolean setVisible) {
318: List instancesList = new LinkedList();
319:
320: for (int i = 0; i < instances.length; i++) {
321: instancesList.add(instances[i]);
322: }
323:
324: getSelectionModel().clearSelection();
325:
326: for (int i = 0; i < getRowCount(); i++) {
327: if (instancesList.contains(getValueAt(i, columnIndex))) {
328: getSelectionModel().addSelectionInterval(i, i);
329: }
330: }
331:
332: if (setVisible && (getSelectedRow() != -1)) {
333: ensureRowVisible(getSelectedRow());
334: }
335: }
336:
337: protected JToolTip createCellTip() {
338: return new JToolTip();
339: }
340:
341: private boolean isAnyRowSelected() {
342: return getSelectedRow() != -1;
343: }
344:
345: private String getInternalFindString(String findString) {
346: if (findString == null) {
347: return null;
348: }
349:
350: return findString.toLowerCase();
351: }
352:
353: private int getSearchRoot() {
354: if (!isAnyRowSelected()) {
355: return 0;
356: } else {
357: return getSelectedRow();
358: }
359: }
360:
361: private boolean doFindNext(int lastFoundRow) {
362: for (int row = lastFoundRow + 1; row < getRowCount(); row++) {
363: if (matchesFindCriterion(row)) {
364: return selectFoundNode(row);
365: }
366: }
367:
368: return false;
369: }
370:
371: private boolean doFindPrevious(int lastFoundRow) {
372: for (int row = lastFoundRow - 1; row >= 0; row--) {
373: if (matchesFindCriterion(row)) {
374: return selectFoundNode(row);
375: }
376: }
377:
378: return false;
379: }
380:
381: private void initListeners() {
382: addMouseListener(this );
383: addMouseMotionListener(this );
384:
385: // Required for correct updating of focused/unfocused selection
386: addFocusListener(new FocusListener() {
387: public void focusGained(FocusEvent e) {
388: if (getSelectedRows().length > 0) {
389: repaint();
390: }
391: }
392:
393: public void focusLost(FocusEvent e) {
394: if (getSelectedRows().length > 0) {
395: repaint();
396: }
397: }
398: });
399:
400: addKeyListener(new KeyAdapter() {
401: public void keyPressed(KeyEvent e) {
402: int rowCount = getRowCount();
403:
404: switch (e.getKeyCode()) {
405: case KeyEvent.VK_HOME:
406:
407: if (rowCount > 0) {
408: setRowSelectionInterval(0, 0);
409: }
410:
411: break;
412: case KeyEvent.VK_END:
413:
414: if (rowCount > 0) {
415: setRowSelectionInterval(rowCount - 1,
416: rowCount - 1);
417: }
418:
419: break;
420: }
421: }
422: });
423: }
424:
425: private boolean matchesFindCriterion(int row) {
426: return getValueAt(row, userFindColumn).toString().toLowerCase()
427: .indexOf(internalFindString) != -1;
428: }
429:
430: private boolean selectFoundNode(int row) {
431: getSelectionModel().setSelectionInterval(row, row);
432: requestFocusInWindow();
433:
434: Rectangle rect = getCellRect(row, userFindColumn, true);
435:
436: if (rect != null) {
437: scrollRectToVisible(rect);
438:
439: return true;
440: } else {
441: return false;
442: }
443: }
444:
445: //------------------------------------
446: }
|