org.eclipse.nebula.jface.gridviewer.GridTreeViewer.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.nebula.jface.gridviewer.GridTreeViewer.java

Source

/*******************************************************************************
 * Copyright (c) 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:
 *    Michael Houston <schmeeky@gmail.com> - initial API and implementation
 *    Tom Schindl <tom.schindl@bestsolution.at> - bug fix in: 191216
 *******************************************************************************/
package org.eclipse.nebula.jface.gridviewer;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.ColumnViewerEditor;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerRow;
import org.eclipse.nebula.widgets.grid.Grid;
import org.eclipse.nebula.widgets.grid.GridItem;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.TreeListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;

/**
 * A concrete viewer based on an Grid control.
 * <p>
 * This class is not intended to be subclassed outside the viewer framework. It
 * is designed to be instantiated with a pre-existing Grid control and
 * configured with a domain-specific content provider, label provider, element
 * filter (optional), and element sorter (optional).
 * <p>
 * Content providers for grid tree viewers must implement the
 * {@link ITreeContentProvider} interface.
 * <p><b>The current implementation does not support lazy content providers.</b></p>
 */
public class GridTreeViewer extends AbstractTreeViewer {

    /** This viewer's grid control. */
    private Grid grid;

    private GridViewerRow cachedRow;

    /**
     * If true, this grid viewer will ensure that the grid's
     * rows / GridItems are always sized to their preferred height.
     */
    private boolean autoPreferredHeight = false;

    private CellLabelProvider rowHeaderLabelProvider;

    /**
      * Creates a grid tree viewer on a newly-created grid control under the given
      * parent. The grid 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.
      * 
      * @param parent 
      *             the parent control
      */
    public GridTreeViewer(Composite parent) {
        this(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
    }

    /**
      * Creates a grid tree viewer on a newly-created grid control under the given
      * parent. The grid control is created using the given SWT 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 SWT style bits used to create the grid.
      */
    public GridTreeViewer(Composite parent, int style) {
        this(new Grid(parent, style));
    }

    /**
      * Creates a grid tree viewer on the given grid control. The viewer has no
      * input, no content provider, a default label provider, no sorter, and no
      * filters.
      * 
      * @param grid 
      *             the grid control
      */
    public GridTreeViewer(Grid grid) {
        this.grid = grid;
        hookControl(grid);
    }

    /**
      * Returns the underlying {@link Grid} Control. 
      * 
      * @return grid control.
      */
    public Grid getGrid() {
        return grid;
    }

    /** {@inheritDoc} */
    protected Item getItemAt(Point point) {
        return grid.getItem(point);
    }

    /** {@inheritDoc} */
    protected ColumnViewerEditor createViewerEditor() {
        return new GridViewerEditor(this, new ColumnViewerEditorActivationStrategy(this),
                ColumnViewerEditor.DEFAULT);
    }

    /** {@inheritDoc} */
    protected void addTreeListener(Control control, TreeListener listener) {
        ((Grid) control).addTreeListener(listener);
    }

    /** {@inheritDoc} */
    protected Item[] getChildren(Widget o) {
        if (o instanceof GridItem) {
            return ((GridItem) o).getItems();
        }
        if (o instanceof Grid) {
            return ((Grid) o).getRootItems();
        }
        return null;
    }

    /** {@inheritDoc} */
    protected boolean getExpanded(Item item) {
        return ((GridItem) item).isExpanded();
    }

    /** {@inheritDoc} */
    protected int getItemCount(Control control) {
        return ((Grid) control).getItemCount();
    }

    /** {@inheritDoc} */
    protected int getItemCount(Item item) {
        return ((GridItem) item).getItemCount();
    }

    /** {@inheritDoc} */
    protected Item[] getItems(Item item) {
        return ((GridItem) item).getItems();
    }

    /** {@inheritDoc} */
    protected Item getParentItem(Item item) {
        return ((GridItem) item).getParentItem();
    }

    /** {@inheritDoc} */
    protected Item[] getSelection(Control control) {
        return ((Grid) control).getSelection();
    }

    /** {@inheritDoc} */
    protected Item newItem(Widget parent, int style, int index) {
        GridItem item;

        if (parent instanceof GridItem) {
            item = (GridItem) createNewRowPart(getViewerRowFromItem(parent), style, index).getItem();
        } else {
            item = (GridItem) createNewRowPart(null, style, index).getItem();
        }

        return item;
    }

    /**
     * Create a new ViewerRow at rowIndex
     * 
     * @param parent 
     *             the parent row
     * @param style 
     *             the style bits to use for the new row
     * @param rowIndex 
     *             the index at which the new row should be created under the parent
     * @return ViewerRow 
     *             the new row
     */
    private ViewerRow createNewRowPart(ViewerRow parent, int style, int rowIndex) {
        if (parent == null) {
            if (rowIndex >= 0) {
                return getViewerRowFromItem(new GridItem(grid, style, rowIndex));
            }
            return getViewerRowFromItem(new GridItem(grid, style));
        }

        if (rowIndex >= 0) {
            return getViewerRowFromItem(new GridItem((GridItem) parent.getItem(), SWT.NONE, rowIndex));
        }

        return getViewerRowFromItem(new GridItem((GridItem) parent.getItem(), SWT.NONE));
    }

    /** {@inheritDoc} */
    protected void removeAll(Control control) {
        ((Grid) control).removeAll();
    }

    /** {@inheritDoc} */
    protected void setExpanded(Item item, boolean expand) {
        ((GridItem) item).setExpanded(expand);
    }

    /** {@inheritDoc} */
    protected void setSelection(List items) {
        Item[] current = getSelection(getGrid());

        // Don't bother resetting the same selection
        if (isSameSelection(items, current)) {
            return;
        }

        GridItem[] newItems = new GridItem[items.size()];
        items.toArray(newItems);
        getGrid().setSelection(newItems);
        getGrid().showSelection();
    }

    /** {@inheritDoc} */
    protected void showItem(Item item) {
        getGrid().showItem((GridItem) item);

    }

    /** {@inheritDoc} */
    public Control getControl() {
        return getGrid();
    }

    /** {@inheritDoc} */
    protected ViewerRow getViewerRowFromItem(Widget item) {
        if (cachedRow == null) {
            cachedRow = new GridViewerRow((GridItem) item);
        } else {
            cachedRow.setItem((GridItem) item);
        }

        return cachedRow;
    }

    /** {@inheritDoc} */
    protected Widget getColumnViewerOwner(int columnIndex) {
        if (columnIndex < 0 || (columnIndex > 0 && columnIndex >= getGrid().getColumnCount())) {
            return null;
        }

        if (getGrid().getColumnCount() == 0)// Hang it off the table if it
            return getGrid();

        return getGrid().getColumn(columnIndex);
    }

    /**
     * Returns the number of columns of this viewer.
     *
     * @return the number of columns
     */
    protected int doGetColumnCount() {
        return grid.getColumnCount();
    }

    /**
     * When set to true, this grid viewer will ensure that each of
     * the grid's items is always automatically sized to its preferred
     * height. The default is false.
     * <p>
     * Since this mechanism usually leads to a grid with rows of
     * different heights and thus to a grid with decreased performance,
     * it should only be applied if that is intended.  To set the
     * height of all items to a specific value, use {@link Grid#setItemHeight(int)}
     * instead.
     * <p>
     * When a column with activated word wrapping is resized
     * by dragging the column resizer, the items are only auto-resized
     * properly if you use {@link GridViewerColumn} to create the
     * columns.
     * <p>
     * When this method is called, existing rows are not resized to their 
     * preferred height.  Therefore it is suggested that this method be called
     * before rows are populated (i.e. before setInput).
     */
    public void setAutoPreferredHeight(boolean autoPreferredHeight) {
        this.autoPreferredHeight = autoPreferredHeight;
    }

    /**
     * @return  true if this grid viewer sizes its rows to their
     *          preferred height
     * @see #setAutoPreferredHeight(boolean)
     */
    public boolean getAutoPreferredHeight() {
        return autoPreferredHeight;
    }

    /** {@inheritDoc} */
    protected void doUpdateItem(final Item item, Object element) {
        super.doUpdateItem(item, element);
        updateRowHeader(item);
        if (autoPreferredHeight && !item.isDisposed())
            ((GridItem) item).pack();
    }

    /**
     * Removes the element at the specified index of the parent.  The selection is updated if required.
     *
     * @param parentOrTreePath the parent element, the input element, or a tree path to the parent element
     * @param index child index
     * @since 3.3
     */
    public void remove(final Object parentOrTreePath, final int index) {
        if (checkBusy())
            return;
        final List oldSelection = new LinkedList(Arrays.asList(((TreeSelection) getSelection()).getPaths()));
        preservingSelection(new Runnable() {
            public void run() {
                TreePath removedPath = null;
                if (internalIsInputOrEmptyPath(parentOrTreePath)) {
                    Tree tree = (Tree) getControl();
                    if (index < tree.getItemCount()) {
                        TreeItem item = tree.getItem(index);
                        if (item.getData() != null) {
                            removedPath = getTreePathFromItem(item);
                            disassociate(item);
                        }
                        item.dispose();
                    }
                } else {
                    Widget[] parentItems = internalFindItems(parentOrTreePath);
                    for (int i = 0; i < parentItems.length; i++) {
                        TreeItem parentItem = (TreeItem) parentItems[i];
                        if (parentItem.isDisposed())
                            continue;
                        if (index < parentItem.getItemCount()) {
                            TreeItem item = parentItem.getItem(index);
                            if (item.getData() != null) {
                                removedPath = getTreePathFromItem(item);
                                disassociate(item);
                            }
                            item.dispose();
                        }
                    }
                }
                if (removedPath != null) {
                    boolean removed = false;
                    for (Iterator it = oldSelection.iterator(); it.hasNext();) {
                        TreePath path = (TreePath) it.next();
                        if (path.startsWith(removedPath, getComparer())) {
                            it.remove();
                            removed = true;
                        }
                    }
                    if (removed) {
                        setSelection(new TreeSelection(
                                (TreePath[]) oldSelection.toArray(new TreePath[oldSelection.size()]),
                                getComparer()), false);
                    }

                }
            }
        });
    }

    /**
     * Label provider used by calculate the row header text
     * 
     * @param rowHeaderLabelProvider
     *            the provider
     */
    public void setRowHeaderLabelProvider(CellLabelProvider rowHeaderLabelProvider) {
        this.rowHeaderLabelProvider = rowHeaderLabelProvider;
    }

    private void updateRowHeader(Widget widget) {
        if (rowHeaderLabelProvider != null) {
            ViewerCell cell = getViewerRowFromItem(widget).getCell(Integer.MAX_VALUE);
            rowHeaderLabelProvider.update(cell);
        }
    }
}