[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
Re: [platform-ui-dev] Proposing a change to how cell editors are used in TableViewer
|
Abeer,
The use case and your change look reasonable overall. Ideally we'd do it
by augmenting the existing viewers rather than defining new ones though.
The best approach would be for you to file this as an enhancement request
in bugzilla, and we could then proceed from there.
Regards,
Nick
Abeer <abeer@xxxxxxxxxx>
Sent by: platform-ui-dev-admin@xxxxxxxxxxx
07/23/2004 04:41 AM
Please respond to
platform-ui-dev
To
platform-ui-dev@xxxxxxxxxxx
cc
Subject
[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);
}
}