Mercurial > projects > dwt-addons
diff dwtx/jface/viewers/TableTreeViewer.d @ 10:b6c35faf97c8
Viewers
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 31 Mar 2008 00:47:19 +0200 |
parents | |
children | 644f1334b451 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwtx/jface/viewers/TableTreeViewer.d Mon Mar 31 00:47:19 2008 +0200 @@ -0,0 +1,882 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Tom Schindl <tom.schindl@bestsolution.at> - bug 153993 + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ + +module dwtx.jface.viewers.TableTreeViewer; + +import dwtx.jface.viewers.AbstractTreeViewer; +import dwtx.jface.viewers.CellEditor; +import dwtx.jface.viewers.ICellEditorListener; +import dwtx.jface.viewers.ICellModifier; +import dwtx.jface.viewers.ColumnViewer; +import dwtx.jface.viewers.IBaseLabelProvider; +import dwtx.jface.viewers.StructuredSelection; +import dwtx.jface.viewers.Viewer; +import dwtx.jface.viewers.DoubleClickEvent; +import dwtx.jface.viewers.OpenEvent; +import dwtx.jface.viewers.ITableLabelProvider; +import dwtx.jface.viewers.ViewerLabel; + +import tango.util.collection.model.SeqView; + +import dwt.DWT; +import dwt.custom.TableTree; +import dwt.custom.TableTreeEditor; +import dwt.custom.TableTreeItem; +import dwt.events.FocusAdapter; +import dwt.events.FocusEvent; +import dwt.events.FocusListener; +import dwt.events.MouseAdapter; +import dwt.events.MouseEvent; +import dwt.events.MouseListener; +import dwt.events.TreeListener; +import dwt.graphics.Image; +import dwt.graphics.Point; +import dwt.graphics.Rectangle; +import dwt.widgets.Composite; +import dwt.widgets.Control; +import dwt.widgets.Display; +import dwt.widgets.Item; +import dwt.widgets.Widget; + +import dwt.dwthelper.utils; + +/** + * A concrete viewer based on a DWT <code>TableTree</code> control. + * <p> + * This class is not intended to be subclassed outside the viewer framework. It + * is designed to be instantiated with a pre-existing DWT table tree control and + * configured with a domain-specific content provider, label provider, element + * filter (optional), and element sorter (optional). + * </p> + * <p> + * Content providers for table tree viewers must implement the + * <code>ITreeContentProvider</code> interface. + * </p> + * <p> + * Label providers for table tree viewers must implement either the + * <code>ITableLabelProvider</code> or the <code>ILabelProvider</code> + * interface (see <code>TableTreeViewer.setLabelProvider</code> for more + * details). + * </p> + * + * @deprecated As of 3.1 use {@link TreeViewer} instead + */ +public class TableTreeViewer : AbstractTreeViewer { + alias AbstractTreeViewer.setSelection setSelection; + /** + * Internal table viewer implementation. + */ + private TableTreeEditorImpl tableEditorImpl; + + /** + * This viewer's table tree control. + */ + private TableTree tableTree; + + /** + * This viewer's table tree editor. + */ + private TableTreeEditor tableTreeEditor; + + /** + * Copied from original TableEditorImpl and moved here since refactoring + * completely wiped out the original implementation in 3.3 + * + * @since 3.1 + */ + class TableTreeEditorImpl { + + private CellEditor cellEditor; + + private CellEditor[] cellEditors; + + private ICellModifier cellModifier; + + private String[] columnProperties; + + private Item tableItem; + + private int columnNumber; + + private ICellEditorListener cellEditorListener; + + private FocusListener focusListener; + + private MouseListener mouseListener; + + private int doubleClickExpirationTime; + + private ColumnViewer viewer; + + private this(ColumnViewer viewer) { + this.viewer = viewer; + initCellEditorListener(); + } + + /** + * Returns this <code>TableViewerImpl</code> viewer + * + * @return the viewer + */ + public ColumnViewer getViewer() { + return viewer; + } + + private void activateCellEditor() { + if( cellEditors !is null ) { + if( cellEditors[columnNumber] !is null && cellModifier !is null ) { + Object element = tableItem.getData(); + String property = columnProperties[columnNumber]; + + if( cellModifier.canModify(element, property) ) { + cellEditor = cellEditors[columnNumber]; + + 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 is null) { + return; + } + setLayoutData(cellEditor.getLayoutData()); + setEditor(control, tableItem, columnNumber); + cellEditor.setFocus(); + if (focusListener is null) { + focusListener = new class FocusAdapter { + public void focusLost(FocusEvent e) { + applyEditorValue(); + } + }; + } + control.addFocusListener(focusListener); + mouseListener = new class MouseAdapter { + Control control_; + this(){ + control_=control; + } + public void mouseDown(MouseEvent e) { + // time wrap? + // check for expiration of doubleClickTime + if (e.time <= doubleClickExpirationTime) { + control_.removeMouseListener(mouseListener); + cancelEditing(); + handleDoubleClickEvent(); + } else if (mouseListener !is null) { + control_.removeMouseListener(mouseListener); + } + } + }; + control.addMouseListener(mouseListener); + } + } + } + } + + /** + * Activate a cell editor for the given mouse position. + */ + private void activateCellEditor(MouseEvent event) { + if (tableItem is null || tableItem.isDisposed()) { + // item no longer exists + return; + } + int columnToEdit; + int columns = getColumnCount(); + if (columns is 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 is -1) { + return; + } + } + + columnNumber = columnToEdit; + activateCellEditor(); + } + + /** + * Deactivates the currently active cell editor. + */ + public void applyEditorValue() { + CellEditor c = this.cellEditor; + if (c !is 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 !is null && !t.isDisposed()) { + saveEditorValue(c, t); + } + setEditor(null, null, 0); + c.removeListener(cellEditorListener); + Control control = c.getControl(); + if (control !is null) { + if (mouseListener !is null) { + control.removeMouseListener(mouseListener); + } + if (focusListener !is 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 !is null) { + setEditor(null, null, 0); + cellEditor.removeListener(cellEditorListener); + CellEditor oldEditor = cellEditor; + cellEditor = null; + oldEditor.deactivate(); + } + } + + /** + * Start editing the given element. + * + * @param element + * @param column + */ + public void editElement(Object element, int column) { + if (cellEditor !is null) { + applyEditorValue(); + } + + setSelection(new StructuredSelection(element), true); + Item[] selection = getSelection(); + if (selection.length !is 1) { + return; + } + + tableItem = selection[0]; + + // Make sure selection is visible + showSelection(); + columnNumber = column; + activateCellEditor(); + + } + + /** + * Return the array of CellEditors used in the viewer + * + * @return the cell editors + */ + public CellEditor[] getCellEditors() { + return cellEditors; + } + + /** + * Get the cell modifier + * + * @return the cell modifier + */ + public ICellModifier getCellModifier() { + return cellModifier; + } + + /** + * Return the properties for the column + * + * @return the array of column properties + */ + public Object[] getColumnProperties() { + Object[] res; + foreach( str; columnProperties ){ + res ~= new ArrayWrapperString( str ); + } + return res; + } + + /** + * Handles the mouse down event; activates the cell editor. + * + * @param event + * the mouse event that should be handled + */ + public void handleMouseDown(MouseEvent event) { + if (event.button !is 1) { + return; + } + + if (cellEditor !is 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 !is 1) { + tableItem = null; + return; + } + tableItem = items[0]; + + activateCellEditor(event); + } + + private void initCellEditorListener() { + cellEditorListener = new class ICellEditorListener { + public void editorValueChanged(bool oldValidState, + bool newValidState) { + // Ignore. + } + + public void cancelEditor() { + this.outer.cancelEditing(); + } + + public void applyEditorValue() { + this.outer.applyEditorValue(); + } + }; + } + + /** + * Return whether there is an active cell editor. + * + * @return <code>true</code> if there is an active cell editor; + * otherwise <code>false</code> is returned. + */ + public bool isCellEditorActive() { + return cellEditor !is 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 !is null ) { + if( ! cellEditor.isValueValid() ) { + // Do what???? + } + } + String property = null; + + if( columnProperties !is null && columnNumber < columnProperties.length ) { + property = columnProperties[columnNumber]; + } + cellModifier.modify(tableItem, property, cellEditor.getValue()); + } + + /** + * Set the cell editors + * + * @param editors + */ + public void setCellEditors(CellEditor[] editors) { + this.cellEditors = editors; + } + + /** + * Set the cell modifier + * + * @param modifier + */ + public void setCellModifier(ICellModifier modifier) { + this.cellModifier = modifier; + } + + /** + * Set the column properties + * + * @param columnProperties + */ + public void setColumnProperties(String[] columnProperties) { + this.columnProperties = columnProperties; + } + + Rectangle getBounds(Item item, int columnNumber) { + return (cast(TableTreeItem) item).getBounds(columnNumber); + } + + int getColumnCount() { + // getColumnCount() should be a API in TableTree. + return getTableTree().getTable().getColumnCount(); + } + + Item[] getSelection() { + return getTableTree().getSelection(); + } + + void setEditor(Control w, Item item, int columnNumber) { + tableTreeEditor.setEditor(w, cast(TableTreeItem) item, columnNumber); + } + + void setSelection(StructuredSelection selection, bool b) { + this.outer.setSelection(selection, b); + } + + void showSelection() { + getTableTree().showSelection(); + } + + void setLayoutData(CellEditor.LayoutData layoutData) { + tableTreeEditor.horizontalAlignment = layoutData.horizontalAlignment; + tableTreeEditor.grabHorizontal = layoutData.grabHorizontal; + tableTreeEditor.minimumWidth = layoutData.minimumWidth; + } + + void handleDoubleClickEvent() { + Viewer viewer = getViewer(); + fireDoubleClick(new DoubleClickEvent(viewer, viewer.getSelection())); + fireOpen(new OpenEvent(viewer, viewer.getSelection())); + } + } + + /** + * Creates a table tree viewer on the given table tree control. The viewer + * has no input, no content provider, a default label provider, no sorter, + * and no filters. + * + * @param tree + * the table tree control + */ + public this(TableTree tree) { + super(); + tableTree = tree; + hookControl(tree); + tableTreeEditor = new TableTreeEditor(tableTree); + tableEditorImpl = new TableTreeEditorImpl(this); + } + + /** + * Creates a table tree viewer on a newly-created table tree control under + * the given parent. The table tree control is created using the DWT style + * bits <code>MULTI, H_SCROLL, V_SCROLL, and BORDER</code>. The viewer + * has no input, no content provider, a default label provider, no sorter, + * and no filters. + * + * @param parent + * the parent control + */ + public this(Composite parent) { + this(parent, DWT.MULTI | DWT.H_SCROLL | DWT.V_SCROLL | DWT.BORDER); + } + + /** + * Creates a table tree viewer on a newly-created table tree control under + * the given parent. The table tree control is created using the given DWT + * style bits. The viewer has no input, no content provider, a default label + * provider, no sorter, and no filters. + * + * @param parent + * the parent control + * @param style + * the DWT style bits + */ + public this(Composite parent, int style) { + this(new TableTree(parent, style)); + } + + /* + * (non-Javadoc) Method declared on AbstractTreeViewer. + */ + protected void addTreeListener(Control c, TreeListener listener) { + (cast(TableTree) c).addTreeListener(listener); + } + + /** + * Cancels a currently active cell editor. All changes already done in the + * cell editor are lost. + */ + public void cancelEditing() { + tableEditorImpl.cancelEditing(); + } + + /* + * (non-Javadoc) Method declared on AbstractTreeViewer. + */ + protected void doUpdateItem(Item item, Object element) { + // update icon and label + // Similar code in TableTreeViewer.doUpdateItem() + IBaseLabelProvider prov = getLabelProvider(); + ITableLabelProvider tprov = null; + + if ( auto t = cast(ITableLabelProvider) prov ) { + tprov = t; + } + + int columnCount = tableTree.getTable().getColumnCount(); + TableTreeItem ti = cast(TableTreeItem) 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 is 0; column++) { + String text = "";//$NON-NLS-1$ + Image image = null; + if (tprov !is null) { + text = tprov.getColumnText(element, column); + image = tprov.getColumnImage(element, column); + } else { + if (column is 0) { + ViewerLabel updateLabel = new ViewerLabel(item.getText(), + item.getImage()); + buildLabel(updateLabel, element); + + // As it is possible for user code to run the event + // loop check here. + if (item.isDisposed()) { + unmapElement(element, item); + return; + } + + text = updateLabel.getText(); + image = updateLabel.getImage(); + } + } + + // Avoid setting text to null + if (text is null) { + text = ""; //$NON-NLS-1$ + } + + ti.setText(column, text); + // Apparently a problem to setImage to null if already null + if (ti.getImage(column) !is image) { + ti.setImage(column, image); + } + + getColorAndFontCollector().setFontsAndColors(element); + getColorAndFontCollector().applyFontsAndColors(ti); + } + + } + + /** + * Starts editing the given element. + * + * @param element + * the element + * @param column + * the column number + */ + public void editElement(Object element, int column) { + tableEditorImpl.editElement(element, column); + } + + /** + * Returns the cell editors of this viewer. + * + * @return the list of cell editors + */ + public CellEditor[] getCellEditors() { + return tableEditorImpl.getCellEditors(); + } + + /** + * Returns the cell modifier of this viewer. + * + * @return the cell modifier + */ + public ICellModifier getCellModifier() { + return tableEditorImpl.getCellModifier(); + } + + /* + * (non-Javadoc) Method declared on AbstractTreeViewer. + */ + protected Item[] getChildren(Widget o) { + if (auto i = cast(TableTreeItem) o ) { + return i.getItems(); + } + if (auto i = cast(TableTree) o ) { + return i.getItems(); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.AbstractTreeViewer#getChild(dwt.widgets.Widget, + * int) + */ + protected Item getChild(Widget widget, int index) { + if (auto w = cast(TableTreeItem) widget ) { + return w.getItem(index); + } + if (auto w = cast(TableTree) widget ) { + return w.getItem(index); + } + return null; + } + + /** + * Returns the column properties of this 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 tableEditorImpl.getColumnProperties(); + } + + /* + * (non-Javadoc) Method declared on Viewer. + */ + public Control getControl() { + return tableTree; + } + + /** + * Returns the element with the given index from this 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) { + // XXX: Workaround for 1GBCSB1: DWT:WIN2000 - TableTree should have + // getItem(int index) + TableTreeItem i = tableTree.getItems()[index]; + if (i !is null) { + return i.getData(); + } + return null; + } + + /* + * (non-Javadoc) Method declared on AbstractTreeViewer. + */ + protected bool getExpanded(Item item) { + return (cast(TableTreeItem) item).getExpanded(); + } + + /* + * (non-Javadoc) + * + * @see dwtx.jface.viewers.ColumnViewer#getItemAt(dwt.graphics.Point) + */ + protected Item getItemAt(Point p) { + return getTableTree().getTable().getItem(p); + } + + /* + * (non-Javadoc) Method declared on AbstractTreeViewer. + */ + protected int getItemCount(Control widget) { + return (cast(TableTree) widget).getItemCount(); + } + + /* + * (non-Javadoc) Method declared on AbstractTreeViewer. + */ + protected int getItemCount(Item item) { + return (cast(TableTreeItem) item).getItemCount(); + } + + /* + * (non-Javadoc) Method declared on AbstractTreeViewer. + */ + protected dwt.widgets.Item.Item[] getItems( + dwt.widgets.Item.Item item) { + return (cast(TableTreeItem) item).getItems(); + } + + /** + * The table tree viewer implementation of this <code>Viewer</code> + * framework method returns the label provider, which in the case of table + * tree 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 AbstractTreeViewer. + */ + protected Item getParentItem(Item item) { + return (cast(TableTreeItem) item).getParentItem(); + } + + /* + * (non-Javadoc) Method declared on AbstractTreeViewer. + */ + protected Item[] getSelection(Control widget) { + return (cast(TableTree) widget).getSelection(); + } + + /** + * Returns this table tree viewer's table tree control. + * + * @return the table tree control + */ + public TableTree getTableTree() { + return tableTree; + } + + /* + * (non-Javadoc) Method declared on AbstractTreeViewer. + */ + protected void hookControl(Control control) { + super.hookControl(control); + tableTree.getTable().addMouseListener(new class MouseAdapter { + public void mouseDown(MouseEvent e) { + /* + * If user clicked on the [+] or [-], do not activate + * CellEditor. + */ + // XXX: This code should not be here. DWT should either have + // support to see + // if the user clicked on the [+]/[-] or manage the table editor + // activation + dwt.widgets.TableItem.TableItem[] items = tableTree + .getTable().getItems(); + for (int i = 0; i < items.length; i++) { + Rectangle rect = items[i].getImageBounds(0); + if (rect.contains(e.x, e.y)) { + return; + } + } + + tableEditorImpl.handleMouseDown(e); + } + }); + } + + /** + * 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 bool isCellEditorActive() { + return tableEditorImpl.isCellEditorActive(); + } + + /* + * (non-Javadoc) Method declared in AbstractTreeViewer. + */ + protected Item newItem(Widget parent, int flags, int ix) { + TableTreeItem item; + if (ix >= 0) { + if (cast(TableTreeItem) parent ) { + item = new TableTreeItem(cast(TableTreeItem) parent, flags, ix); + } else { + item = new TableTreeItem(cast(TableTree) parent, flags, ix); + } + } else { + if (cast(TableTreeItem)parent ) { + item = new TableTreeItem(cast(TableTreeItem) parent, flags); + } else { + item = new TableTreeItem(cast(TableTree) parent, flags); + } + } + return item; + } + + /* + * (non-Javadoc) Method declared in AbstractTreeViewer. + */ + protected void removeAll(Control widget) { + (cast(TableTree) widget).removeAll(); + } + + /** + * Sets the cell editors of this table viewer. + * + * @param editors + * the list of cell editors + */ + public void setCellEditors(CellEditor[] editors) { + tableEditorImpl.setCellEditors(editors); + } + + /** + * Sets the cell modifier of this table viewer. + * + * @param modifier + * the cell modifier + */ + public void setCellModifier(ICellModifier modifier) { + tableEditorImpl.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) { + tableEditorImpl.setColumnProperties(columnProperties); + } + + /* + * (non-Javadoc) Method declared in AbstractTreeViewer. + */ + protected void setExpanded(Item node, bool expand) { + (cast(TableTreeItem) node).setExpanded(expand); + } + + /* + * (non-Javadoc) Method declared in AbstractTreeViewer. + */ + protected void setSelection(SeqView!(Item) items) { + getTableTree().setSelection(cast(TableTreeItem[]) items.toArray); + } + + /* + * (non-Javadoc) Method declared in AbstractTreeViewer. + */ + protected void showItem(Item item) { + getTableTree().showItem(cast(TableTreeItem) item); + } +}