blob: 0a29d8190df892667b549402a017314ea5dea2f3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.bpel.ui.util;
import org.eclipse.bpel.ui.Messages;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.ACC;
import org.eclipse.swt.accessibility.Accessible;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleControlAdapter;
import org.eclipse.swt.accessibility.AccessibleControlEvent;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.TypedListener;
/**
* A modification of the SWT TableCursor class to better handle empty tables and dynamic tables
*/
public class TableCursor extends Canvas {
Table table;
int row = -1, column = 0; // having row negative will end up hiding the cursor
Listener tableListener, resizeListener;
boolean progVisible = false;
boolean userVisible = true;
boolean hasFocus = false;
AccessibleAdapter accessAdapter = null;
Listener selectionAccessListener = null;
Listener focusAccessListener = null;
AccessibleControlAdapter accessControlAdapter = null;
boolean hasAccessibility = false;
public TableCursor(Table parent, int style) {
super(parent, style);
table = parent;
Listener listener = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Dispose :
dispose(event);
break;
case SWT.KeyDown :
keyDown(event);
break;
case SWT.Paint :
paint(event);
break;
case SWT.Traverse :
traverse(event);
break;
}
}
};
addListener(SWT.Dispose, listener);
addListener(SWT.KeyDown, listener);
addListener(SWT.Paint, listener);
addListener(SWT.Traverse, listener);
tableListener = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.MouseDown :
tableMouseDown(event);
break;
case SWT.FocusIn :
tableFocusIn(event);
break;
}
}
};
table.addListener(SWT.FocusIn, tableListener);
table.addListener(SWT.MouseDown, tableListener);
resizeListener = new Listener() {
public void handleEvent(Event event) {
resize();
}
};
ScrollBar hBar = table.getHorizontalBar();
if (hBar != null)
hBar.addListener(SWT.Selection, resizeListener);
ScrollBar vBar = table.getVerticalBar();
if (vBar != null)
vBar.addListener(SWT.Selection, resizeListener);
this.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
hasFocus = true;
redraw();
}
public void focusLost(FocusEvent e) {
hasFocus = false;
redraw();
}});
refresh();
initAccessible();
}
/**
* this is called whenever the content of the table has changed, it
* will reconcile the cursor and any listeners that we need
*/
public void refresh() {
// the number of rows and columns could have changed, ideally we should track
// which columns have listeners but for the now, we'll just remove and readd
int columns = table.getColumnCount();
for (int i = 0; i < columns; i++) {
TableColumn column = table.getColumn(i);
column.removeListener(SWT.Resize, resizeListener);
}
for (int i = 0; i < columns; i++) {
TableColumn column = table.getColumn(i);
column.addListener(SWT.Resize, resizeListener);
}
// reset the row and column to be a valid one
//boolean repaint = false;
if (row >= table.getItemCount()) {
row = table.getItemCount()-1;
}
if (column >= columns) {
column = columns - 1;
}
// check to see what the selection is, and reset the tablecursor to
// a valid row/column in that selection
TableItem[] selection = table.getSelection();
if (selection.length == 0) {
row = -1;
}
else {
// // there is a selection, so make sure our table cursor is in that selection
// // range
// int min = 999999;
// int max = -1;
// for (int i = 0; i < selection.length; i++) {
// int temp = table.indexOf(selection[i]);
// min = Math.min(temp, min);
// max = Math.max(temp, max);
// }
// if (row > max || row < min)
// row = min;
}
setSelection(row, column);
}
public void addSelectionListener(SelectionListener listener) {
checkWidget();
if (listener == null)
SWT.error(SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener(listener);
addListener(SWT.Selection, typedListener);
addListener(SWT.DefaultSelection, typedListener);
}
void dispose(Event event) {
Display display = getDisplay();
display.asyncExec(new Runnable() {
public void run() {
if (table.isDisposed())
return;
table.removeListener(SWT.FocusIn, tableListener);
table.removeListener(SWT.MouseDown, tableListener);
int columns = table.getColumnCount();
for (int i = 0; i < columns; i++) {
TableColumn column = table.getColumn(i);
column.removeListener(SWT.Resize, resizeListener);
}
ScrollBar hBar = table.getHorizontalBar();
if (hBar != null) {
hBar.removeListener(SWT.Selection, resizeListener);
}
ScrollBar vBar = table.getVerticalBar();
if (vBar != null) {
vBar.removeListener(SWT.Selection, resizeListener);
}
}
});
}
void keyDown(Event event) {
switch (event.character) {
case SWT.CR :
notifyListeners(SWT.DefaultSelection, new Event());
return;
}
switch (event.keyCode) {
case SWT.ARROW_UP :
if (column < 0)
column = 0;
setRowColumn(row - 1, column, true);
break;
case SWT.ARROW_DOWN :
if (column < 0)
column = 0;
setRowColumn(row + 1, column, true);
break;
case SWT.ARROW_LEFT :
case SWT.ARROW_RIGHT :
{
if (column < 0)
column = 0;
int leadKey = (getStyle() & SWT.RIGHT_TO_LEFT) != 0 ? SWT.ARROW_RIGHT : SWT.ARROW_LEFT;
if (event.keyCode == leadKey) {
setRowColumn(row, column - 1, true);
} else {
setRowColumn(row, column + 1, true);
}
break;
}
case SWT.HOME :
if (column < 0)
column = 0;
setRowColumn(0, column, true);
break;
case SWT.END :
{
if (column < 0)
column = 0;
int row = table.getItemCount() - 1;
setRowColumn(row, column, true);
break;
}
}
}
void paint(Event event) {
GC gc = event.gc;
Display display = getDisplay();
gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION));
gc.fillRectangle(event.x, event.y, event.width, event.height);
TableItem item = null;
if (row >= 0)
item = table.getItem(row);
int x = 0, y = 0;
Point size = getSize();
if (item != null) {
Image image = item.getImage(column);
if (image != null) {
Rectangle imageSize = image.getBounds();
int imageY = y + (int) (((float)size.y - (float)imageSize.height) / 2.0);
gc.drawImage(image, x, imageY);
x += imageSize.width;
}
x += (column == 0) ? 2 : 6;
int textY = y + (int) (((float)size.y - (float)gc.getFontMetrics().getHeight()) / 2.0);
gc.drawString(item.getText(column), x, textY);
}
if (isFocusControl()) {
gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE));
gc.drawFocus(0, 0, size.x, size.y);
}
}
void tableFocusIn(Event event) {
if (isDisposed())
return;
if (isVisible()) {
setFocus();
redraw();
}
}
void tableMouseDown(Event event) {
event.doit = true;
if (isDisposed() || !isVisible())
return;
Point pt = new Point(event.x, event.y);
Rectangle clientRect = table.getClientArea();
int columns = table.getColumnCount();
int start = table.getTopIndex();
int end = table.getItemCount();
for (int row = start; row < end; row++) {
TableItem item = table.getItem(row);
for (int column = 0; column < columns; column++) {
Rectangle rect = item.getBounds(column);
if (rect.y > clientRect.y + clientRect.height)
return;
if (rect.contains(pt)) {
setRowColumn(row, column, true);
//setFocus();
return;
}
}
}
}
void traverse(Event event) {
switch (event.detail) {
case SWT.TRAVERSE_ARROW_NEXT :
case SWT.TRAVERSE_ARROW_PREVIOUS :
case SWT.TRAVERSE_RETURN :
event.doit = false;
return;
}
event.doit = true;
}
void setRowColumn(int row, int column, boolean notify) {
if (0 <= row && row < table.getItemCount()) {
if (0 <= column && column < table.getColumnCount()) {
this.row = row;
this.column = column;
TableItem item = table.getItem(row);
table.showItem(item);
setBounds(item.getBounds(column));
// redraw();
if (notify) {
notifyListeners(SWT.Selection, new Event());
}
}
}
redraw();
updateVisible();
}
@Override
public void setVisible(boolean visible) {
checkWidget();
userVisible = visible;
resize();
}
void resize() {
if (row >= 0 && row < table.getItemCount()) {
TableItem item = table.getItem(row);
setBounds(item.getBounds(column));
}
updateVisible();
}
void updateVisible() {
progVisible = false;
if (0 <= row && row < table.getItemCount()) {
if (0 <= column && column < table.getColumnCount()) {
progVisible = true;
}
}
super.setVisible(progVisible && userVisible);
}
public int getColumn() {
checkWidget();
return column;
}
public TableItem getRow() {
checkWidget();
if (table.getItemCount() == 0)
return null;
return table.getItem(row);
}
public void setSelection(int row, int column) {
checkWidget();
setRowColumn(row, column, false);
}
public void setSelection(TableItem row, int column) {
checkWidget();
setRowColumn(table.indexOf(row), column, false);
}
private void initAccessible() {
final Accessible accessible = getAccessible();
if (accessAdapter == null) {
accessAdapter = new AccessibleAdapter() {
@Override
public void getName(AccessibleEvent e) {
String name = null;
TableItem item = null;
TableColumn[] tableColumns = table.getColumns();
TableColumn thisCol = null;
if (row >= 0 && row < table.getItemCount() && column >= 0 && column < table.getColumnCount()) {
item = table.getItem(row);
if (column >= 0 && column < tableColumns.length) {
thisCol = tableColumns[column];
}
}
if (item != null) {
if (thisCol != null)
name = thisCol.getText();
if (name != null && name.length() > 0)
name = name + "=" + item.getText(column); //$NON-NLS-1$
else
name = item.getText(column);
}
e.result = name;
}
@Override
public void getHelp(AccessibleEvent e) {
String help = null;
e.result = help;
}
@Override
public void getKeyboardShortcut(AccessibleEvent e) {
}
};
accessControlAdapter = new AccessibleControlAdapter() {
@Override
public void getChildAtPoint(AccessibleControlEvent e) {
Point testPoint = toControl(new Point(e.x, e.y));
int childID = ACC.CHILDID_NONE;
if (childID == ACC.CHILDID_NONE) {
Rectangle location = getBounds();
location.height = location.height - getClientArea().height;
if (location.contains(testPoint)) {
childID = ACC.CHILDID_SELF;
}
}
e.childID = childID;
}
@Override
public void getLocation(AccessibleControlEvent e) {
Rectangle location = null;
int childID = e.childID;
if (childID == ACC.CHILDID_SELF) {
location = getBounds();
}
if (location != null) {
Point pt = toDisplay(new Point(location.x, location.y));
e.x = pt.x;
e.y = pt.y;
e.width = location.width;
e.height = location.height;
}
}
@Override
public void getChildCount(AccessibleControlEvent e) {
e.detail = 0;
}
@Override
public void getDefaultAction(AccessibleControlEvent e) {
String action = Messages.TableCursor_ScreenReader_Cell_Action1;
e.result = action;
}
@Override
public void getFocus(AccessibleControlEvent e) {
int childID = ACC.CHILDID_NONE;
if (isFocusControl()) {
childID = ACC.CHILDID_SELF;
}
e.childID = childID;
}
@Override
public void getRole(AccessibleControlEvent e) {
int role = 0;
int childID = e.childID;
if (childID == ACC.CHILDID_SELF)
role = ACC.ROLE_LISTITEM;
e.detail = role;
}
@Override
public void getSelection(AccessibleControlEvent e) {
e.childID = ACC.CHILDID_NONE;
}
@Override
public void getState(AccessibleControlEvent e) {
int state = 0;
int childID = e.childID;
if (childID == ACC.CHILDID_SELF) {
state = ACC.STATE_SELECTABLE;
if (isFocusControl()) {
state |= ACC.STATE_FOCUSABLE;
if (TableCursor.this.hasFocus) {
state += ACC.STATE_FOCUSED | ACC.STATE_SELECTED;
}
}
}
e.detail = state;
}
@Override
public void getChildren(AccessibleControlEvent e) {
e.children = null;
}
};
selectionAccessListener = new Listener() {
public void handleEvent(Event event) {
accessible.setFocus(ACC.CHILDID_SELF);
}
};
focusAccessListener = new Listener() {
public void handleEvent(Event event) {
accessible.setFocus(ACC.CHILDID_SELF);
}
};
}
if (hasAccessibility) {
accessible.removeAccessibleListener(accessAdapter);
accessible.removeAccessibleControlListener(accessControlAdapter);
removeListener(SWT.Selection, selectionAccessListener);
removeListener(SWT.FocusIn, focusAccessListener);
hasAccessibility = false;
}
if (hasAccessibility == false) {
accessible.addAccessibleListener(accessAdapter);
accessible.addAccessibleControlListener(accessControlAdapter);
addListener(SWT.Selection, selectionAccessListener);
addListener(SWT.FocusIn, focusAccessListener);
hasAccessibility = true;
}
}
}