Mercurial > projects > dwt-addons
view dwtx/jface/viewers/TableTreeViewer.d @ 90:7ffeace6c47f
Update 3.4M7 to 3.4
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 06 Jul 2008 23:30:07 +0200 |
parents | 07b9d96fd764 |
children | 04b47443bb01 |
line wrap: on
line source
/******************************************************************************* * Copyright (c) 2000, 2008 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 * @noextend This class is not intended to be subclassed by clients. */ public class TableTreeViewer : AbstractTreeViewer { alias AbstractTreeViewer.addTreeListener addTreeListener; alias AbstractTreeViewer.doUpdateItem doUpdateItem; alias AbstractTreeViewer.getLabelProvider getLabelProvider; alias AbstractTreeViewer.getSelection getSelection; 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(control) MouseAdapter { Control control_; this(Control a){ control_=a; } 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(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 override 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 override void cancelEditing() { tableEditorImpl.cancelEditing(); } /* * (non-Javadoc) Method declared on AbstractTreeViewer. */ protected override 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 override void editElement(Object element, int column) { tableEditorImpl.editElement(element, column); } /** * Returns the cell editors of this viewer. * * @return the list of cell editors */ public override CellEditor[] getCellEditors() { return tableEditorImpl.getCellEditors(); } /** * Returns the cell modifier of this viewer. * * @return the cell modifier */ public override ICellModifier getCellModifier() { return tableEditorImpl.getCellModifier(); } /* * (non-Javadoc) Method declared on AbstractTreeViewer. */ protected override 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 override 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 override Object[] getColumnProperties() { return tableEditorImpl.getColumnProperties(); } /* * (non-Javadoc) Method declared on Viewer. */ public override 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 override bool getExpanded(Item item) { return (cast(TableTreeItem) item).getExpanded(); } /* * (non-Javadoc) * * @see dwtx.jface.viewers.ColumnViewer#getItemAt(dwt.graphics.Point) */ protected override Item getItemAt(Point p) { return getTableTree().getTable().getItem(p); } /* * (non-Javadoc) Method declared on AbstractTreeViewer. */ protected override int getItemCount(Control widget) { return (cast(TableTree) widget).getItemCount(); } /* * (non-Javadoc) Method declared on AbstractTreeViewer. */ protected override int getItemCount(Item item) { return (cast(TableTreeItem) item).getItemCount(); } /* * (non-Javadoc) Method declared on AbstractTreeViewer. */ protected override 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 override IBaseLabelProvider getLabelProvider() { return super.getLabelProvider(); } /* * (non-Javadoc) Method declared on AbstractTreeViewer. */ protected override Item getParentItem(Item item) { return (cast(TableTreeItem) item).getParentItem(); } /* * (non-Javadoc) Method declared on AbstractTreeViewer. */ protected override 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 override 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 override bool isCellEditorActive() { return tableEditorImpl.isCellEditorActive(); } /* * (non-Javadoc) Method declared in AbstractTreeViewer. */ protected override 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 override void removeAll(Control widget) { (cast(TableTree) widget).removeAll(); } /** * Sets the cell editors of this table viewer. * * @param editors * the list of cell editors */ public override void setCellEditors(CellEditor[] editors) { tableEditorImpl.setCellEditors(editors); } /** * Sets the cell modifier of this table viewer. * * @param modifier * the cell modifier */ public override 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 override void setColumnProperties(String[] columnProperties) { tableEditorImpl.setColumnProperties(columnProperties); } /* * (non-Javadoc) Method declared in AbstractTreeViewer. */ protected override void setExpanded(Item node, bool expand) { (cast(TableTreeItem) node).setExpanded(expand); } /* * (non-Javadoc) Method declared in AbstractTreeViewer. */ protected override void setSelection(SeqView!(Item) items) { getTableTree().setSelection(cast(TableTreeItem[]) items.toArray); } /* * (non-Javadoc) Method declared in AbstractTreeViewer. */ protected override void showItem(Item item) { getTableTree().showItem(cast(TableTreeItem) item); } }