| Summary: |
[CellEditors] [Viewers] Proposing a change to how cell editors are used in TableViewer |
| Product: |
[Eclipse Project] Platform
|
Reporter: |
Abeer Bagul <abeerbagul> |
| Component: |
UI | Assignee: |
Eric Moffatt <emoffatt> |
| Status: |
CLOSED
FIXED
|
QA Contact: |
|
| Severity: |
enhancement
|
|
|
| Priority: |
P4
|
CC: |
bokowski, bradleyjames, daveo, heath.borders, mlists, n.a.edgar, Serge_Yuschenko, Tod_Creasey, tom.schindl, vulcannis
|
| Version: |
3.0 | |
|
| Target Milestone: |
3.3 M2 | |
|
| Hardware: |
PC | |
|
| OS: |
All | |
|
| Whiteboard: |
|
| Bug Depends on: |
149193
|
|
|
| Bug Blocks: |
|
|
|
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 (called PromptElementCellModifier), to illustrate how i am using this interface. **** INPCellModifier**** 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); } ****NPTableViewer**** 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); } } } ****NPTableViewerImpl**** 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(); } ****PromptElementCellModifier**** 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); } }