blob: 61ae118aea8a800109f9364651c9ae118f815f23 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2005 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 Jens Lukowski/Innoopract - initial renaming/restructuring
*******************************************************************************/
package org.eclipse.wst.common.ui.internal.viewers;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableTreeViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableCursor;
import org.eclipse.swt.custom.TableTreeItem;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
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.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
/**
* Adds a TableCursor to a StructuredViewer - for keyboard navigation of the table The intent of
* this class is to provide the standard listeners for using F2 to activate cell editors. Due to a
* current bug in the TableCursor, TableViewers using this class must make a call similar to the
* TableNavigator method moveCellEditorsAbove(cellEditors) whenever a setCellEditors call is made in
* the StructuredViewer. This is so that the cell editor control shows up above the table cursor
* control.
*/
public class TableNavigator extends TableCursor {
private static final String TABLETREEITEM_ID = "TableTreeItemID";
final Table table;
public TableNavigator(Table table, StructuredViewer viewer) {
super(table, SWT.NONE);
this.table = table;
final Table currentTable = table;
final StructuredViewer sViewer = viewer;
// Linux index out of bounds fix. See defect 253429, 253433, and more
setVisible(false);
addPaintListener(viewer);
addKeyListeners(viewer);
addMouseListeners(viewer);
addSelectionListener(new SelectionAdapter() {
/**
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(SelectionEvent)
*/
public void widgetSelected(SelectionEvent e) {
super.widgetSelected(e);
if (sViewer instanceof TableTreeViewer) {
TableTreeItem tableTreeItem = (TableTreeItem) getRow().getData(TABLETREEITEM_ID);
StructuredSelection selection = new StructuredSelection(tableTreeItem.getData());
sViewer.setSelection(selection, true);
}
}
});
addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent e) {
// if e.source is not a child of the table then set selection - this is for tab into viewer
Object eventSource = e.getSource();
if (eventSource instanceof Control) {
if (!isChild(currentTable, (Control) eventSource)) {
if (currentTable.getItemCount() > 0 && currentTable.getSelectionCount() <= 0) {
if (sViewer instanceof TableTreeViewer) {
TableTreeItem tableTreeItem = (TableTreeItem) getRow().getData(TABLETREEITEM_ID);
StructuredSelection selection = new StructuredSelection(tableTreeItem.getData());
sViewer.setSelection(selection, true);
} else {
currentTable.setSelection(0);
setSelection(0, 0);
}
}
} else {
if (currentTable.getItems().length > 0) {
// cursor can end up on a non-existent table row
// currently no way to get the current table cursor row
// so for now just catch the exception since it doesn't
// cause any side effects.
try {
setVisible(true);
} catch (Exception ee) {
currentTable.setSelection(0);
setSelection(0, 0);
}
} else // do not show table cursor if there are no elements in the table - avoid repaint
{
setVisible(false);
}
}
}
}
protected boolean isChild(Control parent, Control child) {
Control tempChild = child;
while (tempChild != null) {
if (tempChild == parent) {
return true;
}
tempChild = tempChild.getParent();
}
return false;
}
/**
* @see org.eclipse.swt.events.FocusAdapter#focusLost(FocusEvent)
*/
public void focusLost(FocusEvent e) {
// Set the table navigator to be not visible if the the table
// is not in focus and a child of the table is not in focus
// note that we do this asynchronously so we don't mess up the
// current focus handling.
Display.getDefault().asyncExec(new Runnable() {
/**
* @see java.lang.Runnable#run()
*/
public void run() {
if (currentTable != null && !currentTable.isDisposed()
&& !currentTable.isFocusControl()
&& !isChild(currentTable, Display.getDefault().getFocusControl())) {
setVisible(false);
}
}
});
}
});
table.addFocusListener(new FocusAdapter() {
/**
* @see org.eclipse.swt.events.FocusListener#focusGained(FocusEvent)
*/
public void focusGained(FocusEvent e) {
// only display navigator if there are items in the table
// and if the focus wasn't gained from our own table navigator
// (ie focus came from outside)
if (currentTable.getItemCount() > 0 && (Display.getDefault().getFocusControl() != null)
&& !Display.getDefault().getFocusControl().equals(TableNavigator.this)) {
// note that we do this asynchronously so we don't mess up the
// current focus handling.
Display.getDefault().asyncExec(new Runnable() {
/**
* @see java.lang.Runnable#run()
*/
public void run() {
if (!isVisible()) {
try {
setVisible(true);
setFocus();
} catch (Exception e) {
// catch IllegalArgumentExceptions here - index out of bounds on tableviewer
if (currentTable.getItemCount() > 0) {
currentTable.setSelection(0);
setSelection(0, 0);
} else // do not show table cursor if there are no elements in the table - avoid repaint
{
setVisible(false);
}
}
}
}
});
}
}
});
}
public Table getTable() {
return table;
}
public void addPaintListener(StructuredViewer viewer) {
addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
TableItem[] selection = table.getSelection();
final TableItem row = (selection.length == 0) ? table.getItem(table.getTopIndex())
: selection[0];
final String cellText = row.getText(getColumn());
final Image cellImage = row.getImage(getColumn());
final int col = getColumn();
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
if (!row.isDisposed()) {
String newText = row.getText(getColumn());
if (!newText.equals(cellText) || !(row.getImage(col) == cellImage)) {
redraw();
}
}
}
});
}
});
}
public SelectionKeyAdapter getKeyAdapter(StructuredViewer viewer) {
if (keyAdapter == null) {
return new SelectionKeyAdapter(viewer);
} else
return keyAdapter;
}
public void setKeyAdapter(SelectionKeyAdapter kAdapter) {
keyAdapter = kAdapter;
}
protected SelectionKeyAdapter keyAdapter = null;
public class SelectionKeyAdapter extends KeyAdapter {
StructuredViewer structuredViewer;
public SelectionKeyAdapter(StructuredViewer viewer) {
super();
this.structuredViewer = viewer;
}
int lastKeyPressed = -1; // used to cache the last key for key combos
public void keyPressed(KeyEvent e) {
TableItem row = getRow();
int column = getColumn();
// hack to emulate SHIFT+F10 popup menu - otherwise table cursor
// obscures the table popup mechanism and it doesn't work.
if (lastKeyPressed == SWT.SHIFT && e.keyCode == SWT.F10) {
Menu popup = getTable().getMenu();
popup.setVisible(true);
}
lastKeyPressed = e.keyCode;
//jvh - look for + or - key
// column == 0
if (row.getData(TABLETREEITEM_ID) instanceof TableTreeItem) {
if (column == 0 && e.character == '+') {
TableTreeItem tableTreeItem = (TableTreeItem) row.getData(TABLETREEITEM_ID);
((TableTreeViewer) structuredViewer).setExpandedState(tableTreeItem.getData(), true);
refresh();
} else if (column == 0 && e.character == '-') {
TableTreeItem tableTreeItem = (TableTreeItem) row.getData(TABLETREEITEM_ID);
((TableTreeViewer) structuredViewer).setExpandedState(tableTreeItem.getData(), false);
refresh();
}
}
// use F2 to invoke editing for a cell
if (e.keyCode == SWT.F2) {
if (structuredViewer instanceof TableViewer) {
((TableViewer) structuredViewer).editElement(row.getData(), column);
} else if (structuredViewer instanceof TableTreeViewer) {
TableTreeItem tableTreeItem = (TableTreeItem) row.getData(TABLETREEITEM_ID);
((TableTreeViewer) structuredViewer).editElement(tableTreeItem.getData(), column);
}
}
}
}
public void addKeyListeners(StructuredViewer viewer) {
final StructuredViewer structuredViewer = viewer;
addKeyListener(getKeyAdapter(structuredViewer));
}
public void addMouseListeners(StructuredViewer viewer) {
final StructuredViewer structuredViewer = viewer;
addMouseListener(new MouseAdapter() {
public void mouseUp(MouseEvent e) {
TableItem row = getRow();
int column = getColumn();
// use mouse button 1 to invoke editing for a cell
if (e.button == 1) {
if (structuredViewer instanceof TableViewer) {
((TableViewer) structuredViewer).editElement(row.getData(), column);
} else if (structuredViewer instanceof TableTreeViewer && column == 1) {
TableTreeItem tableTreeItem = (TableTreeItem) row.getData(TABLETREEITEM_ID);
((TableTreeViewer) structuredViewer).editElement(tableTreeItem.getData(), column);
}
if (structuredViewer instanceof TableTreeViewer
&& row.getData(TABLETREEITEM_ID) instanceof TableTreeItem) {
if (column == 0) {
TableTreeItem tableTreeItem = (TableTreeItem) row.getData(TABLETREEITEM_ID);
boolean expandState = tableTreeItem.getExpanded();
((TableTreeViewer) structuredViewer).setExpandedState(tableTreeItem.getData(),
!expandState);
refresh();
}
}
}
}
});
}
/**
* Ensure that cell editor control shows up above the table cursor control. Should be called
* whenever the table viewer makes a new call to setCellEditors i.e. in constructor and in
* refreshCellEditors
*
* @param - array of cell editors for the StructuredViewer
*/
public void moveCellEditorsAbove(CellEditor[] editorArray) {
for (int i = 0; i < editorArray.length; i++) {
CellEditor cEd = editorArray[i];
if (cEd != null && cEd.getControl() != null) {
cEd.getControl().moveAbove(null);
}
}
}
public void refresh() {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
if (!isDisposed() && isVisible())
redraw();
}
});
}
}