[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[platform-ui-dev] Proposing a change to how cell editors are used in TableViewer
|
Hi,
I am working a lot with Table and TableViewer classes, and have the
following requirements:
If the celleditor control is a combo box, the values list has to be
populated dynamically depending on the data in the selected row
(TableItem).
Also, sometimes, i have to dynamically change the control being offered
as a cell editor depending on the data in the selected TableItem. (eg:
many times i have to dynamically decide between a Text and a Combo
control for that column (both are valid in specific cicumstances).
There is no provision currently in the Eclipse source for doing this,
so i have created a subinterface of the ICellModifier interface, and
have added a hack to the TableViewerImpl class (in
activateCellEditor()). I also had to hack the TableViewer class to use
my class intead of TableViewerImpl. Actually, the change is just of one
line in TableViewerImpl. I am attaching the three source files. Please
tell me if this change is possible to the jface codebase, else i will
have to maintain my code in sync with the jface code.
Thanx in advance
Abeer
P.S.: I am also attaching an application specific implementation of the
INPCellModifier, to illustrate how i am using this interface.
package com.kenati.npeint.tools.cliide.ui.widgets;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
/**
* @author abeer
*/
public interface INPCellModifier extends ICellModifier
{
public CellEditor getCellEditor(Object element, String property);
}
package com.kenati.npeint.tools.cliide.ui.widgets;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IFontProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.IViewerLabelProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerLabel;
import org.eclipse.jface.viewers.ViewerSorter;
/**
* We are using all the code from the TableViewer class as is since the
* TableViewer is not intended to be subclassed.
* We have only two changes in this class
* TableViewer uses the class TableViewerImpl and we want to use
* the class NPTableViewerImpl instead.
* Also we are using the interface INPCellModifier instead of ICellModifier
* We need maintain to this class in sync with future releases of Eclipse
*/
public class NPTableViewer extends StructuredViewer {
/**
* Internal table viewer implementation.
*/
/**
* ****************************
* Abeer :) - this is the only diff between TableViewer and NPTableViewer
* using NPTableViewerImpl instead of TableViewerImpl
* ****************************
*/
private NPTableViewerImpl tableViewerImpl;
/**
* This viewer's table control.
*/
private Table table;
/**
* This viewer's table editor.
*/
private TableEditor tableEditor;
/**
* Creates a table viewer on a newly-created table control under the given parent.
* The table control is created using the SWT style bits <code>MULTI, H_SCROLL, V_SCROLL,</code> and <code>BORDER</code>.
* The viewer has no input, no content provider, a default label provider,
* no sorter, and no filters. The table has no columns.
*
* @param parent the parent control
*/
public NPTableViewer(Composite parent) {
this(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
}
/**
* Creates a table viewer on a newly-created table control under the given parent.
* The table control is created using the given style bits.
* The viewer has no input, no content provider, a default label provider,
* no sorter, and no filters. The table has no columns.
*
* @param parent the parent control
* @param style SWT style bits
*/
public NPTableViewer(Composite parent, int style) {
this(new Table(parent, style));
}
/**
* Creates a table viewer on the given table control.
* The viewer has no input, no content provider, a default label provider,
* no sorter, and no filters.
*
* @param table the table control
*/
public NPTableViewer(Table table) {
this.table = table;
hookControl(table);
tableEditor = new TableEditor(table);
initTableViewerImpl();
}
/**
* Adds the given elements to this table viewer.
* If this viewer does not have a sorter, the elements are added at the end
* in the order given; otherwise the elements are inserted at appropriate positions.
* <p>
* This method should be called (by the content provider) when elements
* have been added to the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* </p>
*
* @param elements the elements to add
*/
public void add(Object[] elements) {
assertElementsNotNull(elements);
Object[] filtered = filter(elements);
for (int i = 0; i < filtered.length; i++){
Object element = filtered[i];
int index = indexForElement(element);
updateItem(new TableItem(getTable(), SWT.NONE, index), element);
}
}
/**
* Adds the given element to this table viewer.
* If this viewer does not have a sorter, the element is added at the end;
* otherwise the element is inserted at the appropriate position.
* <p>
* This method should be called (by the content provider) when a single element
* has been added to the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* Note that there is another method for efficiently processing the simultaneous
* addition of multiple elements.
* </p>
*
* @param element the element to add
*/
public void add(Object element) {
add(new Object[] { element });
}
/**
* Cancels a currently active cell editor. All changes already done in the cell
* editor are lost.
*/
public void cancelEditing() {
tableViewerImpl.cancelEditing();
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
protected Widget doFindInputItem(Object element) {
if (equals(element, getRoot()))
return getTable();
return null;
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
protected Widget doFindItem(Object element) {
TableItem[] children = table.getItems();
for (int i = 0; i < children.length; i++) {
TableItem item = children[i];
Object data = item.getData();
if (data != null && equals(data, element))
return item;
}
return null;
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
protected void doUpdateItem(Widget widget, Object element, boolean fullMap) {
if (widget instanceof TableItem) {
final TableItem item = (TableItem) widget;
// remember element we are showing
if (fullMap) {
associate(element, item);
} else {
item.setData(element);
mapElement(element, item);
}
IBaseLabelProvider prov = getLabelProvider();
ITableLabelProvider tprov = null;
ILabelProvider lprov = null;
if (prov instanceof ITableLabelProvider) {
tprov = (ITableLabelProvider) prov;
}
else {
lprov = (ILabelProvider) prov;
}
int columnCount = table.getColumnCount();
TableItem ti = item;
// Also enter loop if no columns added. See 1G9WWGZ: JFUIF:WINNT - TableViewer with 0 columns does not work
for (int column = 0; column < columnCount || column == 0; column++) {
// Similar code in TableTreeViewer.doUpdateItem()
String text = "";//$NON-NLS-1$
Image image = null;
if (tprov != null) {
text = tprov.getColumnText(element, column);
image = tprov.getColumnImage(element, column);
}
else {
if (column == 0) {
if (lprov instanceof IViewerLabelProvider) {
IViewerLabelProvider itemProvider = (IViewerLabelProvider) lprov;
ViewerLabel updateLabel = new ViewerLabel(item.getText(),item.getImage());
itemProvider.updateLabel(updateLabel, element);
text = updateLabel.getText();
image = updateLabel.getImage();
}
else{
text = lprov.getText(element);
image = lprov.getImage(element);
}
}
}
ti.setText(column, text);
if (ti.getImage(column) != image) {
ti.setImage(column, image);
}
}
if (prov instanceof IColorProvider) {
IColorProvider cprov = (IColorProvider) prov;
ti.setForeground(cprov.getForeground(element));
ti.setBackground(cprov.getBackground(element));
}
if (prov instanceof IFontProvider) {
IFontProvider fprov = (IFontProvider) prov;
ti.setFont(fprov.getFont(element));
}
}
}
/**
* Starts editing the given element.
*
* @param element the element
* @param column the column number
*/
public void editElement(Object element, int column) {
tableViewerImpl.editElement(element,column);
}
/**
* Returns the cell editors of this table viewer.
*
* @return the list of cell editors
*/
public CellEditor[] getCellEditors() {
return tableViewerImpl.getCellEditors();
}
/**
* Returns the cell modifier of this table viewer.
*
* @return the cell modifier
*/
public ICellModifier getCellModifier() {
return tableViewerImpl.getCellModifier();
}
/**
* Returns the column properties of this table viewer.
* The properties must correspond with the columns of the table control.
* They are used to identify the column in a cell modifier.
*
* @return the list of column properties
*/
public Object[] getColumnProperties() {
return tableViewerImpl.getColumnProperties();
}
/* (non-Javadoc)
* Method declared on Viewer.
*/
public Control getControl() {
return table;
}
/**
* Returns the element with the given index from this table viewer.
* Returns <code>null</code> if the index is out of range.
* <p>
* This method is internal to the framework.
* </p>
*
* @param index the zero-based index
* @return the element at the given index, or <code>null</code> if the
* index is out of range
*/
public Object getElementAt(int index) {
if (index >= 0 && index < table.getItemCount()) {
TableItem i = table.getItem(index);
if(i != null)
return i.getData();
}
return null;
}
/**
* The table viewer implementation of this <code>Viewer</code> framework
* method returns the label provider, which in the case of table
* viewers will be an instance of either <code>ITableLabelProvider</code>
* or <code>ILabelProvider</code>.
* If it is an <code>ITableLabelProvider</code>, then it provides a
* separate label text and image for each column. If it is an
* <code>ILabelProvider</code>, then it provides only the label text
* and image for the first column, and any remaining columns are blank.
*/
public IBaseLabelProvider getLabelProvider() {
return super.getLabelProvider();
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
protected List getSelectionFromWidget() {
Widget[] items = table.getSelection();
ArrayList list = new ArrayList(items.length);
for (int i = 0; i < items.length; i++) {
Widget item = items[i];
Object e = item.getData();
if (e != null)
list.add(e);
}
return list;
}
/**
* Returns this table viewer's table control.
*
* @return the table control
*/
public Table getTable() {
return table;
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
protected void hookControl(Control control) {
super.hookControl(control);
Table tableControl = (Table)control;
tableControl.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
tableViewerImpl.handleMouseDown(e);
}
});
}
/*
* Returns the index where the item should be inserted.
*/
protected int indexForElement(Object element) {
ViewerSorter sorter = getSorter();
if(sorter == null)
return table.getItemCount();
int count = table.getItemCount();
int min = 0, max = count - 1;
while (min <= max) {
int mid = (min + max) / 2;
Object data = table.getItem(mid).getData();
int compare = sorter.compare(this, data, element);
if (compare == 0) {
// find first item > element
while (compare == 0) {
++mid;
if (mid >= count) {
break;
}
data = table.getItem(mid).getData();
compare = sorter.compare(this, data, element);
}
return mid;
}
if (compare < 0)
min = mid + 1;
else
max = mid - 1;
}
return min;
}
/**
* Initializes the table viewer implementation.
*/
/**
* ****************************
* Abeer :) - this is the only diff between TableViewer and NPTableViewer
* using NPTableViewerImpl instead of TableViewerImpl
* ****************************
*/
private void initTableViewerImpl() {
tableViewerImpl = new NPTableViewerImpl(this) {
Rectangle getBounds(Item item, int columnNumber) {
return ((TableItem)item).getBounds(columnNumber);
}
int getColumnCount() {
return getTable().getColumnCount();
}
Item[] getSelection() {
return getTable().getSelection();
}
void setEditor(Control w, Item item, int columnNumber) {
tableEditor.setEditor(w, (TableItem)item, columnNumber);
}
void setSelection(StructuredSelection selection, boolean b) {
NPTableViewer.this.setSelection(selection,b);
}
void showSelection() {
getTable().showSelection();
}
void setLayoutData(CellEditor.LayoutData layoutData) {
tableEditor.grabHorizontal = layoutData.grabHorizontal;
tableEditor.horizontalAlignment = layoutData.horizontalAlignment;
tableEditor.minimumWidth = layoutData.minimumWidth;
}
void handleDoubleClickEvent() {
Viewer viewer = getViewer();
fireDoubleClick (new DoubleClickEvent(viewer, viewer.getSelection()));
fireOpen (new OpenEvent(viewer, viewer.getSelection()));
}
};
}
/* (non-Javadoc)
* Method declared on Viewer.
*/
protected void inputChanged(Object input, Object oldInput) {
getControl().setRedraw(false);
try {
// refresh() attempts to preserve selection, which we want here
refresh();
}
finally {
getControl().setRedraw(true);
}
}
/**
* Inserts the given element into this table viewer at the given position.
* If this viewer has a sorter, the position is ignored and the element is inserted
* at the correct position in the sort order.
* <p>
* This method should be called (by the content provider) when elements
* have been added to the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* </p>
*
* @param element the element
* @param position a 0-based position relative to the model, or -1 to indicate the last position
*/
public void insert(Object element, int position) {
tableViewerImpl.applyEditorValue();
if (getSorter() != null || hasFilters()) {
add(element);
return;
}
if (position == -1)
position = table.getItemCount();
updateItem(new TableItem(table, SWT.NONE, position), element);
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
protected void internalRefresh(Object element) {
internalRefresh(element, true);
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
protected void internalRefresh(Object element, boolean updateLabels) {
tableViewerImpl.applyEditorValue();
if (element == null || equals(element, getRoot())) {
// the parent
// in the code below, it is important to do all disassociates
// before any associates, since a later disassociate can undo an earlier associate
// e.g. if (a, b) is replaced by (b, a), the disassociate of b to item 1 could undo
// the associate of b to item 0.
Object[] children = getSortedChildren(getRoot());
TableItem[] items = table.getItems();
int min = Math.min(children.length, items.length);
for (int i = 0; i < min; ++i) {
// if the element is unchanged, update its label if appropriate
if (equals(children[i], items[i].getData())) {
if (updateLabels) {
updateItem(items[i], children[i]);
}
else {
// associate the new element, even if equal to the old one,
// to remove stale references (see bug 31314)
associate(children[i], items[i]);
}
}
else {
// updateItem does an associate(...), which can mess up
// the associations if the order of elements has changed.
// E.g. (a, b) -> (b, a) first replaces a->0 with b->0, then replaces b->1 with a->1, but this actually removes b->0.
// So, if the object associated with this item has changed,
// just disassociate it for now, and update it below.
items[i].setText(""); //$NON-NLS-1$
items[i].setImage(new Image[0]);
disassociate(items[i]);
}
}
// dispose of all items beyond the end of the current elements
if (min < items.length) {
for (int i = items.length; --i >= min;) {
disassociate(items[i]);
}
table.remove(min, items.length-1);
}
// Workaround for 1GDGN4Q: ITPUI:WIN2000 - TableViewer icons get scrunched
if (table.getItemCount() == 0) {
table.removeAll();
}
// Update items which were removed above
for (int i = 0; i < min; ++i) {
if (items[i].getData() == null) {
updateItem(items[i], children[i]);
}
}
// add any remaining elements
for (int i = min; i < children.length; ++i) {
updateItem(new TableItem(table, SWT.NONE, i), children[i]);
}
}
else {
Widget w = findItem(element);
if (w != null) {
updateItem(w, element);
}
}
}
/**
* Removes the given elements from this table viewer.
*
* @param elements the elements to remove
*/
private void internalRemove(final Object[] elements) {
Object input = getInput();
for (int i = 0; i < elements.length; ++i) {
if (equals(elements[i], input)) {
setInput(null);
return;
}
}
// use remove(int[]) rather than repeated TableItem.dispose() calls
// to allow SWT to optimize multiple removals
int[] indices = new int[elements.length];
int count = 0;
for (int i = 0; i < elements.length; ++i) {
Widget w = findItem(elements[i]);
if (w instanceof TableItem) {
TableItem item = (TableItem) w;
disassociate(item);
indices[count++] = table.indexOf(item);
}
}
if (count < indices.length) {
System.arraycopy(indices, 0, indices = new int[count], 0, count);
}
table.remove(indices);
// Workaround for 1GDGN4Q: ITPUI:WIN2000 - TableViewer icons get scrunched
if (table.getItemCount() == 0) {
table.removeAll();
}
}
/**
* Returns whether there is an active cell editor.
*
* @return <code>true</code> if there is an active cell editor, and
* <code>false</code> otherwise
*/
public boolean isCellEditorActive() {
return tableViewerImpl.isCellEditorActive();
}
/**
* Removes the given elements from this table viewer.
* The selection is updated if required.
* <p>
* This method should be called (by the content provider) when elements
* have been removed from the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* </p>
*
* @param elements the elements to remove
*/
public void remove(final Object[] elements) {
assertElementsNotNull(elements);
preservingSelection(new Runnable() {
public void run() {
internalRemove(elements);
}
});
}
/**
* Removes the given element from this table viewer.
* The selection is updated if necessary.
* <p>
* This method should be called (by the content provider) when a single element
* has been removed from the model, in order to cause the viewer to accurately
* reflect the model. This method only affects the viewer, not the model.
* Note that there is another method for efficiently processing the simultaneous
* removal of multiple elements.
* </p>
*
* @param element the element
*/
public void remove(Object element) {
remove(new Object[] { element });
}
/*
* Non-Javadoc.
* Method defined on StructuredViewer.
*/
public void reveal(Object element) {
Assert.isNotNull(element);
Widget w = findItem(element);
if (w instanceof TableItem)
getTable().showItem((TableItem) w);
}
/**
* Sets the cell editors of this table viewer.
*
* @param editors the list of cell editors
*/
public void setCellEditors(CellEditor[] editors) {
tableViewerImpl.setCellEditors(editors);
}
/**
* Sets the cell modifier of this table viewer.
*
* @param modifier the cell modifier
*/
public void setCellModifier(INPCellModifier modifier) {
tableViewerImpl.setCellModifier(modifier);
}
/**
* Sets the column properties of this table viewer.
* The properties must correspond with the columns of the table control.
* They are used to identify the column in a cell modifier.
*
* @param columnProperties the list of column properties
*/
public void setColumnProperties(String[] columnProperties) {
tableViewerImpl.setColumnProperties(columnProperties);
}
/**
* The table viewer implementation of this <code>Viewer</code> framework
* method ensures that the given label provider is an instance
* of either <code>ITableLabelProvider</code> or <code>ILabelProvider</code>.
* If it is an <code>ITableLabelProvider</code>, then it provides a
* separate label text and image for each column. If it is an
* <code>ILabelProvider</code>, then it provides only the label text
* and image for the first column, and any remaining columns are blank.
*/
public void setLabelProvider(IBaseLabelProvider labelProvider) {
Assert.isTrue(labelProvider instanceof ITableLabelProvider || labelProvider instanceof ILabelProvider );
super.setLabelProvider(labelProvider);
}
/* (non-Javadoc)
* Method declared on StructuredViewer.
*/
protected void setSelectionToWidget(List list, boolean reveal) {
if (list == null) {
table.deselectAll();
return;
}
int size = list.size();
TableItem[] items = new TableItem[size];
TableItem firstItem = null;
int count = 0;
for (int i = 0; i < size; ++i) {
Object o = list.get(i);
Widget w = findItem(o);
if (w instanceof TableItem) {
TableItem item = (TableItem) w;
items[count++] = item;
if (firstItem == null)
firstItem = item;
}
}
if (count < size) {
System.arraycopy(items, 0, items = new TableItem[count], 0, count);
}
table.setSelection(items);
if (reveal && firstItem != null) {
table.showItem(firstItem);
}
}
}
package com.kenati.npeint.tools.cliide.ui.widgets;
/**
* @author abeer
* We are using all the code from the TableViewerImpl class as is since
* access to the TableViewerImpl class is restricted to its package only
* We are using INPCellModifier instead of ICellModifier
* We need to change only one line of code:
* in method activateCellEditor(),
* instead of "cellEditor = cellEditors[columnNumber];"
* we are using "cellEditor = cellModifier.getCellEditor(element, property);"
* We need maintain to this class in sync with future releases of Eclipse
*/
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellEditorListener;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;
/* package */ abstract class NPTableViewerImpl {
private CellEditor cellEditor;
private CellEditor[] cellEditors;
private INPCellModifier cellModifier;
private String[] columnProperties;
private Item tableItem;
private int columnNumber;
private ICellEditorListener cellEditorListener;
private FocusListener focusListener;
private MouseListener mouseListener;
private int doubleClickExpirationTime;
private StructuredViewer viewer;
NPTableViewerImpl(StructuredViewer viewer) {
this.viewer = viewer;
initCellEditorListener();
}
/**
* Returns this <code>TableViewerImpl</code> viewer
*
* @return the viewer
*/
public StructuredViewer getViewer() {
return viewer;
}
private void activateCellEditor() {
if(cellModifier != null) {
Object element = tableItem.getData();
String property = columnProperties[columnNumber];
if (cellModifier.canModify(element, property)) {
/*****************************
* Abeer :) - this is the only diff between TableViewerImpl and NPTableViewerImpl
* instead of "cellEditor = cellEditors[columnNumber];"
* we are using "cellEditor = cellModifier.getCellEditor(element, property);"
*****************************/
//cellEditor = cellEditors[columnNumber];
cellEditor = cellModifier.getCellEditor(element, property);
//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.
final 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);
mouseListener = new MouseAdapter() {
public void mouseDown(MouseEvent e) {
// time wrap?
// check for expiration of doubleClickTime
if (e.time <= doubleClickExpirationTime ) {
control.removeMouseListener(mouseListener);
cancelEditing();
handleDoubleClickEvent();
} else if (mouseListener != null) {
control.removeMouseListener(mouseListener);
}
}
};
control.addMouseListener(mouseListener);
}
}
}
/**
* 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);
Control control = c.getControl();
if (control != null) {
if (mouseListener != null) {
control.removeMouseListener(mouseListener);
}
if (focusListener != null) {
control.removeFocusListener(focusListener);
}
}
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 mouse down event; activates the cell editor.
*/
public void handleMouseDown(MouseEvent event) {
if (event.button != 1)
return;
if (cellEditor != null)
applyEditorValue();
// activate the cell editor immediately. If a second mouseDown
// is received prior to the expiration of the doubleClick time then
// the cell editor will be deactivated and a doubleClick event will
// be processed.
//
doubleClickExpirationTime = event.time + Display.getCurrent().getDoubleClickTime();
Item[] items = getSelection();
// Do not edit if more than one row is selected.
if (items.length != 1) {
tableItem = null;
return;
}
tableItem = items[0];
activateCellEditor(event);
}
private void initCellEditorListener() {
cellEditorListener = new ICellEditorListener() {
public void editorValueChanged(boolean oldValidState, boolean newValidState) {
// Ignore.
}
public void cancelEditor() {
NPTableViewerImpl.this.cancelEditing();
}
public void applyEditorValue() {
NPTableViewerImpl.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;
}
/**
* 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(INPCellModifier 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();
abstract void handleDoubleClickEvent();
}
package com.kenati.npeint.tools.cliide.ui.dialogs;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.TableItem;
import com.kenati.npeint.tools.cliide.ui.model.PromptElementList;
import com.kenati.npeint.tools.cliide.ui.model.PromptElementTO;
import com.kenati.npeint.tools.cliide.ui.widgets.INPCellModifier;
import com.kenati.npeint.tools.cliide.ui.widgets.NPTableViewer;
import com.kenati.npeint.tools.common.Constants;
public class PromptElementCellModifier implements INPCellModifier
{
private NPTableViewer tableViewer;
private PromptElementList elementList;
// column indices
private static final int COL_TYPE = 0;
private static final int COL_VALUE = 1;
// column 1 : type (Combo box)
private ComboBoxCellEditor typeEditor;
private String noItems[] = {""};
// column 2 : value - use prompt names (Combo box)
private ComboBoxCellEditor usePromptNameEditor;
//OR
// column 2 : value - string / function name (Free text)
private TextCellEditor stringValueEditor;
PromptElementCellModifier(NPTableViewer tableViewer)
{
this.tableViewer = tableViewer;
// column 1 : filter criterias (Combo box)
typeEditor = new ComboBoxCellEditor(tableViewer.getTable(), noItems, SWT.READ_ONLY);
// column 2 : value - use prompt names (Combo box)
usePromptNameEditor = new ComboBoxCellEditor(tableViewer.getTable(), noItems, SWT.READ_ONLY);
// Column 2 : string / function name (Free text)
stringValueEditor = new TextCellEditor(tableViewer.getTable());
}
public void setParamList(PromptElementList elementList)
{
this.elementList = elementList;
}
public CellEditor getCellEditor(Object element, String property)
{
// get the index of the column
int colIndex = -1;
for(int i=0; i<tableViewer.getTable().getColumnCount(); i++)
if (property.equalsIgnoreCase(tableViewer.getTable().getColumn(i).getText()))
{
colIndex = i;
break;
}
switch(colIndex)
{
case COL_TYPE:
if (noItems != null)
{
typeEditor.setItems(elementList.getTypes());
noItems = null;
}
return typeEditor;
case COL_VALUE:
PromptElementTO elementTO = (PromptElementTO) element;
if (elementTO.getType().equals(Constants.ATTR_PROMPTELEMENT_STRING) || elementTO.getType().equals(Constants.ATTR_PROMPTELEMENT_FUNCTION))
return stringValueEditor;
else if (elementTO.getType().equals(Constants.ATTR_PROMPTELEMENT_USEPROMPT))
{
String[] usePromptNames = elementList.getUsePromptNames();
if (usePromptNames != null)
usePromptNameEditor.setItems(usePromptNames);
return usePromptNameEditor;
}
default:
return null;
}
}
public boolean canModify(Object element, String property)
{
//get the selected TO obj
PromptElementTO selElement = (PromptElementTO) element;
//check if the element is a new or saved one
if (selElement.isNew())
return true;
else
{
// get the index of the column
int colIndex = -1;
for(int i=0; i<tableViewer.getTable().getColumnCount(); i++)
if (property.equalsIgnoreCase(tableViewer.getTable().getColumn(i).getText()))
{
colIndex = i;
break;
}
//can only change the value but not the type
if (colIndex == 1)
return true;
else
return false;
}
}
public Object getValue(Object element, String property)
{
// get the index of the column
int colIndex = -1;
for(int i=0; i<tableViewer.getTable().getColumnCount(); i++)
if (property.equalsIgnoreCase(tableViewer.getTable().getColumn(i).getText()))
{
colIndex = i;
break;
}
Object result = null;
PromptElementTO elementTO = (PromptElementTO) element;
switch(colIndex)
{
case COL_VALUE: //value
if (elementTO.getType() == Constants.ATTR_PROMPTELEMENT_USEPROMPT)
{
// get the current use prompt name
String promptName = elementTO.getValue();
// get the list of all prompt names in the combo box
String[] usePromptNames = elementList.getUsePromptNames();
if (usePromptNames == null)
result = "";
else
{
//get the index of the current use prompt
int index = 0;
for (index=0; index<usePromptNames.length; index++)
{
if (usePromptNames[index].equals(promptName))
break;
}
if (index == usePromptNames.length)
index = 0;
result = new Integer(index);
}
}
else
{
result = elementTO.getValue();
if (result == null)
result = "";
}
break;
case COL_TYPE: //type
//get the current type
String type = elementTO.getType();
//get the list of all criterias in the combo box
String[] allTypes = elementList.getTypes();
//get the index of the current criteria
int index = 0;
for (index=0; index<allTypes.length; index++)
{
if (allTypes[index].equals(type))
break;
}
if (index == allTypes.length)
index = 0;
result = new Integer(index);
break;
}
return result;
}
public void modify(Object element, String property, Object value)
{
//get the index of the column
int colIndex = -1;
for(int i=0; i<tableViewer.getTable().getColumnCount(); i++)
if (property.equalsIgnoreCase(tableViewer.getTable().getColumn(i).getText()))
{
colIndex = i;
break;
}
TableItem item = (TableItem) element;
PromptElementTO elementTO = (PromptElementTO) item.getData();
boolean isColWidthValid = true;
switch(colIndex)
{
case COL_TYPE: //type
if (((Integer)value).intValue() == -1)
elementTO.setType("");
else
elementTO.setType((String) elementList.getTypes()[((Integer)value).intValue()]);
elementTO.setValue("");
break;
case COL_VALUE: //value
if (elementTO.getType() == Constants.ATTR_PROMPTELEMENT_USEPROMPT)
{
if (((Integer)value).intValue() == -1)
elementTO.setValue("");
else
elementTO.setValue((String) elementList.getUsePromptNames()[((Integer)value).intValue()]);
}
else
{
elementTO.setValue(((String)value).trim());
}
}
((PromptElementList) tableViewer.getInput()).elementChanged(elementTO);
}
}