| /******************************************************************************* |
| * 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; |
| } |
| } |
| } |
| |