blob: 24371ec7997a8a4692b2e4965c2a46a72e3f4d4d [file] [log] [blame]
package org.eclipse.ptp.internal.debug.ui.views;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ScrollBar;
/**
* @author clement
*
*/
public class CTable extends Canvas {
protected GC m_GC;
protected Display m_Display;
protected List<Point> m_Selection;
protected AbstractCTableCellEditor m_CellEditor;
protected ICTableModel m_Model;
protected int m_LeftColumn;
protected int m_TopRow;
// visiable
protected int m_RowsVisible;
protected int m_RowsFullyVisible;
protected int m_ColumnsVisible;
protected int m_ColumnsFullyVisible;
// selection
protected boolean m_RowSelectionMode;
protected boolean m_MultiSelectMode;
protected int m_FocusRow;
protected int m_FocusCol;
protected int m_ClickColumnIndex;
protected int m_ClickRowIndex;
// resize
protected int m_ResizeColumnIndex;
protected int m_ResizeColumnLeft;
protected int m_ResizeRowIndex;
protected int m_ResizeRowTop;
protected int m_NewRowSize;
// Listener
protected List<ICTableCellSelectionListener> cellSelectionListeners;
protected List<ICTableCellResizeListener> cellResizeListeners;
public CTable(Composite parent, int style) {
super(parent, SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | SWT.DOUBLE_BUFFERED | style);
init();
}
private void init() {
m_GC = new GC(this);
m_Display = Display.getCurrent();
m_Selection = new ArrayList<Point>();
m_CellEditor = null;
m_RowSelectionMode = false;
m_MultiSelectMode = false;
m_TopRow = 0;
m_LeftColumn = 0;
m_FocusRow = 0;
m_FocusCol = 0;
m_RowsVisible = 0;
m_RowsFullyVisible = 0;
m_ColumnsVisible = 0;
m_ColumnsFullyVisible = 0;
m_ResizeColumnIndex = -1;
m_ResizeRowIndex = -1;
m_ResizeRowTop = -1;
m_NewRowSize = -1;
m_ResizeColumnLeft = -1;
m_ClickColumnIndex = -1;
m_ClickRowIndex = -1;
cellSelectionListeners = new ArrayList<ICTableCellSelectionListener>();
cellResizeListeners = new ArrayList<ICTableCellResizeListener>();
createListeners();
}
protected void createListeners() {
addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
onPaint(event);
}
});
addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
redraw();
}
});
addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
onMouseDown(e);
}
public void mouseUp(MouseEvent e) {
onMouseUp(e);
}
public void mouseDoubleClick(MouseEvent e) {
onMouseDoubleClick(e);
}
});
addMouseMoveListener(new MouseMoveListener() {
public void mouseMove(MouseEvent e) {
onMouseMove(e);
}
});
if (getVerticalBar() != null) {
getVerticalBar().addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
m_TopRow = getVerticalBar().getSelection();
redraw();
}
});
}
if (getHorizontalBar() != null) {
getHorizontalBar().addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
m_LeftColumn = getHorizontalBar().getSelection();
redraw();
}
});
}
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
onKeyDown(e);
}
});
}
public ICTableModel getModel() {
return m_Model;
}
public void setModel(ICTableModel model) {
m_Model = model;
reset();
}
public Rectangle getVisibleArea() {
doCalculations();
return new Rectangle(m_LeftColumn, m_TopRow, m_ColumnsFullyVisible, m_RowsFullyVisible);
}
public void reset() {
m_FocusCol = -1;
m_FocusRow = -1;
clearSelectionWithoutRedraw();
}
protected int getFixedWidth() {
int width = 0;
for (int i = 0; i < m_Model.getFixedColumnCount(); i++)
width += m_Model.getColumnWidth(i);
return width;
}
protected int getColumnLeft(int index) {
if (index < m_Model.getFixedColumnCount()) {
int x = 0;
for (int i = 0; i < index; i++) {
x += m_Model.getColumnWidth(i);
}
return x;
}
if (index < m_LeftColumn)
return -1;
int x = getFixedWidth();
for (int i = m_LeftColumn; i < index; i++) {
x += m_Model.getColumnWidth(i);
}
return x;
}
protected int getColumnRight(int index) {
if (index < 0)
return 0;
return getColumnLeft(index) + m_Model.getColumnWidth(index);
}
protected int getLastColumnRight() {
return getColumnRight(m_Model.getColumnCount() - 1);
}
protected void doCalculations() {
if (m_Model == null) {
ScrollBar sb = getHorizontalBar();
if (sb != null) {
sb.setVisible(false);
sb.setMinimum(0);
sb.setMaximum(1);
sb.setPageIncrement(1);
sb.setThumb(1);
sb.setSelection(1);
}
sb = getVerticalBar();
if (sb != null) {
sb.setVisible(false);
sb.setMinimum(0);
sb.setMaximum(1);
sb.setPageIncrement(1);
sb.setThumb(1);
sb.setSelection(1);
}
return;
}
int m_RowHeight = m_Model.getRowHeight();
Rectangle rect = getClientArea();
if (m_LeftColumn < m_Model.getFixedColumnCount()) {
m_LeftColumn = m_Model.getFixedColumnCount();
}
if (m_TopRow < m_Model.getFixedRowCount()) {
m_TopRow = m_Model.getFixedRowCount();
}
int fixedHeight = m_RowHeight + (m_Model.getFixedRowCount() - 1) * m_Model.getRowHeight();
m_ColumnsVisible = 0;
m_ColumnsFullyVisible = 0;
if (m_Model.getColumnCount() > m_Model.getFixedColumnCount()) {
int runningWidth = getColumnLeft(m_LeftColumn);
for (int col = m_LeftColumn; col < m_Model.getColumnCount(); col++) {
if (runningWidth < rect.width + rect.x)
m_ColumnsVisible++;
runningWidth += m_Model.getColumnWidth(col);
if (runningWidth < rect.width + rect.x)
m_ColumnsFullyVisible++;
else
break;
}
}
ScrollBar sb = getHorizontalBar();
if (sb != null) {
//TODO: assume all columns has the same width
boolean visiable = !((m_Model.getColumnCount()*m_Model.getColumnWidth(0)+5 < rect.width) && (m_LeftColumn == m_Model.getFixedColumnCount()));
sb.setVisible(visiable);
if (visiable) {
if (m_Model.getColumnCount() <= m_Model.getFixedColumnCount()) {
sb.setMinimum(0);
sb.setMaximum(1);
sb.setPageIncrement(1);
sb.setThumb(1);
sb.setSelection(1);
} else {
sb.setMinimum(m_Model.getFixedColumnCount());
sb.setMaximum(m_Model.getColumnCount());
sb.setIncrement(1);
sb.setPageIncrement(2);
sb.setThumb(m_ColumnsFullyVisible);
sb.setSelection(m_LeftColumn);
}
}
}
m_RowsFullyVisible = Math.max(0, (rect.height - fixedHeight) / m_RowHeight);
m_RowsFullyVisible = Math.min(m_RowsFullyVisible, m_Model.getRowCount() - m_Model.getFixedRowCount());
m_RowsFullyVisible = Math.max(0, m_RowsFullyVisible);
m_RowsVisible = m_RowsFullyVisible + 1;
if (m_TopRow + m_RowsFullyVisible > m_Model.getRowCount()) {
m_TopRow = Math.max(m_Model.getFixedRowCount(), m_Model.getRowCount() - m_RowsFullyVisible);
}
if (m_TopRow + m_RowsFullyVisible >= m_Model.getRowCount()) {
m_RowsVisible--;
}
sb = getVerticalBar();
if (sb != null) {
boolean visiable = !((m_Model.getRowCount()*m_Model.getRowHeight()+5 < rect.height) && (m_TopRow == m_Model.getFixedRowCount()));
sb.setVisible(visiable);
if (visiable) {
if (m_Model.getRowCount() <= m_Model.getFixedRowCount()) {
sb.setMinimum(0);
sb.setMaximum(1);
sb.setPageIncrement(1);
sb.setThumb(1);
sb.setSelection(1);
} else {
sb.setMinimum(m_Model.getFixedRowCount());
sb.setMaximum(m_Model.getRowCount());
sb.setPageIncrement(m_RowsVisible);
sb.setIncrement(1);
sb.setThumb(m_RowsFullyVisible);
sb.setSelection(m_TopRow);
}
}
}
}
public Rectangle getCellRect(int col, int row) {
int m_RowHeight = m_Model.getRowHeight();
if ((col < 0) || (col >= m_Model.getColumnCount()))
return new Rectangle(-1, -1, 0, 0);
int x = getColumnLeft(col) + 1;
int y;
if (row == 0)
y = 0;
else if (row < m_Model.getFixedRowCount())
y = row * m_RowHeight;
else
y = (m_Model.getFixedRowCount() + row - m_TopRow) * m_RowHeight;
int width = m_Model.getColumnWidth(col) - 1;
int height = m_RowHeight - 1;
if (row == 0)
height = m_RowHeight - 1;
return new Rectangle(x, y, width, height);
}
protected boolean canDrawCell(int col, int row, Rectangle clipRect) {
Rectangle r = getCellRect(col, row);
return canDrawCell(r, clipRect);
}
protected boolean canDrawCell(Rectangle r, Rectangle clipRect) {
if (r.y + r.height < clipRect.y)
return false;
if (r.y > clipRect.y + clipRect.height)
return false;
if (r.x + r.width < clipRect.x)
return false;
if (r.x > clipRect.x + clipRect.width)
return false;
return true;
}
public void redraw() {
doCalculations();
super.redraw();
}
protected void onPaint(PaintEvent event) {
Rectangle rect = getClientArea();
GC gc = event.gc;
if (m_Model != null) {
drawCells(gc, gc.getClipping(), 0, m_Model.getFixedColumnCount(), 0, m_Model.getFixedRowCount());
drawCells(gc, gc.getClipping(), m_LeftColumn, m_Model.getColumnCount(), 0, m_Model.getFixedRowCount());
drawCells(gc, gc.getClipping(), 0, m_Model.getFixedColumnCount(), m_TopRow, m_TopRow + m_RowsVisible);
drawCells(gc, gc.getClipping(), m_LeftColumn, m_Model.getColumnCount(), m_TopRow, m_TopRow + m_RowsVisible);
drawBottomSpace(gc);
} else {
gc.fillRectangle(rect);
}
}
// Bottom-Space
protected void drawBottomSpace(GC gc) {
Rectangle r = getClientArea();
if (m_Model.getRowCount() > 0) {
r.y = (m_Model.getFixedRowCount() + m_RowsVisible) * m_Model.getRowHeight() + 1;
}
gc.setForeground(m_Display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
gc.drawLine(0, r.y - 2, getLastColumnRight(), r.y - 2);
gc.drawLine(getLastColumnRight(), 0, getLastColumnRight(), r.y - 2);
}
public void redraw(Rectangle cellsToRedraw) {
redraw(cellsToRedraw.x, cellsToRedraw.y, cellsToRedraw.width, cellsToRedraw.height);
}
public void redraw(int firstCol, int firstRow, int numOfCols, int numOfRows) {
Rectangle clipRect = getClientArea();
GC gc = new GC(this);
drawCells(gc, clipRect, firstCol, firstCol + numOfCols, firstRow, firstRow + numOfRows);
gc.dispose();
}
protected void drawCells(GC gc, Rectangle clipRect, int fromCol, int toCol, int fromRow, int toRow) {
int cnt = 0;
Rectangle r;
if (m_CellEditor != null) {
if (!isCellVisible(m_CellEditor.m_Col, m_CellEditor.m_Row)) {
Rectangle hide = new Rectangle(-101, -101, 100, 100);
m_CellEditor.setBounds(hide);
} else {
m_CellEditor.setBounds(getCellRect(m_CellEditor.m_Col, m_CellEditor.m_Row));
}
}
for (int row = fromRow; row < toRow; row++) {
r = getCellRect(0, row);
if (r.y + r.height < clipRect.y) {
continue;
}
if (r.y > clipRect.y + clipRect.height) {
break;
}
for (int col = fromCol; col < toCol; col++) {
r = getCellRect(col, row);
if (r.x > clipRect.x + clipRect.width) {
break;
}
if (canDrawCell(col, row, clipRect)) {
drawCell(gc, col, row);
cnt++;
}
}
}
}
protected void drawCell(GC gc, int col, int row) {
if ((row < 0) || (row >= m_Model.getRowCount())) {
return;
}
Rectangle rect = getCellRect(col, row);
m_Model.getCellRenderer(col, row).drawCell(gc, rect, col, row, m_Model.getContentAt(col, row), showAsSelected(col, row), col < m_Model.getFixedColumnCount() || row < m_Model.getFixedRowCount(), col == m_ClickColumnIndex && row == m_ClickRowIndex);
}
protected boolean showAsSelected(int col, int row) {
// A cell with an open editor should be drawn without focus
if (m_CellEditor != null) {
if (col == m_CellEditor.m_Col && row == m_CellEditor.m_Row)
return false;
}
return isCellSelected(col, row);
}
protected void drawRow(GC gc, int row) {
Rectangle clipRect = getClientArea();
drawCells(gc, clipRect, 0, m_Model.getFixedColumnCount(), row, row + 1);
drawCells(gc, clipRect, m_LeftColumn, m_Model.getColumnCount(), row, row + 1);
}
protected void drawCol(GC gc, int col) {
Rectangle clipRect = getClientArea();
drawCells(gc, clipRect, col, col + 1, 0, m_Model.getFixedRowCount());
drawCells(gc, clipRect, col, col + 1, m_TopRow, m_TopRow + m_RowsVisible);
}
protected int getColumnForResize(int x, int y) {
if (m_Model == null)
return -1;
if ((y <= 0) || (y >= m_Model.getFixedRowCount() * m_Model.getRowHeight()))
return -1;
if (x < getFixedWidth() + 3) {
for (int i = 0; i < m_Model.getFixedColumnCount(); i++)
if (Math.abs(x - getColumnRight(i)) < 3) {
if (m_Model.isColumnResizable(i))
return i;
return -1;
}
}
for (int i = m_LeftColumn; i < m_Model.getColumnCount(); i++) {
int left = getColumnLeft(i);
int right = left + m_Model.getColumnWidth(i);
if (Math.abs(x - right) < 3) {
if (m_Model.isColumnResizable(i))
return i;
return -1;
}
if ((x >= left + 3) && (x <= right - 3))
break;
}
return -1;
}
protected int getRowForResize(int x, int y) {
if (m_Model == null || !m_Model.isRowResizable())
return -1;
if ((x <= 0) || (x >= getFixedWidth()))
return -1;
if (y < m_Model.getRowHeight())
return -1;
int row = (y / m_Model.getRowHeight());
int rowY = (row + 1) * m_Model.getRowHeight();
if (Math.abs(rowY - y) < 3)
return row;
return -1;
}
/**
* Returns the number of the row that is present at position y or -1, if out
* of area.
*
* @param y
* @return int
*/
public int calcRowNum(int y) {
if (m_Model == null)
return -1;
if (y < m_Model.getRowHeight())
return (m_Model.getFixedRowCount() == 0 ? m_TopRow : 0);
y -= m_Model.getRowHeight();
int row = 1 + (y / m_Model.getRowHeight());
if ((row < 0) || (row >= m_Model.getRowCount()))
return -1;
if (row >= m_Model.getFixedRowCount())
return m_TopRow + row - m_Model.getFixedRowCount();
return row;
}
/**
* Returns the number of the column that is present at position x or -1, if
* out of area.
*
* @param y
* @return int
*/
public int calcColumnNum(int x) {
if (m_Model == null)
return -1;
int col = 0;
int z = 0;
for (int i = 0; i < m_Model.getFixedColumnCount(); i++) {
if ((x >= z) && (x <= z + m_Model.getColumnWidth(i))) {
return i;
}
z += m_Model.getColumnWidth(i);
}
col = -1;
z = getFixedWidth();
for (int i = m_LeftColumn; i < m_Model.getColumnCount(); i++) {
if ((x >= z) && (x <= z + m_Model.getColumnWidth(i))) {
col = i;
break;
}
z += m_Model.getColumnWidth(i);
}
return col;
}
public boolean isCellVisible(int col, int row) {
if (m_Model == null)
return false;
return ((col >= m_LeftColumn && col < m_LeftColumn + m_ColumnsVisible && row >= m_TopRow && row < m_TopRow + m_RowsVisible) || (col < m_Model.getFixedColumnCount() && row < m_Model.getFixedRowCount()));
}
public boolean isCellFullyVisible(int col, int row) {
if (m_Model == null)
return false;
return ((col >= m_LeftColumn && col < m_LeftColumn + m_ColumnsFullyVisible && row >= m_TopRow && row < m_TopRow + m_RowsFullyVisible) || (col < m_Model.getFixedColumnCount() && row < m_Model.getFixedRowCount()));
}
public boolean isRowVisible(int row) {
if (m_Model == null)
return false;
return ((row >= m_TopRow && row < m_TopRow + m_RowsVisible) || row < m_Model.getFixedRowCount());
}
public boolean isRowFullyVisible(int row) {
if (m_Model == null)
return false;
return ((row >= m_TopRow && row < m_TopRow + m_RowsFullyVisible) || row < m_Model.getFixedRowCount());
}
protected void focusCell(int col, int row, int stateMask) {
GC gc = new GC(this);
if (m_CellEditor != null)
m_CellEditor.close(true);
if (row >= m_Model.getFixedRowCount() && (col >= m_Model.getFixedColumnCount() || m_RowSelectionMode)) {
if ((stateMask & SWT.CTRL) == 0 && (stateMask & SWT.SHIFT) == 0) {
// case: no modifier key
boolean redrawAll = (m_Selection.size() > 1);
int oldFocusRow = m_FocusRow;
int oldFocusCol = m_FocusCol;
clearSelectionWithoutRedraw();
addToSelection(col, row);
m_FocusRow = row;
m_FocusCol = col;
if (redrawAll) {
redraw();
}
else if (m_RowSelectionMode) {
if (isRowVisible(oldFocusRow))
drawRow(gc, oldFocusRow);
if (isRowVisible(m_FocusRow))
drawRow(gc, m_FocusRow);
drawBottomSpace(gc);
}
else {
if (isCellVisible(oldFocusCol, oldFocusRow))
drawCell(gc, oldFocusCol, oldFocusRow);
if (isCellVisible(m_FocusCol, m_FocusRow))
drawCell(gc, m_FocusCol, m_FocusRow);
drawBottomSpace(gc);
}
}
else if ((stateMask & SWT.CTRL) != 0) {
// case: CTRL key pressed
if (toggleSelection(col, row)) {
m_FocusCol = col;
m_FocusRow = row;
}
if (m_RowSelectionMode) {
drawRow(gc, row);
}
else {
drawCell(gc, col, row);
}
}
else if ((stateMask & SWT.SHIFT) != 0) {
// case: SHIFT key pressed
if (m_RowSelectionMode) {
if (row < m_FocusRow) {
// backward selection
while (row != m_FocusRow) {
addToSelection(0, --m_FocusRow);
}
}
else {
// forward selection
while (row != m_FocusRow) {
addToSelection(0, ++m_FocusRow);
}
}
}
else {// cell selection mode
if (row < m_FocusRow || (row == m_FocusRow && col < m_FocusCol)) {
// backward selection
while (row != m_FocusRow || col != m_FocusCol) {
m_FocusCol--;
if (m_FocusCol < m_Model.getFixedColumnCount()) {
m_FocusCol = m_Model.getColumnCount();
m_FocusRow--;
}
addToSelection(m_FocusCol, m_FocusRow);
}
}
else {
// forward selection
while (row != m_FocusRow || col != m_FocusCol) {
m_FocusCol++;
if (m_FocusCol == m_Model.getColumnCount()) {
m_FocusCol = m_Model.getFixedColumnCount();
m_FocusRow++;
}
addToSelection(m_FocusCol, m_FocusRow);
}
}
}
redraw();
}
// notify non-fixed cell listeners
fireCellSelection(col, row, stateMask);
}
else {
// a fixed cell was focused
drawCell(gc, col, row);
// notify fixed cell listeners
fireFixedCellSelection(col, row, stateMask);
}
gc.dispose();
}
protected void onMouseDown(MouseEvent e) {
if (e.button == 1) {
// deactivateEditor(true);
setCapture(true);
// Resize column?
int columnIndex = getColumnForResize(e.x, e.y);
if (columnIndex >= 0) {
m_ResizeColumnIndex = columnIndex;
m_ResizeColumnLeft = getColumnLeft(columnIndex);
return;
}
// Resize row?
int rowIndex = getRowForResize(e.x, e.y);
if (rowIndex >= 0) {
m_ResizeRowIndex = rowIndex;
m_ResizeRowTop = rowIndex * m_Model.getRowHeight();
m_NewRowSize = m_Model.getRowHeight();
return;
}
}
// focus change
int col = calcColumnNum(e.x);
int row = calcRowNum(e.y);
if (col == -1 || row == -1)
return;
m_ClickColumnIndex = col;
m_ClickRowIndex = row;
focusCell(col, row, e.stateMask);
}
protected void onMouseMove(MouseEvent e) {
if (m_Model == null)
return;
// show resize cursor?
if ((m_ResizeColumnIndex != -1) || (getColumnForResize(e.x, e.y) >= 0))
setCursor(new Cursor(m_Display, SWT.CURSOR_SIZEWE));
else if ((m_ResizeRowIndex != -1) || (getRowForResize(e.x, e.y) >= 0))
setCursor(new Cursor(m_Display, SWT.CURSOR_SIZENS));
else
setCursor(null);
if (e.button == 1) {
// extend selection?
if (m_ClickColumnIndex != -1 && m_MultiSelectMode) {
int row = calcRowNum(e.y);
int col = calcColumnNum(e.x);
if (row >= m_Model.getFixedRowCount() && col >= m_Model.getFixedColumnCount()) {
m_ClickColumnIndex = col;
m_ClickRowIndex = row;
focusCell(col, row, (e.stateMask | SWT.SHIFT));
}
}
}
// column resize?
if (m_ResizeColumnIndex != -1) {
Rectangle rect = getClientArea();
int oldSize = m_Model.getColumnWidth(m_ResizeColumnIndex);
if (e.x > rect.x + rect.width - 1)
e.x = rect.x + rect.width - 1;
int newSize = e.x - m_ResizeColumnLeft;
if (newSize < m_Model.getColumnWidthMinimum())
newSize = m_Model.getColumnWidthMinimum();
int leftX = getColumnLeft(m_ResizeColumnIndex);
int rightX = getColumnRight(m_ResizeColumnIndex);
m_Model.setColumnWidth(m_ResizeColumnIndex, newSize);
newSize = m_Model.getColumnWidth(m_ResizeColumnIndex);
GC gc = new GC(this);
gc.copyArea(rightX, 0, rect.width - rightX, rect.height, leftX + newSize, 0);
drawCol(gc, m_ResizeColumnIndex);
if (newSize < oldSize) {
int delta = oldSize - newSize;
redraw(rect.width - delta, 0, delta, rect.height, false);
}
gc.dispose();
}
// row resize?
if (m_ResizeRowIndex != -1) {
Rectangle rect = getClientArea();
GC gc = new GC(this);
// calculate new size
if (e.y > rect.y + rect.height - 1)
e.y = rect.y + rect.height - 1;
m_NewRowSize = e.y - m_ResizeRowTop;
if (m_NewRowSize < m_Model.getRowHeightMinimum())
m_NewRowSize = m_Model.getRowHeightMinimum();
gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
int lineEnd = getColumnRight(m_LeftColumn + m_ColumnsVisible - 1);
int m_LineX = rect.x + 1;
int m_LineY = m_ResizeRowTop + m_NewRowSize - 1;
gc.drawLine(m_LineX, m_LineY, rect.x + lineEnd, m_LineY);
gc.dispose();
}
}
protected void onMouseUp(MouseEvent e) {
if (m_Model == null)
return;
setCapture(false);
if (m_ResizeColumnIndex != -1) {
fireColumnResize(m_ResizeColumnIndex, m_Model.getColumnWidth(m_ResizeColumnIndex));
m_ResizeColumnIndex = -1;
redraw();
}
if (m_ResizeRowIndex != -1) {
m_ResizeRowIndex = -1;
m_Model.setRowHeight(m_NewRowSize);
fireRowResize(m_NewRowSize);
redraw();
}
if (m_ClickColumnIndex != -1) {
int col = m_ClickColumnIndex;
int row = m_ClickRowIndex;
m_ClickColumnIndex = -1;
m_ClickRowIndex = -1;
if (m_CellEditor == null) {
drawCell(new GC(this), col, row);
}
}
}
protected void onKeyDown(KeyEvent e) {
boolean focusChanged = false;
int newFocusRow = m_FocusRow;
int newFocusCol = m_FocusCol;
if (m_Model == null)
return;
if ((e.character == ' ') || (e.character == '\r')) {
openEditorInFocus();
return;
} else if (e.keyCode == SWT.HOME) {
newFocusCol = m_Model.getFixedColumnCount();
if (newFocusRow == -1)
newFocusRow = m_Model.getFixedRowCount();
focusChanged = true;
} else if (e.keyCode == SWT.END) {
newFocusCol = m_Model.getColumnCount() - 1;
if (newFocusRow == -1)
newFocusRow = m_Model.getFixedRowCount();
focusChanged = true;
} else if (e.keyCode == SWT.ARROW_LEFT) {
if (!m_RowSelectionMode) {
if (newFocusCol > m_Model.getFixedColumnCount())
newFocusCol--;
}
focusChanged = true;
} else if (e.keyCode == SWT.ARROW_RIGHT) {
if (!m_RowSelectionMode) {
if (newFocusCol == -1) {
newFocusCol = m_Model.getFixedColumnCount();
newFocusRow = m_Model.getFixedRowCount();
} else if (newFocusCol < m_Model.getColumnCount() - 1)
newFocusCol++;
}
focusChanged = true;
} else if (e.keyCode == SWT.ARROW_DOWN) {
if (newFocusRow == -1) {
newFocusRow = m_Model.getFixedRowCount();
newFocusCol = m_Model.getFixedColumnCount();
} else if (newFocusRow < m_Model.getRowCount() - 1)
newFocusRow++;
focusChanged = true;
} else if (e.keyCode == SWT.ARROW_UP) {
if (newFocusRow > m_Model.getFixedRowCount())
newFocusRow--;
focusChanged = true;
} else if (e.keyCode == SWT.PAGE_DOWN) {
newFocusRow += m_RowsVisible - 1;
if (newFocusRow >= m_Model.getRowCount())
newFocusRow = m_Model.getRowCount() - 1;
if (newFocusCol == -1)
newFocusCol = m_Model.getFixedColumnCount();
focusChanged = true;
} else if (e.keyCode == SWT.PAGE_UP) {
newFocusRow -= m_RowsVisible - 1;
if (newFocusRow < m_Model.getFixedRowCount())
newFocusRow = m_Model.getFixedRowCount();
if (newFocusCol == -1)
newFocusCol = m_Model.getFixedColumnCount();
focusChanged = true;
}
if (focusChanged) {
focusCell(newFocusCol, newFocusRow, e.stateMask);
if (!isCellFullyVisible(m_FocusCol, m_FocusRow))
scrollToFocus();
}
}
protected void onMouseDoubleClick(MouseEvent e) {
if (m_Model == null)
return;
if (e.button == 1) {
if (e.y < (m_Model.getFixedRowCount() * m_Model.getRowHeight())) {
// double click in header area
int columnIndex = getColumnForResize(e.x, e.y);
resizeColumnOptimal(columnIndex);
return;
}
//FIXME: assume column 0 is fixed column, problem may occur on 2 fixed columns
else if (e.x < m_Model.getColumnWidth(0) + ((m_Model.getFixedColumnCount() - 1) * m_Model.getColumnWidth(0))) {
// double click in header area
return;
}
else
openEditorInFocus();
}
}
public int resizeColumnOptimal(int column) {
if (column >= 0 && column < m_Model.getColumnCount()) {
int optWidth = 5;
for (int i = 0; i < m_Model.getFixedRowCount(); i++) {
int width = m_Model.getCellRenderer(column, i).getOptimalWidth(m_GC, column, i, m_Model.getContentAt(column, i), true);
if (width > optWidth)
optWidth = width;
}
for (int i = m_TopRow; i < m_TopRow + m_RowsVisible; i++) {
int width = m_Model.getCellRenderer(column, i).getOptimalWidth(m_GC, column, i, m_Model.getContentAt(column, i), true);
if (width > optWidth)
optWidth = width;
}
m_Model.setColumnWidth(column, optWidth);
redraw();
return optWidth;
}
return -1;
}
public void openEditorInFocus() {
m_CellEditor = m_Model.getCellEditor(m_FocusCol, m_FocusRow);
if (m_CellEditor != null) {
Rectangle r = getCellRect(m_FocusCol, m_FocusRow);
m_CellEditor.open(this, m_FocusCol, m_FocusRow, r);
}
}
protected void scrollToFocus() {
boolean change = false;
if (getVerticalBar() != null) {
if (m_FocusRow < m_TopRow) {
m_TopRow = m_FocusRow;
change = true;
}
if (m_FocusRow >= m_TopRow + m_RowsFullyVisible) {
m_TopRow = m_FocusRow - m_RowsFullyVisible + 1;
change = true;
}
}
if (getHorizontalBar() != null) {
if (m_FocusCol < m_LeftColumn) {
m_LeftColumn = m_FocusCol;
change = true;
}
if (m_FocusCol >= m_LeftColumn + m_ColumnsFullyVisible) {
int oldLeftCol = m_LeftColumn;
Rectangle rect = getClientArea();
while (m_LeftColumn < m_FocusCol && getColumnRight(m_FocusCol) > rect.width + rect.x) {
m_LeftColumn++;
}
change = (oldLeftCol != m_LeftColumn);
}
}
if (change)
redraw();
}
protected void fireCellSelection(int col, int row, int statemask) {
for (int i = 0; i < cellSelectionListeners.size(); i++) {
((ICTableCellSelectionListener) cellSelectionListeners.get(i)).cellSelected(col, row, statemask);
}
}
protected void fireFixedCellSelection(int col, int row, int statemask) {
for (int i = 0; i < cellSelectionListeners.size(); i++) {
((ICTableCellSelectionListener) cellSelectionListeners.get(i)).fixedCellSelected(col, row, statemask);
}
}
protected void fireColumnResize(int col, int newSize) {
for (int i = 0; i < cellResizeListeners.size(); i++) {
((ICTableCellResizeListener) cellResizeListeners.get(i)).columnResized(col, newSize);
}
}
protected void fireRowResize(int newSize) {
for (int i = 0; i < cellResizeListeners.size(); i++) {
((ICTableCellResizeListener) cellResizeListeners.get(i)).rowResized(newSize);
}
}
public void addCellSelectionListener(ICTableCellSelectionListener listener) {
cellSelectionListeners.add(listener);
}
public boolean removeCellSelectionListener(ICTableCellSelectionListener listener) {
return cellSelectionListeners.remove(listener);
}
public boolean removeCellResizeListener(ICTableCellResizeListener listener) {
return cellResizeListeners.remove(listener);
}
public void setRowSelectionMode(boolean rowSelectMode) {
m_RowSelectionMode = rowSelectMode;
clearSelection();
}
public void setMultiSelectionMode(boolean multiSelectMode) {
m_MultiSelectMode = multiSelectMode;
clearSelection();
}
public boolean isRowSelectMode() {
return m_RowSelectionMode;
}
public boolean isMultiSelectMode() {
return m_MultiSelectMode;
}
protected void clearSelectionWithoutRedraw() {
m_Selection.clear();
}
public void clearSelection() {
clearSelectionWithoutRedraw();
m_FocusCol = -1;
m_FocusRow = -1;
if (m_MultiSelectMode)
redraw();
}
protected boolean toggleSelection(int col, int row) {
if (m_MultiSelectMode) {
Point pt = new Point(col, row);
if (m_Selection.contains(pt)) {
m_Selection.remove(pt);
return false;
} else {
m_Selection.add(pt);
return true;
}
}
return false;
}
protected void addToSelection(int col, int row) {
if (m_MultiSelectMode) {
if (m_RowSelectionMode)
col = 0;
Point pt = new Point(col, row);
if (!m_Selection.contains(pt)) {
m_Selection.add(pt);
}
}
}
public void setSelection(int col, int row, boolean scroll) {
if (col < m_Model.getColumnCount() && col >= m_Model.getFixedColumnCount() && row < m_Model.getRowCount() && row >= m_Model.getFixedRowCount()) {
focusCell(col, row, SWT.None);
if (scroll) {
scrollToFocus();
}
}
}
public boolean isCellSelected(int col, int row) {
if (!m_MultiSelectMode) {
if (m_RowSelectionMode)
return (row == m_FocusRow);
return (col == m_FocusCol && row == m_FocusRow);
}
if (m_RowSelectionMode)
col = 0;
return m_Selection.contains(new Point(col, row));
}
public int[] getRowSelection() {
if (!m_RowSelectionMode)
return null;
if (!m_MultiSelectMode) {
if (m_FocusRow < 0)
return new int[0];
int[] tmp = new int[1];
tmp[0] = m_FocusRow;
return tmp;
}
Point[] pts = m_Selection.toArray(new Point[0]);
int[] erg = new int[pts.length];
for (int i = 0; i < erg.length; i++) {
erg[i] = pts[i].y;
}
return erg;
}
public Point[] getCellSelection() {
if (m_RowSelectionMode)
return null;
if (!m_MultiSelectMode) {
if (m_FocusRow < 0 || m_FocusCol < 0)
return new Point[0];
Point[] tmp = new Point[1];
tmp[0] = new Point(m_FocusCol, m_FocusRow);
return tmp;
}
return (Point[]) m_Selection.toArray(new Point[0]);
}
}