0001: /*
0002: * Javu WingS - Lightweight Java Component Set
0003: * Copyright (c) 2005-2007 Krzysztof A. Sadlocha
0004: * e-mail: ksadlocha@programics.com
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation; either
0009: * version 2.1 of the License, or (at your option) any later version.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU Lesser General Public
0017: * License along with this library; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0019: */
0020:
0021: package com.javujavu.javux.wings;
0022:
0023: import java.awt.AWTEvent;
0024: import java.awt.Color;
0025: import java.awt.Cursor;
0026: import java.awt.Dimension;
0027: import java.awt.Graphics;
0028: import java.awt.ItemSelectable;
0029: import java.awt.Point;
0030: import java.awt.Rectangle;
0031: import java.awt.event.FocusEvent;
0032: import java.awt.event.ItemEvent;
0033: import java.awt.event.KeyEvent;
0034: import java.awt.event.MouseEvent;
0035: import java.util.Vector;
0036: import com.javujavu.javux.wings.item.ItemEditor;
0037: import com.javujavu.javux.wings.item.ItemOwner;
0038: import com.javujavu.javux.wings.item.ItemRenderer;
0039: import com.javujavu.javux.wings.item.ItemStyles;
0040: import com.javujavu.javux.wings.table.Column;
0041: import com.javujavu.javux.wings.table.DefaultTableModel;
0042:
0043: /**
0044: * This class displays items organized into a table with
0045: * rows and columns<br>
0046: * <br>
0047: * <b>This class is thread safe.</b>
0048: **/
0049: public class WingTable extends WingComponent implements ItemSelectable,
0050: ItemOwner {
0051: public static final int HEIGHT_OF_FIRST_ROW = 0;
0052: public static final int HEIGHT_OF_FONT = -1;
0053: public static final int HEIGHT_OF_ALL_CELLS = -2;
0054: protected ItemStyles itemStyles;
0055: protected Style stHeader;
0056: protected Style stHeaderDisabled;
0057: protected Color vgrid;
0058: protected Color hgrid;
0059:
0060: private int rowHeight;
0061: private int rowHeightSet;
0062: private int headerHeight;
0063: private int headerHeightSet;
0064:
0065: private Cursor stdCursor;
0066: private int resizedColumn;
0067: private int resizingStart;
0068: private int lastIncColumn;
0069:
0070: private int focusedRow;
0071: private int focusedColumn;
0072: private int dragRow;
0073: private int dragColumn;
0074:
0075: private Rectangle selectedArea;
0076: private boolean[][] selectedMap;
0077:
0078: private int selectionMode;
0079: private boolean cellSelection;
0080:
0081: private boolean mousePressed;
0082: private int defWidth;
0083: private boolean focused;
0084:
0085: private/*final*/Vector columns;
0086: private/*final*/DefaultTableModel model;
0087: private ItemEditor cellEditor;
0088: private ItemRenderer cellRenderer;
0089:
0090: private boolean editable;
0091: private WingComponent editor;
0092: private int editRow = -1;
0093: private int editColumn;
0094: private boolean keyPressed;
0095:
0096: public WingTable() {
0097: this (new DefaultTableModel());
0098: }
0099:
0100: public WingTable(DefaultTableModel model) {
0101: this .model = model;
0102: focusedRow = focusedColumn = dragRow = dragColumn = -1;
0103: headerHeightSet = -1;
0104: resizedColumn = -1;
0105: lastIncColumn = 0;
0106:
0107: rowHeightSet = HEIGHT_OF_FIRST_ROW;
0108: columns = new Vector();
0109: setWingFocusable(true);
0110: enableEvents(AWTEvent.KEY_EVENT_MASK
0111: | AWTEvent.MOUSE_EVENT_MASK
0112: | AWTEvent.MOUSE_MOTION_EVENT_MASK
0113: | AWTEvent.FOCUS_EVENT_MASK);
0114: }
0115:
0116: public void loadSkin() {
0117: String idt = WingSkin.catKeys(styleId, "table");
0118:
0119: stNormal = WingSkin.getStyle(idt, null, DOC | NORMAL, null);
0120: stDisabled = WingSkin.getStyle(idt, null, DOC | DISABLED,
0121: stNormal).merge(stTop);
0122:
0123: itemStyles = new ItemStyles(idt, stTop);
0124: hgrid = WingSkin.getColor(idt, "hgrid");
0125: vgrid = WingSkin.getColor(idt, "vgrid");
0126:
0127: String idh = WingSkin.catKeys(styleId, "table.header");
0128:
0129: stHeader = WingSkin
0130: .getStyle(idh, null, ITEM | NORMAL, stNormal);
0131: stHeaderDisabled = WingSkin.getStyle(idh, null,
0132: ITEM | DISABLED, stHeader).merge(stTop);
0133: stNormal = stNormal.merge(stTop);
0134: stHeader = stHeader.merge(stTop);
0135: }
0136:
0137: public void setCellRenderer(ItemRenderer cellRenderer) {
0138: this .cellRenderer = cellRenderer;
0139: revalidateAndRepaint();
0140: }
0141:
0142: public ItemRenderer getCellRenderer() {
0143: ItemRenderer r = cellRenderer;
0144: if (r == null)
0145: r = getRenderer();
0146: return r;
0147: }
0148:
0149: public int getColumnCount() {
0150: return columns.size();
0151: }
0152:
0153: private boolean wrongColumn(int index) {
0154: return index < 0 || index >= columns.size();
0155: }
0156:
0157: private Column column(int index) {
0158: return (Column) columns.elementAt(index);
0159: }
0160:
0161: public synchronized void setColumnCount(int columnCount) {
0162: int oldSize = columns.size();
0163: columns.setSize(columnCount);
0164: for (int i = oldSize; i < columnCount; i++) {
0165: columns.setElementAt(new Column(), i);
0166: }
0167: resizedColumn = -1;
0168: lastIncColumn = 0;
0169: revalidateAndRepaint();
0170: }
0171:
0172: public void addColumn(Object title) {
0173: addColumn(title, 0, LEFT, null, null);
0174: }
0175:
0176: public synchronized void addColumn(Object title, int width,
0177: int alignment, ItemRenderer renderer, ItemEditor editor) {
0178: Column c = new Column();
0179: c.title = title;
0180: c.width = width;
0181: c.alignment = alignment;
0182: c.renderer = renderer;
0183: c.editor = editor;
0184: columns.addElement(c);
0185:
0186: resizedColumn = -1;
0187: lastIncColumn = 0;
0188: revalidateAndRepaint();
0189: }
0190:
0191: public synchronized void setColumnTitle(Object title, int index) {
0192: if (wrongColumn(index))
0193: return;
0194: column(index).title = title;
0195: repaint();
0196: }
0197:
0198: public synchronized void setColumnWidth(int width, int index) {
0199: if (wrongColumn(index))
0200: return;
0201: column(index).width = width;
0202: revalidateAndRepaint();
0203: }
0204:
0205: public synchronized void setColumnAlignment(int alignment, int index) {
0206: if (wrongColumn(index))
0207: return;
0208: column(index).alignment = alignment;
0209: repaint();
0210: }
0211:
0212: public synchronized void setColumnRenderer(ItemRenderer renderer,
0213: int index) {
0214: if (wrongColumn(index))
0215: return;
0216: column(index).renderer = renderer;
0217: repaint();
0218: }
0219:
0220: public synchronized void setColumnEditor(ItemEditor editor,
0221: int index) {
0222: if (wrongColumn(index))
0223: return;
0224: column(index).editor = editor;
0225: }
0226:
0227: public synchronized int getColumnWidth(int index) {
0228: if (wrongColumn(index))
0229: return 0;
0230: return column(index).width;
0231: }
0232:
0233: /**
0234: * @param height
0235: * <li>0 - no header
0236: * <li>-1 - default, calculate dynamically
0237: */
0238: public synchronized void setHeaderHeight(int height) {
0239: headerHeightSet = height;
0240: revalidateAndRepaint();
0241: }
0242:
0243: public synchronized void setRowHeight(int height) {
0244: rowHeightSet = height;
0245: revalidateAndRepaint();
0246: }
0247:
0248: public void setEditor(ItemEditor editor) {
0249: this .cellEditor = editor;
0250: }
0251:
0252: public void setEditable(boolean editable) {
0253: this .editable = editable;
0254: if (!editable)
0255: removeEditor();
0256: }
0257:
0258: public synchronized void setSelectionMode(int mode) {
0259: selectionMode = mode;
0260: // repaint();
0261: }
0262:
0263: public synchronized void setCellSelectionEnabled(
0264: boolean enableCellSelection) {
0265: this .cellSelection = enableCellSelection;
0266: repaint();
0267: }
0268:
0269: private boolean wrongRow(int rowIndex) {
0270: return rowIndex < 0 || rowIndex >= getRowCount();
0271: }
0272:
0273: public synchronized void removeAllRows() {
0274: model.setRowCount(0);
0275: clearSelection();
0276: }
0277:
0278: public void addRow(Object row) {
0279: insertRow(-1, row);
0280: }
0281:
0282: public synchronized void insertRow(int rowIndex, Object row) {
0283: if (rowIndex == -1)
0284: rowIndex = model.getRowCount();
0285: if (rowIndex < 0 || rowIndex > getRowCount())
0286: return;
0287: model.insertRow(rowIndex, row);
0288: revalidateAndRepaint();
0289: }
0290:
0291: public synchronized void setRow(Object row, int rowIndex) {
0292: if (wrongRow(rowIndex))
0293: return;
0294: model.setRow(row, rowIndex);
0295: revalidateAndRepaint();
0296: }
0297:
0298: public synchronized Object getRow(int rowIndex) {
0299: if (wrongRow(rowIndex))
0300: return null;
0301: return model.getRow(rowIndex);
0302: }
0303:
0304: public synchronized void removeRow(int rowIndex) {
0305: if (wrongRow(rowIndex))
0306: return;
0307:
0308: model.removeRow(rowIndex);
0309: int row = focusedRow, col = focusedColumn, rowCount = model
0310: .getRowCount();
0311: clearSelection();
0312: if (row >= rowCount)
0313: row = rowCount - 1;
0314: if (row >= 0)
0315: changeSelection(row, col, false, false);
0316: removeEditor();
0317: revalidateAndRepaint();
0318: }
0319:
0320: public synchronized void removeRow(Object row) {
0321: removeRow(model.indexOfRow(row));
0322: }
0323:
0324: public synchronized int indexOfRow(Object row) {
0325: return model.indexOfRow(row);
0326: }
0327:
0328: public synchronized int getRowCount() {
0329: return model.getRowCount();
0330: }
0331:
0332: public synchronized Object getValueAt(int rowIndex, int columnIndex) {
0333: if (wrongRow(rowIndex) || wrongColumn(columnIndex))
0334: return null;
0335: return model.getValueAt(rowIndex, columnIndex);
0336: }
0337:
0338: public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
0339: if (wrongRow(rowIndex) || wrongColumn(columnIndex))
0340: return;
0341: model.setValueAt(aValue, rowIndex, columnIndex);
0342: repaint();
0343: }
0344:
0345: public synchronized boolean isCellSelected(int row, int col) {
0346: if (!cellSelection)
0347: col = 0;
0348: return (selectedArea != null && selectedArea.contains(col, row) && (selectedMap == null || selectedMap[row
0349: - selectedArea.y][col - selectedArea.x]));
0350: }
0351:
0352: public synchronized int getSelectedRow() {
0353: return (selectedArea != null) ? selectedArea.y : -1;
0354: }
0355:
0356: public synchronized int getSelectedColumn() {
0357: return (selectedArea != null) ? selectedArea.x : -1;
0358: }
0359:
0360: public synchronized int getSelectedRowCount() {
0361: return (selectedArea != null) ? selectedArea.height : 0;
0362: }
0363:
0364: public synchronized int getSelectedColumnCount() {
0365: return (selectedArea != null) ? selectedArea.width : 0;
0366: }
0367:
0368: public synchronized void selectAll() {
0369: changeSelection(0, 0, false, false);
0370: changeSelection(getRowCount() - 1, getColumnCount() - 1, false,
0371: true);
0372: }
0373:
0374: public void changeSelection(int row, int col, boolean toggle,
0375: boolean extend) {
0376: changeSelection(row, col, toggle, !extend, true, false);
0377: }
0378:
0379: // |setdr|set |set|tog|skip|clear|
0380: // |start|area|cur|gle|spos|sel |
0381: //---------------+---------------+-----+----+---+---+----+-----+----
0382: // sel begin | m.press | + | | + | | | + |
0383: // drag | m.drag | | | + | | + | |
0384: // sel end | m.rel | | + | + | | | |
0385: //---------------+---------------+-----+----+---+---+----+-----+----
0386: // sel begin | ctrl+m.pres | + | | + | | | |
0387: // drag | ctrl+m.drag | | | + | | + | |
0388: // sel end toggle| ctrl+m.rel | | + | + | + | | |
0389: //---------------+---------------+-----+----+---+---+----+-----+----
0390: // sel begin | k.press | + | | + | | | + |
0391: // sel end | k.rel | | + | + | | | |
0392: //---------------+---------------+-----+----+---+---+----+-----+----
0393: // drag | shift+k.press | | | + | | | |
0394: // sel end | shift+k.rel | | + | + | | | |
0395: //---------------+---------------+-----+----+---+---+----+-----+----
0396: // |-exte| | | | | |
0397: // |nd | | | | | |
0398:
0399: private synchronized void changeSelection(int row, int col,
0400: boolean toggle, boolean setStart, boolean setArea,
0401: boolean clear) {
0402: if (selectionMode != MULTIPLE_SELECTION)
0403: toggle = false;
0404: if (selectionMode == SINGLE_SELECTION)
0405: setStart = true;
0406: if (!cellSelection)
0407: col = 0;
0408:
0409: if (row < 0 || row >= model.getRowCount() || col < 0
0410: || col >= getColumnCount()) {
0411: return;
0412: }
0413:
0414: if (clear)
0415: clearSelection();
0416: // removeEditor();
0417:
0418: focusedRow = row;
0419: focusedColumn = col;
0420:
0421: if (setStart) {
0422: dragRow = row;
0423: dragColumn = col;
0424: }
0425:
0426: if (setArea) {
0427: int rowo = (focusedRow < dragRow) ? focusedRow : dragRow;
0428: int rowe = (focusedRow < dragRow) ? dragRow : focusedRow;
0429: int colo = (focusedColumn < dragColumn) ? focusedColumn
0430: : dragColumn;
0431: int cole = (focusedColumn < dragColumn) ? dragColumn
0432: : focusedColumn;
0433:
0434: Rectangle newArea = new Rectangle(colo, rowo, cole - colo
0435: + 1, rowe - rowo + 1);
0436:
0437: if (!toggle || selectedArea == null) {
0438: selectedArea = newArea;
0439: selectedMap = null;
0440: } else if (newArea.height == 1 && newArea.width == 1
0441: && newArea.equals(selectedArea)) {
0442: selectedArea = null;
0443: selectedMap = null;
0444: } else {
0445: Rectangle unionArea = (selectedArea == null) ? newArea
0446: : newArea.union(selectedArea);
0447: boolean[][] unionMap = null;
0448:
0449: if (!unionArea.equals(selectedArea)
0450: || selectedMap == null) {
0451: unionMap = new boolean[unionArea.height][unionArea.width];
0452: int dx = selectedArea.x - unionArea.x;
0453: int dy = selectedArea.y - unionArea.y;
0454: for (int x = 0; x < selectedArea.width; x++)
0455: for (int y = 0; y < selectedArea.height; y++) {
0456: unionMap[y + dy][x + dx] = selectedMap == null
0457: || selectedMap[y][x];
0458: }
0459: selectedMap = unionMap;
0460: }
0461:
0462: int dx = newArea.x - unionArea.x;
0463: int dy = newArea.y - unionArea.y;
0464: if (newArea.height > 1 || newArea.width > 1
0465: || !selectedArea.contains(newArea.x, newArea.y)) {
0466: for (int x = 0; x < newArea.width; x++)
0467: for (int y = 0; y < newArea.height; y++) {
0468: selectedMap[y + dy][x + dx] = true;
0469: }
0470: } else {
0471: selectedMap[dy][dx] = !selectedMap[dy][dx];
0472: }
0473:
0474: selectedArea = unionArea;
0475: }
0476: }
0477: repaint();
0478: }
0479:
0480: private void changeSelection(int row, int col, boolean toggle,
0481: boolean setStart, boolean setArea, boolean clear,
0482: boolean notify, Point dragPoint) {
0483: ItemEvent event = null;
0484: synchronized (this ) {
0485: if (dragPoint != null) {
0486: row = rowAtPoint(dragPoint.x, dragPoint.y);
0487: col = columnAtPoint(dragPoint.x, dragPoint.y);
0488: if (row == focusedRow
0489: && (col == focusedColumn || !cellSelection)) {
0490: return;
0491: }
0492: }
0493: if (!cellSelection)
0494: col = 0;
0495: if (row < 0 || row >= model.getRowCount() || col < 0
0496: || col >= getColumnCount()) {
0497: return;
0498: }
0499:
0500: changeSelection(row, col, toggle, setStart, setArea, clear);
0501:
0502: if (notify) {
0503: event = new ItemEvent(
0504: this ,
0505: ItemEvent.ITEM_STATE_CHANGED,
0506: (selectedArea != null
0507: && selectedArea.height == 1
0508: && selectedArea.width == 1 && selectedMap == null) ? ((cellSelection) ? getValueAt(
0509: focusedRow, focusedColumn)
0510: : getRow(focusedRow))
0511: : null, ItemEvent.SELECTED);
0512: }
0513: }
0514:
0515: Rectangle scrollRect = getCellRect(row, col);
0516: if (scrollRect != null) {
0517: if (!cellSelection) {
0518: Rectangle r2 = getCellRect(row, getColumnCount() - 1);
0519: if (r2 != null)
0520: scrollRect = scrollRect.union(r2);
0521: }
0522: scrollRectToVisible(scrollRect);
0523: }
0524: if (event != null)
0525: postOnEventThread(event);
0526: }
0527:
0528: public synchronized void clearSelection() {
0529: selectedArea = null;
0530: selectedMap = null;
0531: focusedRow = focusedColumn = dragRow = dragColumn = -1;
0532: repaint();
0533: }
0534:
0535: public synchronized Object[] getSelectedObjects() {
0536: if (selectedArea == null)
0537: return null;
0538: Vector v = new Vector();
0539: for (int y = 0; y < selectedArea.height; y++)
0540: for (int x = 0; x < selectedArea.width; x++) {
0541: if (selectedMap == null || selectedMap[y][x]) {
0542: Object o = (cellSelection) ? model.getValueAt(
0543: selectedArea.y + y, selectedArea.x + x)
0544: : model.getRow(selectedArea.y + y);
0545: if (o != null)
0546: v.addElement(o);
0547: }
0548: }
0549: if (v.size() == 0)
0550: return null;
0551: Object[] r = new Object[v.size()];
0552: v.copyInto(r);
0553: return r;
0554: }
0555:
0556: public void copy() {
0557: StringBuffer b = new StringBuffer();
0558: synchronized (this ) {
0559: if (selectedArea == null)
0560: return;
0561: for (int y = 0; y < selectedArea.height; y++) {
0562: if (cellSelection) {
0563: for (int x = 0; x < selectedArea.width; x++) {
0564: Object o = (selectedMap == null || selectedMap[y][x]) ? model
0565: .getValueAt(selectedArea.y + y,
0566: selectedArea.x + x)
0567: : null;
0568: if (o != null)
0569: b.append(o.toString());
0570: if (x < selectedArea.width - 1)
0571: b.append('\t');
0572: }
0573: } else if (selectedMap == null || selectedMap[y][0]) {
0574: for (int x = 0; x < getColumnCount(); x++) {
0575: Object o = model.getValueAt(selectedArea.y + y,
0576: x);
0577: if (o != null)
0578: b.append(o.toString());
0579: if (x < getColumnCount() - 1)
0580: b.append('\t');
0581: }
0582:
0583: }
0584: if (y < selectedArea.height - 1)
0585: b.append('\n');
0586: }
0587: }
0588: setClipboardText(b.toString());
0589: }
0590:
0591: /**
0592: * <br><br><strong>This method acquire TreeLock</strong>
0593: */
0594: public Rectangle getCellRect(int rowIndex, int columnIndex) {
0595: synchronized (getTreeLock()) {
0596: synchronized (this ) {
0597: wingValidate();
0598:
0599: if (columnIndex < 0 || columnIndex >= getColumnCount())
0600: return null;
0601: int x = 0, y = headerHeight + rowIndex * rowHeight;
0602: int i;
0603: for (i = 0; i < columnIndex; i++) {
0604: x += column(i).width;
0605: }
0606:
0607: return new Rectangle(x, y, column(i).width
0608: - ((vgrid != null) ? 1 : 0), rowHeight
0609: - ((hgrid != null) ? 1 : 0));
0610: }
0611: }
0612: }
0613:
0614: public synchronized Object getTooltipAt(int x, int y) {
0615: Object r = super .getTooltipAt(x, y);
0616: if (r != null)
0617: return r;
0618:
0619: int col = columnAtPoint(x, y);
0620: if (y < headerHeight && col >= 0)
0621: return column(col).title;
0622: int row = rowAtPoint(x, y);
0623: if (row >= 0)
0624: return getValueAt(row, col);
0625: return null;
0626:
0627: }
0628:
0629: /////////////////////////////////////////////////////////
0630: // editor support
0631:
0632: /**
0633: * <br><br><strong>This method acquire TreeLock</strong>
0634: */
0635: public WingComponent editCellAt(int row, int col) {
0636: if (!editable || !isEnabled())
0637: return null;
0638:
0639: synchronized (getTreeLock()) {
0640: synchronized (this ) {
0641: if (wrongRow(row) || wrongColumn(col))
0642: return null;
0643:
0644: cleanEditor(true);
0645:
0646: ItemEditor e = column(col).editor;
0647: if (e == null)
0648: e = cellEditor;
0649: editRow = row;
0650: editColumn = col;
0651: if (e != null)
0652: editor = e.getComponent(this , model.getValueAt(row,
0653: col), new Point(col, row));
0654: if (editor != null) {
0655: add(editor);
0656: wingValidate();
0657: // scrollRectToVisible(r);
0658: editor.setBounds(getCellRect(row, col));
0659: editor.wingRequestFocusInWindow();
0660: } else
0661: editRow = -1;
0662: return editor;
0663: }
0664: }
0665: }
0666:
0667: public synchronized void commitEdit(Object value) {
0668: if (editRow != -1) {
0669: setValueAt(value, editRow, editColumn);
0670: removeEditor();
0671: wingRequestFocusInWindow();
0672: }
0673: }
0674:
0675: public synchronized void removeEditor() {
0676: if (editor != null) {
0677: editRow = -1;
0678: revalidateAndRepaint();
0679: }
0680: }
0681:
0682: /**
0683: * <br><br><strong>This method acquire TreeLock</strong>
0684: */
0685: public void invalidate() {
0686: cleanEditor(false);
0687: super .invalidate();
0688: }
0689:
0690: /**
0691: * <br><br><strong>This method acquire TreeLock</strong>
0692: */
0693: private void cleanEditor(boolean unconditionally) {
0694: synchronized (getTreeLock()) {
0695: synchronized (this ) {
0696: if (editor != null
0697: && (unconditionally || editRow == -1)) {
0698: WingComponent toRemove = editor;
0699: editor = null;
0700: editRow = -1;
0701: remove(toRemove);
0702: repaint();
0703: }
0704: }
0705: }
0706: }
0707:
0708: ////////////////////////////////////////////////////////////
0709:
0710: public synchronized Dimension getPreferredSize() {
0711: Dimension prefSize = wingPrefSize;
0712: if (prefSize == null) {
0713: int columnCount = getColumnCount();
0714: if (columnCount == 0)
0715: return new Dimension(10, 10);
0716:
0717: Dimension viewSize = getViewOrSize();
0718:
0719: int defWidth = (viewSize.width == 0) ? 50
0720: : (viewSize.width / columnCount);
0721: if (defWidth == 0)
0722: defWidth = 1;
0723: int i, w = 0;
0724: for (i = 0; i < columnCount; i++) {
0725: int columnWidth = column(i).width;
0726: if (columnWidth <= 0)
0727: w += defWidth;
0728: else
0729: w += columnWidth;
0730: }
0731: wingPrefSize = prefSize = new Dimension(w,
0732: calcHeaderHeight() + calcRowHeight()
0733: * model.getRowCount());
0734: }
0735: return prefSize;
0736: }
0737:
0738: private int calcHeaderHeight() {
0739: if (headerHeightSet >= 0)
0740: return headerHeightSet;
0741: int hh = 0;
0742: Dimension d;
0743: ItemRenderer headerRenderer = getRenderer();
0744: int columnCount = getColumnCount();
0745: for (int i = 0; i < columnCount; i++) {
0746: d = headerRenderer.getItemSize(column(i).title, this ,
0747: stHeader, null);
0748: if (d.height > hh)
0749: hh = d.height;
0750: }
0751: return hh;
0752: }
0753:
0754: private int calcRowHeight() {
0755: if (rowHeightSet > 0)
0756: return rowHeightSet;
0757: int rowHeight = 1;
0758: int columnCount = getColumnCount();
0759: if (getRowCount() == 0)
0760: return 1;
0761: Dimension d;
0762: Point context = new Point();
0763:
0764: if (rowHeightSet == HEIGHT_OF_FONT) {
0765: d = getCellRenderer().getItemSize("Wj8", this ,
0766: itemStyles.normal, context);
0767: rowHeight = d.height;
0768: } else {
0769: int n = (rowHeightSet == HEIGHT_OF_ALL_CELLS) ? getRowCount()
0770: : 1;
0771: for (int j = 0; j < n; j++)
0772: for (int i = 0; i < columnCount; i++) {
0773: ItemRenderer r = column(i).renderer;
0774: if (r == null)
0775: r = getCellRenderer();
0776: context.x = i;
0777: d = r.getItemSize(model.getValueAt(j, i), this ,
0778: itemStyles.normal, context);
0779: if (d.height > rowHeight)
0780: rowHeight = d.height;
0781: }
0782: }
0783: if (hgrid != null)
0784: rowHeight += 1;
0785: return rowHeight;
0786: }
0787:
0788: public synchronized void doLayout() {
0789: Dimension size = getSize();
0790: if (size.width <= 0 || size.height <= 0)
0791: return;
0792:
0793: int columnCount = getColumnCount();
0794: if (columnCount == 0)
0795: return;
0796: defWidth = size.width / columnCount;
0797:
0798: for (int i = 0; i < columnCount; i++) {
0799: Column c = column(i);
0800: if (c.width == 0)
0801: c.width = defWidth;
0802: }
0803:
0804: Dimension prefSize = getPreferredSize();
0805:
0806: if (size.width != prefSize.width) {
0807: int w = 0, i = 0;
0808: for (i = 0; i <= resizedColumn; i++) {
0809: w += column(i).width;
0810: }
0811: int have = size.width - w, need = prefSize.width - w;
0812: for (; i < columnCount; i++) {
0813: Column c = column(i);
0814: c.width = (c.width * have) / need;
0815: if (c.width < 1)
0816: c.width = 1;
0817: w += c.width;
0818: }
0819:
0820: i = lastIncColumn;
0821: i = i % columnCount;
0822: while (w < size.width) {
0823: if (i <= resizedColumn)
0824: i = (resizedColumn + 1) % columnCount;
0825: column(i).width++;
0826: w++;
0827: i = (i + 1) % columnCount;
0828: }
0829: if (w > size.width && resizedColumn >= 0) {
0830: Column c = column(resizedColumn);
0831: c.width += size.width - w;
0832: if (c.width < 1)
0833: c.width = 1;
0834: }
0835: lastIncColumn = i;
0836: prefSize.width = size.width;
0837: }
0838:
0839: headerHeight = calcHeaderHeight();
0840: rowHeight = calcRowHeight();
0841: if (size.height < prefSize.height) {
0842: headerHeight = (headerHeight * size.height)
0843: / prefSize.height;
0844: int rowCount = model.getRowCount();
0845: if (rowCount > 0)
0846: rowHeight = (size.height - headerHeight) / rowCount;
0847: if (rowHeight < 2)
0848: rowHeight = 2;
0849: // prefSize.height= size.height;
0850: }
0851: }
0852:
0853: public void getScrollIncrements(Point unit, Point block) {
0854: super .getScrollIncrements(unit, block);
0855: unit.x = defWidth;
0856: unit.y = rowHeight;
0857: }
0858:
0859: public synchronized void wingPaint(Graphics g) {
0860: Rectangle oldClip = g.getClipBounds();
0861: Rectangle clipBounds = (oldClip != null) ? oldClip
0862: : new Rectangle(getSize());
0863: Rectangle cellClip = new Rectangle();
0864:
0865: int columnCount = getColumnCount();
0866: ItemRenderer headerRenderer = getRenderer();
0867: if (clipBounds.y < headerHeight && headerHeight > 0) {
0868: for (int x = 0, col = 0; col < columnCount
0869: && x < clipBounds.x + clipBounds.width; col++) {
0870: Column c = column(col);
0871: if (x + c.width > clipBounds.x) {
0872: int width = c.width;
0873: int height = headerHeight;
0874: cellClip.setBounds(x, 0, width, height);
0875: WingToolkit.intersection(cellClip, clipBounds);
0876: g.setClip(cellClip);
0877: Style st = isEnabled() ? stHeader
0878: : stHeaderDisabled;
0879: headerRenderer.drawItem(g, x, 0, width, height,
0880: c.title, this , st, st.margin, CENTER,
0881: RIGHT, null);
0882: }
0883: x += c.width;
0884: }
0885: }
0886: int rowo, rowe, rc = model.getRowCount();
0887: if (rc > 0) {
0888: Point context = new Point();
0889: rowo = (clipBounds.y - headerHeight) / rowHeight;
0890: rowe = (clipBounds.y + clipBounds.height - headerHeight
0891: + rowHeight - 1)
0892: / rowHeight + 1;
0893: if (rowo < 0)
0894: rowo = 0;
0895: if (rowe > rc)
0896: rowe = rc;
0897: for (int x = 0, col = 0; col < columnCount
0898: && x < clipBounds.x + clipBounds.width; col++) {
0899: Column c = column(col);
0900: if (x + c.width > clipBounds.x) {
0901: int width = c.width;
0902: for (int row = rowo; row < rowe; row++) {
0903: int vgrid = (this .vgrid != null) ? 1 : 0, hgrid = (this .hgrid != null) ? 1
0904: : 0;
0905: int y = headerHeight + rowHeight * row;
0906: cellClip.setBounds(x, y, width - vgrid,
0907: rowHeight - hgrid);
0908: WingToolkit.intersection(cellClip, clipBounds);
0909: g.setClip(cellClip);
0910: boolean cellSelected = isCellSelected(row, col);
0911: boolean cellDark = model.isDarkRow(row);
0912: boolean cellFocused = focused
0913: && focusedRow == row
0914: && (focusedColumn == col || !cellSelection);
0915: if (!cellFocused || selectedArea == null)
0916: cellSelected |= ((row >= focusedRow && row <= dragRow) || (row >= dragRow && row <= focusedRow))
0917: && (!cellSelection
0918: || (col >= focusedColumn && col <= dragColumn) || (col >= dragColumn && col <= focusedColumn));
0919:
0920: ItemRenderer r = c.renderer;
0921: if (r == null)
0922: r = getCellRenderer();
0923: Style st = itemStyles.get(isEnabled(),
0924: cellSelected, cellFocused, cellDark);
0925:
0926: context.x = col;
0927: context.y = row;
0928: r.drawItem(g, x, y, width - vgrid, rowHeight
0929: - hgrid, model.getValueAt(row, col),
0930: this , st, st.margin, c.alignment,
0931: RIGHT, context);
0932: g.setClip(clipBounds);
0933: if (vgrid != 0) {
0934: g.setColor(this .vgrid);
0935: g.fillRect(x + width - vgrid, y, vgrid,
0936: rowHeight);
0937: }
0938: if (hgrid != 0) {
0939: g.setColor(this .hgrid);
0940: g.fillRect(x, y + rowHeight - hgrid, width,
0941: hgrid);
0942: }
0943: }
0944: }
0945: x += c.width;
0946: }
0947: }
0948: g.setClip(oldClip);
0949: }
0950:
0951: protected void wingProcessMouseEvent(MouseEvent e) {
0952: int id = e.getID();
0953: if (id == MouseEvent.MOUSE_PRESSED) {
0954: if (wingFocusable && !focused)
0955: requestFocus(); //wingRequestFocusInWindow();
0956:
0957: Point p = e.getPoint();
0958: if (p.y >= 0 && p.y < headerHeight) {
0959: synchronized (this ) {
0960: resizedColumn = headerHandleAtPoint(p.x);
0961: }
0962: if (resizedColumn != -1) {
0963: resizingStart = p.x;
0964: }
0965: } else {
0966: int row = rowAtPoint(p.x, p.y);
0967: int col = columnAtPoint(p.x, p.y);
0968: if (row != -1 && col != -1) {
0969: if (e.getClickCount() < 2) {
0970: mousePressed = true;
0971: changeSelection(row, col, false, true, false,
0972: !e.isControlDown(), false, null);
0973: } else {
0974: editCellAt(row, col);
0975: }
0976: }
0977: }
0978: } else if (id == MouseEvent.MOUSE_RELEASED) {
0979: resizedColumn = -1;
0980: if (mousePressed) {
0981: changeSelection(focusedRow, focusedColumn, e
0982: .isControlDown(), false, true, false, true,
0983: null);
0984: }
0985: mousePressed = false;
0986: } else if (id == MouseEvent.MOUSE_DRAGGED) {
0987: Point p = e.getPoint();
0988: boolean select = true;
0989: synchronized (this ) {
0990: if (resizedColumn != -1) {
0991: select = false;
0992:
0993: int a = p.x - resizingStart;
0994: if (a > 1 || a < -1) {
0995: Column c = column(resizedColumn);
0996: int w = c.width + a;
0997: if (w < 1)
0998: w = 1;
0999: if (w != c.width) {
1000: c.width = w;
1001: resizingStart = p.x;
1002: revalidateAndRepaint();
1003: }
1004: }
1005: }
1006: }
1007: if (mousePressed && select) {
1008: changeSelection(0, 0, false, false, false, false,
1009: false, p);
1010: }
1011: } else if (id == MouseEvent.MOUSE_MOVED) {
1012: Point p = e.getPoint();
1013: boolean handle = false;
1014: if (0 <= p.y && p.y < headerHeight) {
1015: handle = (headerHandleAtPoint(p.x) != -1);
1016: }
1017: changeCursor(handle);
1018: }
1019: }
1020:
1021: public synchronized int rowAtPoint(int x, int y) {
1022: int r = (y - headerHeight) / rowHeight;
1023: if (r < 0 || r >= model.getRowCount())
1024: r = -1;
1025: return r;
1026: }
1027:
1028: public synchronized int columnAtPoint(int x, int y) {
1029: if (x < 0)
1030: return -1;
1031: for (int col = 0; col < getColumnCount(); col++) {
1032: x -= column(col).width;
1033: if (x < 0)
1034: return col;
1035: }
1036: return -1;
1037: }
1038:
1039: private synchronized int headerHandleAtPoint(int x) {
1040: if (x < 0)
1041: return -1;
1042: for (int col = 0; col < getColumnCount(); col++) {
1043: x -= column(col).width;
1044: if (x >= -2 && x < 0)
1045: return col;
1046: if (x < 0)
1047: break;
1048: }
1049: return -1;
1050: }
1051:
1052: private void changeCursor(boolean handle) {
1053: if (handle) {
1054: if (stdCursor == null) {
1055: stdCursor = getCursor();
1056: setCursor(Cursor
1057: .getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
1058: }
1059: } else if (stdCursor != null) {
1060: setCursor(stdCursor);
1061: stdCursor = null;
1062: }
1063: }
1064:
1065: protected void wingProcessKeyEvent(KeyEvent e,
1066: WingComponent redirecting) {
1067: int id = e.getID();
1068: int k = e.getKeyCode();
1069: int m = e.getModifiers();
1070: boolean pressed = (id == KeyEvent.KEY_PRESSED);
1071: boolean consume = true;
1072: if (pressed && m == 0
1073: && (k == KeyEvent.VK_F2 || k == KeyEvent.VK_ENTER)) {
1074: editCellAt(focusedRow, focusedColumn);
1075: } else if (pressed && m == KeyEvent.CTRL_MASK
1076: && k == KeyEvent.VK_A) {
1077: selectAll();
1078: } else if (pressed && m == KeyEvent.CTRL_MASK
1079: && (k == KeyEvent.VK_C || k == KeyEvent.VK_INSERT)) {
1080: copy();
1081: } else if ((pressed || id == KeyEvent.KEY_RELEASED)
1082: && (m == 0 || m == KeyEvent.SHIFT_MASK)) {
1083: boolean shift = (m == KeyEvent.SHIFT_MASK);
1084: int nrow = focusedRow, ncol = focusedColumn;
1085: if (k == KeyEvent.VK_DOWN)
1086: nrow++;
1087: else if (k == KeyEvent.VK_UP)
1088: nrow--;
1089: else if (k == KeyEvent.VK_LEFT)
1090: ncol--;
1091: else if (k == KeyEvent.VK_RIGHT)
1092: ncol++;
1093: else if (k == KeyEvent.VK_HOME)
1094: ncol = 0;
1095: else if (k == KeyEvent.VK_END)
1096: ncol = getColumnCount() - 1;
1097: else if (k == KeyEvent.VK_PAGE_UP
1098: || k == KeyEvent.VK_PAGE_DOWN) {
1099: int d = (getViewOrSize().height * 3) / rowHeight / 4;
1100: if (k == KeyEvent.VK_PAGE_UP)
1101: nrow -= d;
1102: else
1103: nrow += d;
1104: } else
1105: consume = false;
1106: if (nrow < 0)
1107: nrow = 0;
1108: if (nrow >= getRowCount())
1109: nrow = getRowCount() - 1;
1110:
1111: if (nrow != focusedRow || ncol != focusedColumn) {
1112: if (pressed) {
1113: if (nrow >= 0 && nrow < getRowCount() && ncol >= 0
1114: && ncol < getColumnCount()) {
1115: keyPressed = true;
1116: changeSelection(nrow, ncol, false, !shift,
1117: false, !shift, false, null);
1118: }
1119: } else if (keyPressed) {
1120: changeSelection(focusedRow, focusedColumn, false,
1121: false, true, false, true, null);
1122: keyPressed = false;
1123: }
1124: }
1125: } else
1126: consume = false;
1127: if (consume)
1128: e.consume();
1129: super .wingProcessKeyEvent(e, redirecting);
1130: }
1131:
1132: protected void processFocusEvent(FocusEvent e) {
1133: int id = e.getID();
1134: if (id == FocusEvent.FOCUS_GAINED) {
1135: focused = true;
1136: if (focusedRow == -1) {
1137: changeSelection(0, 0, false, true, true, false, true,
1138: null);
1139: }
1140: } else if (id == FocusEvent.FOCUS_LOST) {
1141: focused = false;
1142: }
1143: repaint();
1144: super.processFocusEvent(e);
1145: }
1146: }
|