org.eclipse.wb.internal.rcp.databinding.ui.contentproviders.TreeContentLabelProvidersUiContentProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.wb.internal.rcp.databinding.ui.contentproviders.TreeContentLabelProvidersUiContentProvider.java

Source

/*******************************************************************************
 * Copyright (c) 2011 Google, Inc.
 * 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:
 *    Google, Inc. - initial API and implementation
 *******************************************************************************/
package org.eclipse.wb.internal.rcp.databinding.ui.contentproviders;

import com.google.common.collect.Lists;

import org.eclipse.wb.internal.core.databinding.ui.editor.ICompleteListener;
import org.eclipse.wb.internal.core.databinding.ui.editor.IUiContentProvider;
import org.eclipse.wb.internal.core.utils.ui.GridDataFactory;
import org.eclipse.wb.internal.rcp.databinding.Messages;
import org.eclipse.wb.internal.rcp.databinding.model.GlobalFactoryHelper;
import org.eclipse.wb.internal.rcp.databinding.model.beans.bindables.BeanSupport;
import org.eclipse.wb.internal.rcp.databinding.model.widgets.input.ObservableCollectionTreeContentProviderInfo;
import org.eclipse.wb.internal.rcp.databinding.model.widgets.input.TreeViewerInputBindingInfo;
import org.eclipse.wb.internal.rcp.databinding.model.widgets.input.designer.BeansObservableFactoryInfo;
import org.eclipse.wb.internal.rcp.databinding.model.widgets.input.designer.TreeBeanAdvisorInfo;
import org.eclipse.wb.internal.rcp.databinding.model.widgets.input.designer.TreeObservableLabelProviderInfo;
import org.eclipse.wb.internal.rcp.databinding.ui.providers.TypeImageProvider;

import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

import org.apache.commons.lang.ArrayUtils;

import java.beans.PropertyDescriptor;
import java.util.Collection;
import java.util.List;

/**
 * Content provider for choose properties (over checked tree): parent/children/has
 * children/text/image for content and label providers for tree viewer in Designer mode.
 * 
 * @author lobas_av
 * @coverage bindings.rcp.ui
 */
public final class TreeContentLabelProvidersUiContentProvider implements IUiContentProvider {
    private static final String PARENT_GROUP_NAME = Messages.TreeContentLabelProvidersUiContentProvider_parentGroup;
    private static final String CHILDREN_GROUP_NAME = Messages.TreeContentLabelProvidersUiContentProvider_childrenGroup;
    private static final String HAS_CHILDREN_GROUP_NAME = Messages.TreeContentLabelProvidersUiContentProvider_hasChildrenGroup;
    private static final String TEXT_GROUP_NAME = Messages.TreeContentLabelProvidersUiContentProvider_textGroup;
    private static final String IMAGE_GROUP_NAME = Messages.TreeContentLabelProvidersUiContentProvider_imageGroup;
    //
    private final TreeViewerInputBindingInfo m_binding;
    private CheckboxTreeViewer m_propertiesViewer;
    private ICompleteListener m_listener;
    private String m_errorMessage;

    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor
    //
    ////////////////////////////////////////////////////////////////////////////
    public TreeContentLabelProvidersUiContentProvider(TreeViewerInputBindingInfo binding) {
        m_binding = binding;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Complete
    //
    ////////////////////////////////////////////////////////////////////////////
    public void setCompleteListener(ICompleteListener listener) {
        m_listener = listener;
    }

    public String getErrorMessage() {
        return m_errorMessage;
    }

    private void setErrorMessage(String message) {
        m_errorMessage = message;
        m_listener.calculateFinish();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // GUI
    //
    ////////////////////////////////////////////////////////////////////////////
    public int getNumberOfControls() {
        return 2;
    }

    public void createContent(Composite parent, int columns) {
        // properties title
        Label title = new Label(parent, SWT.NONE);
        title.setText(Messages.TreeContentLabelProvidersUiContentProvider_propertiesLabel);
        // properties viewer
        m_propertiesViewer = new CheckboxTreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
        GridDataFactory.create(m_propertiesViewer.getControl()).fill().grab().spanH(columns - 1);
        m_propertiesViewer.setContentProvider(new TreePropertiesContentProvider());
        m_propertiesViewer.setLabelProvider(new TreePropertiesLabelProvider());
        m_propertiesViewer.addCheckStateListener(new PropertiesCheckStateListener());
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Handle
    //
    ////////////////////////////////////////////////////////////////////////////
    private void calculateFinish() {
        if (!checkChoosenElement(CHILDREN_GROUP_NAME)) {
            setErrorMessage(Messages.TreeContentLabelProvidersUiContentProvider_errorMessage1);
        } else if (!checkChoosenElement(TEXT_GROUP_NAME)) {
            setErrorMessage(Messages.TreeContentLabelProvidersUiContentProvider_errorMessage2);
        } else {
            setErrorMessage(null);
        }
    }

    /**
     * @return <code>true</code> if given group <code>name</name> is checked.
     */
    private boolean checkChoosenElement(String name) {
        for (Object element : m_propertiesViewer.getCheckedElements()) {
            if (element instanceof PropertiesGroup) {
                PropertiesGroup group = (PropertiesGroup) element;
                if (name.equals(group.name)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Sets {@link Class} for choose properties.
     */
    public void setElementType(Class<?> elementType) throws Exception {
        try {
            // prepare properties
            List<PropertyDescriptor> descriptors = BeanSupport.getPropertyDescriptors(elementType);
            //
            GlobalFactoryHelper.filterElementPropertiesForViewerInput(m_binding.getInputObservable(), elementType,
                    descriptors);
            // prepare groups
            List<PropertiesGroup> groups = Lists.newArrayList();
            groups.add(new PropertiesGroup(PARENT_GROUP_NAME, filterProperties(descriptors, Object.class)));
            groups.add(new PropertiesGroup(CHILDREN_GROUP_NAME, filterCollectionProperties(descriptors)));
            groups.add(new PropertiesGroup(HAS_CHILDREN_GROUP_NAME, filterBooleanProperties(descriptors)));
            groups.add(new PropertiesGroup(TEXT_GROUP_NAME, filterProperties(descriptors, String.class)));
            groups.add(new PropertiesGroup(IMAGE_GROUP_NAME, filterProperties(descriptors, Image.class)));
            // fill viewer
            m_propertiesViewer.setInput(groups);
            m_propertiesViewer.setCheckedElements(ArrayUtils.EMPTY_OBJECT_ARRAY);
            m_propertiesViewer.expandAll();
        } finally {
            calculateFinish();
        }
    }

    /**
     * Helper method that filter given <code>properties</code> include only {@link Class}
     * <code>testType</code> properties.
     */
    private static List<PropertyDescriptor> filterProperties(List<PropertyDescriptor> properties,
            Class<?> testType) {
        List<PropertyDescriptor> newProperties = Lists.newArrayList();
        for (PropertyDescriptor property : properties) {
            Class<?> type = property.getPropertyType();
            if (type != null && (testType == type || testType.isAssignableFrom(type))) {
                newProperties.add(property);
            }
        }
        return newProperties;
    }

    /**
     * Helper method that filter given <code>properties</code> include only boolean properties.
     */
    private static List<PropertyDescriptor> filterBooleanProperties(List<PropertyDescriptor> properties) {
        List<PropertyDescriptor> newProperties = Lists.newArrayList();
        for (PropertyDescriptor property : properties) {
            Class<?> type = property.getPropertyType();
            if (type == boolean.class || type == Boolean.class) {
                newProperties.add(property);
            }
        }
        return newProperties;
    }

    /**
     * Helper method that filter given <code>properties</code> include only {@link Collection} and
     * array properties.
     */
    private static List<PropertyDescriptor> filterCollectionProperties(List<PropertyDescriptor> properties) {
        List<PropertyDescriptor> newProperties = Lists.newArrayList();
        for (PropertyDescriptor property : properties) {
            Class<?> type = property.getPropertyType();
            if (type != null && (type.isArray() || Collection.class.isAssignableFrom(type))) {
                newProperties.add(property);
            }
        }
        return newProperties;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Update
    //
    ////////////////////////////////////////////////////////////////////////////
    public void updateFromObject() throws Exception {
        if (m_binding.isDesignerMode()) {
            Class<?> elementType = m_binding.getElementType();
            if (elementType != null) {
                // set element type
                setElementType(elementType);
                // prepare checked groups
                List<Object> checkedObjects = Lists.newArrayList();
                // check parent/children/has children
                TreeBeanAdvisorInfo advisor = (TreeBeanAdvisorInfo) m_binding.getContentProvider().getAdvisorInfo();
                extractProperties(checkedObjects, PARENT_GROUP_NAME, advisor.getParentProperty());
                extractProperties(checkedObjects, CHILDREN_GROUP_NAME, advisor.getChildrenProperty());
                extractProperties(checkedObjects, HAS_CHILDREN_GROUP_NAME, advisor.getHasChildrenProperty());
                // check text/image
                TreeObservableLabelProviderInfo labelProvider = (TreeObservableLabelProviderInfo) m_binding
                        .getLabelProvider();
                extractProperties(checkedObjects, TEXT_GROUP_NAME, labelProvider.getTextProperty());
                extractProperties(checkedObjects, IMAGE_GROUP_NAME, labelProvider.getImageProperty());
                // apply checked
                if (!checkedObjects.isEmpty()) {
                    m_propertiesViewer.setCheckedElements(checkedObjects.toArray());
                }
            }
        }
        //
        calculateFinish();
    }

    /**
     * Find and fill <code>objects</code>, properties viewer elements ({@link PropertiesGroup} and
     * {@link TreePropertyWrapper}) that association with given <code>property</code>.
     */
    @SuppressWarnings("unchecked")
    private void extractProperties(List<Object> objects, String groupName, String property) {
        if (property != null) {
            List<PropertiesGroup> input = (List<PropertiesGroup>) m_propertiesViewer.getInput();
            for (PropertiesGroup group : input) {
                if (groupName.equals(group.name)) {
                    for (TreePropertyWrapper wrapper : group.properties) {
                        if (property.equals(wrapper.descriptor.getName())) {
                            objects.add(group);
                            objects.add(wrapper);
                            return;
                        }
                    }
                    return;
                }
            }
        }
    }

    public void saveToObject() throws Exception {
        // prepare content provider
        ObservableCollectionTreeContentProviderInfo contentProvider = m_binding.getContentProvider();
        // prepare factory
        BeansObservableFactoryInfo factory = (BeansObservableFactoryInfo) contentProvider.getFactoryInfo();
        // prepare advisor
        TreeBeanAdvisorInfo advisor = (TreeBeanAdvisorInfo) contentProvider.getAdvisorInfo();
        // prepare label provider
        TreeObservableLabelProviderInfo labelProvider = (TreeObservableLabelProviderInfo) m_binding
                .getLabelProvider();
        // extract checked properties
        for (Object element : m_propertiesViewer.getCheckedElements()) {
            if (element instanceof TreePropertyWrapper) {
                TreePropertyWrapper wrapper = (TreePropertyWrapper) element;
                String propertyName = wrapper.descriptor.getName();
                String groupName = wrapper.parent.name;
                // check group
                if (PARENT_GROUP_NAME.equals(groupName)) {
                    advisor.setParentProperty(propertyName);
                } else if (CHILDREN_GROUP_NAME.equals(groupName)) {
                    advisor.setChildrenProperty(propertyName);
                    factory.setPropertyName(propertyName);
                } else if (HAS_CHILDREN_GROUP_NAME.equals(groupName)) {
                    advisor.setHasChildrenProperty(propertyName);
                } else if (TEXT_GROUP_NAME.equals(groupName)) {
                    labelProvider.setTextProperty(propertyName);
                } else if (IMAGE_GROUP_NAME.equals(groupName)) {
                    labelProvider.setImageProperty(propertyName);
                }
            }
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Inner model
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Group.
     */
    private static class PropertiesGroup {
        public String name;
        public TreePropertyWrapper[] properties;

        ////////////////////////////////////////////////////////////////////////////
        //
        // Constructor
        //
        ////////////////////////////////////////////////////////////////////////////
        public PropertiesGroup(String name, List<PropertyDescriptor> descriptors) {
            this.name = name;
            int size = descriptors.size();
            properties = new TreePropertyWrapper[size];
            for (int i = 0; i < size; i++) {
                properties[i] = new TreePropertyWrapper(this, descriptors.get(i));
            }
        }
    }

    /**
     * Property.
     */
    private static class TreePropertyWrapper {
        public PropertiesGroup parent;
        public PropertyDescriptor descriptor;

        ////////////////////////////////////////////////////////////////////////////
        //
        // Constructor
        //
        ////////////////////////////////////////////////////////////////////////////
        public TreePropertyWrapper(PropertiesGroup parent, PropertyDescriptor descriptor) {
            this.parent = parent;
            this.descriptor = descriptor;
        }
    }

    /**
     * Tree content provider.
     */
    private static class TreePropertiesContentProvider implements ITreeContentProvider {
        public Object[] getElements(Object input) {
            List<?> list = (List<?>) input;
            return list.toArray();
        }

        public Object[] getChildren(Object element) {
            if (element instanceof PropertiesGroup) {
                PropertiesGroup group = (PropertiesGroup) element;
                return group.properties;
            }
            return null;
        }

        public boolean hasChildren(Object element) {
            if (element instanceof PropertiesGroup) {
                PropertiesGroup group = (PropertiesGroup) element;
                return group.properties.length > 0;
            }
            return false;
        }

        public Object getParent(Object element) {
            if (element instanceof TreePropertyWrapper) {
                TreePropertyWrapper wrapper = (TreePropertyWrapper) element;
                return wrapper.parent;
            }
            return null;
        }

        public void dispose() {
        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }
    }

    /**
     * Tree label provider.
     */
    private static class TreePropertiesLabelProvider extends LabelProvider {
        @Override
        public String getText(Object element) {
            if (element instanceof PropertiesGroup) {
                PropertiesGroup group = (PropertiesGroup) element;
                return group.name;
            }
            //
            TreePropertyWrapper wrapper = (TreePropertyWrapper) element;
            return wrapper.descriptor.getName();
        }

        @Override
        public Image getImage(Object element) {
            if (element instanceof PropertiesGroup) {
                return TypeImageProvider.OBJECT_IMAGE;
            }
            //
            TreePropertyWrapper wrapper = (TreePropertyWrapper) element;
            return TypeImageProvider.getImage(wrapper.descriptor.getPropertyType());
        }
    }

    /**
     * {@link ICheckStateListener} listener that supported only one checked element into one group.
     */
    private class PropertiesCheckStateListener implements ICheckStateListener {
        public void checkStateChanged(CheckStateChangedEvent event) {
            CheckboxTreeViewer viewer = (CheckboxTreeViewer) event.getCheckable();
            Object element = event.getElement();
            //
            if (event.getChecked()) {
                if (element instanceof PropertiesGroup) {
                    PropertiesGroup group = (PropertiesGroup) element;
                    if (ArrayUtils.isEmpty(group.properties)) {
                        // clear checked for empty group
                        viewer.setChecked(element, false);
                    } else {
                        // checked fist element if checked group
                        viewer.setChecked(group.properties[0], true);
                    }
                } else {
                    TreePropertyWrapper wrapper = (TreePropertyWrapper) element;
                    // ensure checked group
                    if (!viewer.getChecked(wrapper.parent)) {
                        viewer.setChecked(wrapper.parent, true);
                    }
                    // clear checked with other elements
                    for (TreePropertyWrapper property : wrapper.parent.properties) {
                        if (property != wrapper && viewer.getChecked(property)) {
                            viewer.setChecked(property, false);
                        }
                    }
                }
            } else {
                if (element instanceof PropertiesGroup) {
                    // clear checked elements if group unchecked
                    PropertiesGroup group = (PropertiesGroup) element;
                    for (TreePropertyWrapper property : group.properties) {
                        if (viewer.getChecked(property)) {
                            viewer.setChecked(property, false);
                        }
                    }
                } else {
                    // clear checked group if element unchecked
                    TreePropertyWrapper wrapper = (TreePropertyWrapper) element;
                    viewer.setChecked(wrapper.parent, false);
                }
            }
            //
            calculateFinish();
        }
    }
}