001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Anton Avtamonov
019: * @version $Revision$
020: */package javax.swing.plaf.basic;
021:
022: import java.awt.Color;
023: import java.awt.Component;
024: import java.awt.Dimension;
025: import java.awt.Graphics;
026: import java.awt.KeyboardFocusManager;
027: import java.awt.Point;
028: import java.awt.Rectangle;
029: import java.awt.datatransfer.StringSelection;
030: import java.awt.datatransfer.Transferable;
031: import java.awt.event.FocusEvent;
032: import java.awt.event.FocusListener;
033: import java.awt.event.InputEvent;
034: import java.awt.event.KeyEvent;
035: import java.awt.event.KeyListener;
036: import java.awt.event.MouseEvent;
037: import java.util.HashSet;
038: import java.util.Set;
039:
040: import javax.swing.CellRendererPane;
041: import javax.swing.JComponent;
042: import javax.swing.JTable;
043: import javax.swing.KeyStroke;
044: import javax.swing.LookAndFeel;
045: import javax.swing.SwingUtilities;
046: import javax.swing.TransferHandler;
047: import javax.swing.UIManager;
048: import javax.swing.event.MouseInputListener;
049: import javax.swing.plaf.ComponentUI;
050: import javax.swing.plaf.TableUI;
051: import javax.swing.table.TableColumn;
052: import javax.swing.table.TableColumnModel;
053:
054: import org.apache.harmony.x.swing.Utilities;
055:
056: import org.apache.harmony.x.swing.internal.nls.Messages;
057:
058: public class BasicTableUI extends TableUI {
059: public class FocusHandler implements FocusListener {
060: public void focusGained(final FocusEvent e) {
061: repaintFocusedCell();
062: }
063:
064: public void focusLost(final FocusEvent e) {
065: repaintFocusedCell();
066: }
067:
068: private void repaintFocusedCell() {
069: int focusedRow = table.getSelectionModel()
070: .getLeadSelectionIndex();
071: int focusedColumn = table.getColumnModel()
072: .getSelectionModel().getLeadSelectionIndex();
073:
074: if (focusedRow != -1 && focusedColumn != -1) {
075: table.repaint(table.getCellRect(focusedRow,
076: focusedColumn, false));
077: }
078: }
079: }
080:
081: public class KeyHandler implements KeyListener {
082: public void keyPressed(final KeyEvent e) {
083: }
084:
085: public void keyReleased(final KeyEvent e) {
086: }
087:
088: public void keyTyped(final KeyEvent e) {
089: if (table.getActionForKeyStroke(KeyStroke
090: .getKeyStrokeForEvent(e)) != null) {
091: return;
092: }
093:
094: if (!table.isEditing()) {
095: int currentRow = table.getSelectionModel()
096: .getLeadSelectionIndex();
097: int currentColumn = table.getColumnModel()
098: .getSelectionModel().getLeadSelectionIndex();
099: if (currentRow == -1 || currentColumn == -1) {
100: return;
101: }
102: if (!table.editCellAt(currentRow, currentColumn, e)) {
103: return;
104: }
105: }
106:
107: if (table.isEditing()) {
108: e.consume();
109: KeyEvent editorEvent = new KeyEvent(table
110: .getEditorComponent(), e.getID(), e.getWhen(),
111: e.getModifiers(), e.getKeyCode(), e
112: .getKeyChar());
113: table.getEditorComponent().dispatchEvent(editorEvent);
114: }
115: }
116: }
117:
118: public class MouseInputHandler implements MouseInputListener {
119: private DnDMouseHelper dndhelper = new DnDMouseHelper(table);
120:
121: public void mouseClicked(final MouseEvent e) {
122: }
123:
124: public void mouseEntered(final MouseEvent e) {
125: }
126:
127: public void mouseExited(final MouseEvent e) {
128: }
129:
130: public void mousePressed(final MouseEvent e) {
131: if (table == null || !table.isEnabled()) {
132: return;
133: }
134:
135: table.requestFocus();
136:
137: int eventRow = table.rowAtPoint(e.getPoint());
138: if (eventRow == -1) {
139: return;
140: }
141:
142: int eventColumn = table.columnAtPoint(e.getPoint());
143: if (eventColumn == -1) {
144: return;
145: }
146:
147: dndhelper.mousePressed(e, table.getDragEnabled(),
148: eventRow != -1 && eventColumn != -1, table
149: .isCellSelected(eventRow, eventColumn));
150:
151: if (!SwingUtilities.isLeftMouseButton(e)) {
152: return;
153: }
154:
155: if (!table.getDragEnabled()) {
156: table.getSelectionModel().setValueIsAdjusting(true);
157: table.getColumnModel().getSelectionModel()
158: .setValueIsAdjusting(true);
159: if (table.editCellAt(eventRow, eventColumn, e)) {
160: if (table.getCellEditor(eventRow, eventColumn)
161: .shouldSelectCell(e)) {
162: changeSelection(e);
163: }
164: forwardEventToEditor(e);
165: } else {
166: changeSelection(e);
167: }
168: } else if (!table.isCellSelected(eventRow, eventColumn)) {
169: changeSelection(e);
170: }
171: }
172:
173: public void mouseReleased(final MouseEvent e) {
174: if (table == null || !table.isEnabled()) {
175: return;
176: }
177:
178: dndhelper.mouseReleased(e);
179: if (table.isEditing()) {
180: forwardEventToEditor(e);
181: }
182: if (dndhelper.shouldProcessOnRelease()) {
183: changeSelection(e);
184: }
185: table.getSelectionModel().setValueIsAdjusting(false);
186: table.getColumnModel().getSelectionModel()
187: .setValueIsAdjusting(false);
188: }
189:
190: public void mouseDragged(final MouseEvent e) {
191: if (table == null || !table.isEnabled()) {
192: return;
193: }
194:
195: dndhelper.mouseDragged(e);
196:
197: if (SwingUtilities.isLeftMouseButton(e)
198: && !dndhelper.isDndStarted()) {
199:
200: table.getSelectionModel().setValueIsAdjusting(true);
201: table.getColumnModel().getSelectionModel()
202: .setValueIsAdjusting(true);
203:
204: changeSelection(e.getPoint(), false, true);
205: }
206: }
207:
208: public void mouseMoved(final MouseEvent e) {
209: }
210:
211: private void changeSelection(final Point p,
212: final boolean toggle, final boolean extend) {
213: int clickRow = table.rowAtPoint(p);
214: if (clickRow == -1) {
215: return;
216: }
217:
218: int clickColumn = table.columnAtPoint(p);
219: if (clickColumn == -1) {
220: return;
221: }
222:
223: table
224: .changeSelection(clickRow, clickColumn, toggle,
225: extend);
226:
227: }
228:
229: private void changeSelection(final MouseEvent e) {
230: boolean toggle = false;
231: boolean extend = false;
232: if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) {
233: toggle = true;
234: }
235: if ((e.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0) {
236: extend = true;
237: }
238:
239: changeSelection(e.getPoint(), toggle, extend);
240: }
241:
242: private void forwardEventToEditor(final MouseEvent e) {
243: table.getEditorComponent().dispatchEvent(
244: SwingUtilities.convertMouseEvent(table, e, table
245: .getEditorComponent()));
246: }
247: }
248:
249: private class TableTransferHandler extends TransferHandler {
250: private final String lineSeparator = System
251: .getProperty("line.separator");
252:
253: public int getSourceActions(final JComponent c) {
254: return COPY;
255: }
256:
257: protected Transferable createTransferable(final JComponent c) {
258: if (table.getSelectedColumnCount() == 0
259: || table.getSelectedRowCount() == 0) {
260: return null;
261: }
262:
263: StringBuffer content = new StringBuffer();
264: int rowMinSelectionIndex = table.getSelectionModel()
265: .getMinSelectionIndex();
266: int rowMaxSelectionIndex = table.getSelectionModel()
267: .getMaxSelectionIndex();
268: int colMinSelectionIndex = table.getColumnModel()
269: .getSelectionModel().getMinSelectionIndex();
270: int colMaxSelectionIndex = table.getColumnModel()
271: .getSelectionModel().getMaxSelectionIndex();
272: for (int i = rowMinSelectionIndex; i <= rowMaxSelectionIndex; i++) {
273: for (int j = colMinSelectionIndex; j <= colMaxSelectionIndex; j++) {
274: if (table.getSelectionModel().isSelectedIndex(i)
275: && table.getColumnModel()
276: .getSelectionModel()
277: .isSelectedIndex(j)) {
278: String value = table.getValueAt(i, j) == null ? "\t"
279: : table.getValueAt(i, j).toString()
280: + "\t";
281: content.append(value);
282: }
283: }
284: if (i < colMaxSelectionIndex) {
285: content.append(lineSeparator);
286: }
287: }
288:
289: return new StringSelection(content.toString());
290: }
291: }
292:
293: protected JTable table;
294: protected CellRendererPane rendererPane;
295: protected KeyListener keyListener;
296: protected FocusListener focusListener;
297: protected MouseInputListener mouseInputListener;
298:
299: private static final WidthInfo MINIMUM_WIDTH = new WidthInfo() {
300: public int getWidth(final TableColumn column) {
301: return column.getMinWidth();
302: }
303: };
304: private static final WidthInfo MAXIMUM_WIDTH = new WidthInfo() {
305: public int getWidth(final TableColumn column) {
306: return column.getMaxWidth();
307: }
308: };
309: private static final WidthInfo PREFERRED_WIDTH = new WidthInfo() {
310: public int getWidth(final TableColumn column) {
311: return column.getPreferredWidth();
312: }
313: };
314:
315: public static ComponentUI createUI(final JComponent c) {
316: return new BasicTableUI();
317: }
318:
319: public void installUI(final JComponent c) {
320: table = (JTable) c;
321: rendererPane = new CellRendererPane();
322: rendererPane.setVisible(false);
323: table.add(rendererPane);
324:
325: installDefaults();
326: installListeners();
327: installKeyboardActions();
328: }
329:
330: public void uninstallUI(final JComponent c) {
331: uninstallKeyboardActions();
332: uninstallListeners();
333: uninstallDefaults();
334:
335: rendererPane = null;
336: table = null;
337: }
338:
339: public Dimension getMinimumSize(final JComponent c) {
340: return getSize(MINIMUM_WIDTH);
341: }
342:
343: public Dimension getPreferredSize(final JComponent c) {
344: return getSize(PREFERRED_WIDTH);
345: }
346:
347: public Dimension getMaximumSize(final JComponent c) {
348: return getSize(MAXIMUM_WIDTH);
349: }
350:
351: public void paint(final Graphics g, final JComponent c) {
352: if (g == null) {
353: throw new NullPointerException(Messages.getString(
354: "swing.03", "context")); //$NON-NLS-1$ //$NON-NLS-2$
355: }
356: if (table.getColumnCount() == 0 || table.getRowCount() == 0) {
357: return;
358: }
359:
360: Color oldColor = g.getColor();
361: paintCells(g);
362: g.setColor(oldColor);
363: }
364:
365: protected void installDefaults() {
366: LookAndFeel.installColorsAndFont(table, "Table.background",
367: "Table.foreground", "Table.font");
368: if (Utilities.isUIResource(table.getSelectionBackground())) {
369: table.setSelectionBackground(UIManager
370: .getColor("Table.selectionBackground"));
371: }
372: if (Utilities.isUIResource(table.getSelectionForeground())) {
373: table.setSelectionForeground(UIManager
374: .getColor("Table.selectionForeground"));
375: }
376: if (Utilities.isUIResource(table.getGridColor())) {
377: table.setGridColor(UIManager.getColor("Table.gridColor"));
378: }
379:
380: LookAndFeel.installProperty(table, "opaque", Boolean.TRUE);
381:
382: table.setTransferHandler(new TableTransferHandler());
383: }
384:
385: protected void uninstallDefaults() {
386: Utilities.uninstallColorsAndFont(table);
387:
388: table.setTransferHandler(null);
389: }
390:
391: protected void installListeners() {
392: keyListener = createKeyListener();
393: if (keyListener != null) {
394: table.addKeyListener(keyListener);
395: }
396:
397: focusListener = createFocusListener();
398: if (focusListener != null) {
399: table.addFocusListener(focusListener);
400: }
401:
402: mouseInputListener = createMouseInputListener();
403: if (mouseInputListener != null) {
404: table.addMouseListener(mouseInputListener);
405: table.addMouseMotionListener(mouseInputListener);
406: }
407: }
408:
409: protected void uninstallListeners() {
410: table.removeKeyListener(keyListener);
411: table.removeFocusListener(focusListener);
412: table.removeMouseListener(mouseInputListener);
413: table.removeMouseMotionListener(mouseInputListener);
414: }
415:
416: protected void installKeyboardActions() {
417: BasicTableKeyboardActions.installKeyboardActions(table);
418:
419: Set forwardSet = new HashSet();
420: forwardSet.add(KeyStroke.getKeyStroke("ctrl pressed TAB"));
421: table
422: .setFocusTraversalKeys(
423: KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
424: forwardSet);
425:
426: Set backwardSet = new HashSet();
427: forwardSet
428: .add(KeyStroke.getKeyStroke("shift ctrl pressed TAB"));
429: table.setFocusTraversalKeys(
430: KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
431: backwardSet);
432: }
433:
434: protected void uninstallKeyboardActions() {
435: BasicTableKeyboardActions.uninstallKeyboardActions(table);
436: table.setFocusTraversalKeys(
437: KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
438: table.setFocusTraversalKeys(
439: KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
440: }
441:
442: protected KeyListener createKeyListener() {
443: return null;
444: }
445:
446: protected FocusListener createFocusListener() {
447: return new FocusHandler();
448: }
449:
450: protected MouseInputListener createMouseInputListener() {
451: return new MouseInputHandler();
452: }
453:
454: private void paintCells(final Graphics g) {
455: Rectangle clipBounds = g.getClipBounds();
456: int draggedColumn = -1;
457: if (table.getTableHeader() != null
458: && table.getTableHeader().getDraggedColumn() != null) {
459: draggedColumn = getColumnIndex(table.getTableHeader()
460: .getDraggedColumn());
461: }
462: for (int column = 0; column < table.getColumnCount(); column++) {
463: if (column != draggedColumn) {
464: for (int row = 0; row < table.getRowCount(); row++) {
465: Rectangle cellRect = table.getCellRect(row, column,
466: false);
467: Rectangle gridRect = table.getCellRect(row, column,
468: true);
469: if (clipBounds == null
470: || clipBounds.intersects(gridRect)) {
471: paintCell(g, row, column, cellRect, gridRect);
472: paintGrid(g, row, column, gridRect);
473: }
474: }
475: }
476: }
477: if (draggedColumn != -1) {
478: for (int row = 0; row < table.getRowCount(); row++) {
479: Rectangle cellRect = table.getCellRect(row,
480: draggedColumn, false);
481: Rectangle gridRect = table.getCellRect(row,
482: draggedColumn, true);
483:
484: paintBackgroundUnderDraggedCell(g, gridRect);
485: cellRect.translate(table.getTableHeader()
486: .getDraggedDistance(), 0);
487: gridRect.translate(table.getTableHeader()
488: .getDraggedDistance(), 0);
489: if (clipBounds == null
490: || clipBounds.intersects(gridRect)) {
491: paintCell(g, row, draggedColumn, cellRect, gridRect);
492: paintGrid(g, row, draggedColumn, gridRect);
493: }
494: }
495: }
496: }
497:
498: private void paintCell(final Graphics g, final int row,
499: final int column, final Rectangle cellRect,
500: final Rectangle gridRect) {
501: boolean isFocused = table.isFocusOwner()
502: && table.getSelectionModel().getLeadSelectionIndex() == row
503: && table.getColumnModel().getSelectionModel()
504: .getLeadSelectionIndex() == column;
505: Component renderingComponent = table.getCellRenderer(row,
506: column).getTableCellRendererComponent(table,
507: table.getValueAt(row, column),
508: table.isCellSelected(row, column), isFocused, row,
509: column);
510: g.setColor(table.getBackground());
511: g.fillRect(gridRect.x, gridRect.y, gridRect.width,
512: gridRect.height);
513: rendererPane.paintComponent(g, renderingComponent, table,
514: cellRect);
515: }
516:
517: private void paintGrid(final Graphics g, final int row,
518: final int column, final Rectangle gridRect) {
519: if (!table.getShowHorizontalLines()
520: && !table.getShowVerticalLines()) {
521: return;
522: }
523:
524: g.setColor(table.getGridColor());
525: if (table.getShowHorizontalLines()) {
526: g.drawLine(gridRect.x - 1, gridRect.y - 1, gridRect.x
527: + gridRect.width - 1, gridRect.y - 1);
528: g.drawLine(gridRect.x - 1,
529: gridRect.y + gridRect.height - 1, gridRect.x
530: + gridRect.width - 1, gridRect.y
531: + gridRect.height - 1);
532: }
533: if (table.getShowVerticalLines()) {
534: g.drawLine(gridRect.x - 1, gridRect.y - 1, gridRect.x - 1,
535: gridRect.y + gridRect.height - 1);
536: g.drawLine(gridRect.x + gridRect.width - 1, gridRect.y - 1,
537: gridRect.x + gridRect.width - 1, gridRect.y
538: + gridRect.height - 1);
539: }
540: }
541:
542: private void paintBackgroundUnderDraggedCell(final Graphics g,
543: final Rectangle gridRect) {
544: g.setColor(table.getParent().getBackground());
545: g.fillRect(gridRect.x, gridRect.y, gridRect.width,
546: gridRect.height);
547: }
548:
549: private int getColumnIndex(final TableColumn column) {
550: for (int i = 0; i < table.getColumnModel().getColumnCount(); i++) {
551: if (table.getColumnModel().getColumn(i) == column) {
552: return i;
553: }
554: }
555: return table.getColumnModel().getColumnIndex(
556: column.getIdentifier());
557: }
558:
559: private Dimension getSize(final WidthInfo info) {
560: return new Dimension(getWidth(info), getHeight());
561: }
562:
563: private int getHeight() {
564: int result = 0;
565: for (int i = 0; i < table.getRowCount(); i++) {
566: result += table.getRowHeight(i);
567: }
568:
569: return result;
570: }
571:
572: private int getWidth(final WidthInfo info) {
573: int result = 0;
574: TableColumnModel columnModel = table.getColumnModel();
575: for (int i = 0; i < columnModel.getColumnCount(); i++) {
576: result += info.getWidth(columnModel.getColumn(i));
577: }
578:
579: return result;
580: }
581:
582: private interface WidthInfo {
583: int getWidth(final TableColumn column);
584: }
585: }
|