blob: c683bf9bc9acc97fa127575a9b86bb4f9a4938cc [file] [log] [blame]
package org.eclipse.jface.viewers;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.custom.TableEditor;
import java.util.*;
/**
* Internal table viewer implementation.
*/
/* package */ abstract class TableViewerImpl {
private boolean isActivating = false;
private CellEditor cellEditor;
private CellEditor[] cellEditors;
private ICellModifier cellModifier;
private String[] columnProperties;
private Item tableItem;
private int columnNumber;
private ICellEditorListener cellEditorListener;
private FocusListener focusListener;
TableViewerImpl() {
initCellEditorListener();
}
/**
* Activate a cell editor for the given column.
*/
private void activateCellEditor() {
if (cellEditors != null) {
if(cellEditors[columnNumber] != null && cellModifier != null) {
Object element = tableItem.getData();
String property = columnProperties[columnNumber];
if (cellModifier.canModify(element, property)) {
cellEditor = cellEditors[columnNumber];
//table.showSelection();
cellEditor.addListener(cellEditorListener);
Object value = cellModifier.getValue(element, property);
cellEditor.setValue(value);
// Tricky flow of control here:
// activate() can trigger callback to cellEditorListener which will clear cellEditor
// so must get control first, but must still call activate() even if there is no control.
Control control = cellEditor.getControl();
cellEditor.activate();
if (control == null)
return;
setLayoutData(cellEditor.getLayoutData());
setEditor(control, tableItem, columnNumber);
cellEditor.setFocus();
if(focusListener == null) {
focusListener = new FocusAdapter() {
public void focusLost(FocusEvent e) {
applyEditorValue();
}
};
}
control.addFocusListener(focusListener);
}
}
}
}
/**
* Activate a cell editor for the given mouse position.
*/
private void activateCellEditor(MouseEvent event) {
if (tableItem == null || tableItem.isDisposed()) {
//item no longer exists
return;
}
int columnToEdit;
int columns = getColumnCount();
if (columns == 0) {
// If no TableColumn, Table acts as if it has a single column
// which takes the whole width.
columnToEdit = 0;
}
else {
columnToEdit = -1;
for (int i = 0; i < columns; i++) {
Rectangle bounds = getBounds(tableItem, i);
if (bounds.contains(event.x, event.y)) {
columnToEdit = i;
break;
}
}
if (columnToEdit == -1) {
return;
}
}
columnNumber = columnToEdit;
activateCellEditor();
}
/**
* Deactivates the currently active cell editor.
*/
public void applyEditorValue() {
CellEditor c = this.cellEditor;
if (c != null) {
// null out cell editor before calling save
// in case save results in applyEditorValue being re-entered
// see 1GAHI8Z: ITPUI:ALL - How to code event notification when using cell editor ?
this.cellEditor = null;
Item t = this.tableItem;
// don't null out table item -- same item is still selected
if (t != null && !t.isDisposed()) {
saveEditorValue(c, t);
}
setEditor(null, null, 0);
c.removeListener(cellEditorListener);
c.deactivate();
}
}
/**
* Cancels the active cell editor, without saving the value
* back to the domain model.
*/
public void cancelEditing() {
if (cellEditor != null) {
setEditor(null, null, 0);
cellEditor.removeListener(cellEditorListener);
CellEditor oldEditor = cellEditor;
cellEditor = null;
oldEditor.deactivate();
}
}
/**
* Start editing the given element.
*/
public void editElement(Object element, int column) {
if (cellEditor != null)
applyEditorValue();
setSelection(new StructuredSelection(element), true);
Item[] selection = getSelection();
if (selection.length != 1)
return;
tableItem = selection[0];
// Make sure selection is visible
showSelection();
columnNumber = column;
activateCellEditor();
}
abstract Rectangle getBounds(Item item, int columnNumber);
public CellEditor[] getCellEditors() {
return cellEditors;
}
public ICellModifier getCellModifier() {
return cellModifier;
}
abstract int getColumnCount();
public Object[] getColumnProperties() {
return columnProperties;
}
abstract Item[] getSelection();
/**
* Handles the double click event.
*/
public void handleMouseDoubleClick(MouseEvent event) {
//The last mouse down was a double click. Cancel
//the cell editor activation.
isActivating = false;
}
/**
* Handles the mouse down event.
* Activates the cell editor if it is not a double click.
*
* This implementation must:
* i) activate the cell editor when clicking over the item's text or over the item's image.
* ii) activate it only if the item is already selected.
* iii) do NOT activate it on a double click (whether the item is selected or not).
*/
public void handleMouseDown(MouseEvent event) {
if (event.button != 1)
return;
boolean wasActivated = isCellEditorActive();
if (wasActivated)
applyEditorValue();
Item[] items = getSelection();
// Do not edit if more than one row is selected.
if (items.length != 1) {
tableItem = null;
return;
}
if(tableItem != items[0]) {
//This mouse down was a selection. Keep the selection and return;
tableItem = items[0];
return;
}
//It may be a double click. If so, the activation was started by the first click.
if(isActivating || wasActivated)
return;
isActivating = true;
//Post the activation. So it may be canceled if it was a double click.
postActivation(event);
}
private void initCellEditorListener() {
cellEditorListener = new ICellEditorListener() {
public void editorValueChanged(boolean oldValidState, boolean newValidState) {
// Ignore.
}
public void cancelEditor() {
TableViewerImpl.this.cancelEditing();
}
public void applyEditorValue() {
TableViewerImpl.this.applyEditorValue();
}
};
}
/**
* Returns <code>true</code> if there is an active cell editor; otherwise
* <code>false</code> is returned.
*/
public boolean isCellEditorActive() {
return cellEditor != null;
}
/**
* Handle the mouse down event.
* Activate the cell editor if it is not a doble click.
*/
private void postActivation(final MouseEvent event) {
if(!isActivating)
return;
(new Thread() {
public void run() {
try { Thread.sleep(400); } catch (Exception e){}
if(isActivating) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
activateCellEditor(event);
isActivating = false;
}
});
}
}
}).start();
}
/**
* Saves the value of the currently active cell editor,
* by delegating to the cell modifier.
*/
private void saveEditorValue(CellEditor cellEditor, Item tableItem) {
if (cellModifier != null) {
if (!cellEditor.isValueValid()) {
///Do what ???
}
String property = null;
if (columnProperties != null && columnNumber < columnProperties.length)
property = columnProperties[columnNumber];
cellModifier.modify(tableItem, property, cellEditor.getValue());
}
}
public void setCellEditors(CellEditor[] editors) {
this.cellEditors = editors;
}
public void setCellModifier(ICellModifier modifier) {
this.cellModifier = modifier;
}
public void setColumnProperties(String[] columnProperties) {
this.columnProperties = columnProperties;
}
abstract void setEditor(Control w, Item item, int fColumnNumber);
abstract void setLayoutData(CellEditor.LayoutData layoutData);
abstract void setSelection(StructuredSelection selection, boolean b);
abstract void showSelection();
}