org.hibernate.eclipse.console.viewers.xpl.MTreeViewer.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.eclipse.console.viewers.xpl.MTreeViewer.java

Source

/*******************************************************************************
 * Copyright (c) 2007 Red Hat, Inc.
 * Distributed under license by Red Hat, Inc. All rights reserved.
 * This program is 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
 *
 * Contributor:
 *     Red Hat, Inc. - initial API and implementation
 ******************************************************************************/
package org.hibernate.eclipse.console.viewers.xpl;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;

/**
 * TreeViewer has the next lack design to work with the objects as TreeItem id:
 * internalFindItems always return array of size <= 1
 * cause doFindItems & internalFindItem returns FIRST proper item which it find
 * but in common case this is not the TRUTH - so TreeViewer add method doesn't work
 * as we expected.
 * 
 * So MTreeViewer fix the problem.
 * It redefine add method taking into account what for one parentElementOrTreePath as id
 * could exist several ( >= 0 ) widgets.
 * doFindItems & internalFindItem returns ALL proper items which it find.
 * 
 * We expect what TreeViewer developers fix the bug in future versions,
 * but we can't wait it.
 * 
 * more info is here http://jira.jboss.com/jira/browse/JBIDE-1482
 * 
 * @author Vitali
 */
public class MTreeViewer extends TreeViewer {

    public MTreeViewer(Composite parent, int style) {
        super(parent, style);
    }

    public void clearChildren(Object node) {
        Widget widget = null;
        if (node instanceof Widget) {
            widget = (Widget) node;
        } else if (node == null) {
            widget = getTree();
        }
        Widget[] items = null;
        if (widget == null && node != null) {
            items = internalFindItems(node);
        } else {
            items = getChildren(widget);
        }
        for (int j = 0; j < items.length; j++) {
            clearChildren(items[j]);
            if (items[j] instanceof TreeItem) {
                ((TreeItem) items[j]).setExpanded(false);
                ((TreeItem) items[j]).clearAll(true);
            }
        }
    }

    /**
     * Adds the given child elements to this viewer as children of the given
     * parent element. If this viewer does not have a sorter, the elements are
     * added at the end of the parent's list of children in the order given;
     * otherwise, the elements are inserted at the 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 parentElementOrTreePath
     *            the parent element
     * @param childElements
     *            the child elements to add
     */
    public void add(Object parentElementOrTreePath, Object[] childElements) {
        Assert.isNotNull(parentElementOrTreePath);
        assertElementsNotNull(childElements);
        if (isBusy())
            return;
        Widget[] widgets = internalFindItems2(parentElementOrTreePath);
        // If parent hasn't been realized yet, just ignore the add.
        if (widgets.length == 0) {
            return;
        }

        for (int i = 0; i < widgets.length; i++) {
            internalAdd(widgets[i], parentElementOrTreePath, childElements);
            // call this to refresh icon of parent item
            updateItem(widgets[i], parentElementOrTreePath);
        }
    }

    /**
     * Find the items for the given element of tree path
     * 
     * @param parentElementOrTreePath
     *            the element or tree path
     * @return the items for that element
     */
    protected Widget[] internalFindItems2(Object parentElementOrTreePath) {
        Widget[] widgets;
        if (parentElementOrTreePath instanceof TreePath) {
            widgets = internalFindItems(parentElementOrTreePath);
        } else {
            widgets = findItems2(parentElementOrTreePath);
        }
        return widgets;
    }

    /**
     * Finds the widgets which represent the given element. The returned array
     * must not be changed by clients; it might change upon calling other
     * methods on this viewer.
     * <p>
     * This method was introduced to support multiple equal elements in a viewer
     * (@see {@link AbstractTreeViewer}). Multiple equal elements are only
     * supported if the element map is enabled by calling
     * {@link #setUseHashlookup(boolean)} and passing <code>true</code>.
     * </p>
     * <p>
     * The default implementation of this method tries first to find the widget
     * for the given element assuming that it is the viewer's input; this is
     * done by calling <code>doFindInputItem</code>. If it is not found
     * there, the widgets are looked up in the internal element map provided
     * that this feature has been enabled. If the element map is disabled, the
     * widget is found via <code>doFindInputItem</code>.
     * </p>
     * 
     * @param element
     *            the element
     * @return the corresponding widgets
     */
    protected Widget[] findItems2(Object element) {
        Widget result = doFindInputItem(element);
        if (result != null) {
            return new Widget[] { result };
        }
        // if we have an element map use it, otherwise search for the item.
        if (usingElementMap()) {
            return findItems2(element);
        }
        return doFindItems(element);
    }

    /**
     * Recursively tries to find the given element.
     * 
     * @param parent
     *            the parent item
     * @param element
     *            the element
     * @return Widget
     */
    protected List<Item> internalFindItem(Item parent, Object element) {

        List<Item> ret = new ArrayList<Item>();
        // compare with node
        Object data = parent.getData();
        if (data != null) {
            if (equals(data, element)) {
                ret.add(parent);
                return ret;
            }
        }
        // recurse over children
        Item[] items = getChildren(parent);
        for (int i = 0; i < items.length; i++) {
            Item item = items[i];
            List<Item> o = internalFindItem(item, element);
            if (null != o) {
                ret.addAll(o);
            }
        }
        return ret;
    }

    protected Widget[] doFindItems(Object element) {
        Widget[] ret = new Widget[0];
        // compare with root
        Object root = getRoot();
        if (null == root) {
            return ret;
        }
        List<Widget> res = new ArrayList<Widget>();
        Item[] items = getChildren(getControl());
        if (items != null) {
            for (int i = 0; i < items.length; i++) {
                List<Item> o = internalFindItem(items[i], element);
                if (null != o) {
                    res.addAll(o);
                }
            }
        }
        ret = res.toArray(new Widget[0]);
        return ret;
    }

}