org.eclipse.ui.internal.activities.ws.ActivityEnabler.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ui.internal.activities.ws.ActivityEnabler.java

Source

/*******************************************************************************
 * Copyright (c) 2003, 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
 *******************************************************************************/
package org.eclipse.ui.internal.activities.ws;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.activities.ActivitiesPreferencePage;
import org.eclipse.ui.activities.IActivity;
import org.eclipse.ui.activities.ICategory;
import org.eclipse.ui.activities.IMutableActivityManager;
import org.eclipse.ui.activities.NotDefinedException;
import org.eclipse.ui.internal.activities.InternalActivityHelper;

/**
 * A simple control provider that will allow the user to toggle on/off the
 * activities bound to categories.
 * 
 * @since 3.0
 */
public class ActivityEnabler {

    private static final int ALL = 2;

    private static final int NONE = 0;

    private static final int SOME = 1;

    private ISelectionChangedListener selectionListener = new ISelectionChangedListener() {

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
         */
        public void selectionChanged(SelectionChangedEvent event) {
            Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
            try {
                if (element instanceof ICategory) {
                    descriptionText.setText(((ICategory) element).getDescription());
                } else if (element instanceof IActivity) {
                    descriptionText.setText(((IActivity) element).getDescription());
                }
            } catch (NotDefinedException e) {
                descriptionText.setText(""); //$NON-NLS-1$
            }
        }
    };

    /**
     * Listener that manages the grey/check state of categories.
     */
    private ICheckStateListener checkListener = new ICheckStateListener() {

        /*
         * (non-Javadoc)
         * 
         * @see org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged(org.eclipse.jface.viewers.CheckStateChangedEvent)
         */
        public void checkStateChanged(CheckStateChangedEvent event) {
            Set checked = new HashSet(Arrays.asList(dualViewer.getCheckedElements()));
            Object element = event.getElement();
            if (element instanceof ICategory) {
                // clicking on a category should enable/disable all activities
                // within it
                dualViewer.setSubtreeChecked(element, event.getChecked());
                // the state of the category is always absolute after clicking
                // on it. Never gray.
                dualViewer.setGrayed(element, false);
                Object categoryActivities[] = provider.getChildren(element);
                // Update the category's activities for multiplicity in other
                // categories
                for (int index = 0; index < categoryActivities.length; index++) {
                    handleDuplicateActivities(event.getChecked(), categoryActivities[index]);
                }

            } else {
                // Activity checked
                handleActivityCheck(checked, element);
                handleDuplicateActivities(event.getChecked(), element);
            }
        }

        /**
         * Handle duplicate activities.
         * 
         * @param checkedState
         *            Checked state of the element.
         * @param element
         *            The checked element.
         */
        private void handleDuplicateActivities(boolean checkedState, Object element) {
            // Retrieve duplicate activities from the other categories
            Object[] duplicateActivities = provider.getDuplicateCategoryActivities((CategorizedActivity) element);
            CategorizedActivity activity = null;
            for (int index = 0; index < duplicateActivities.length; index++) {
                activity = (CategorizedActivity) duplicateActivities[index];
                // Update the duplicate activity with the same state as the
                // original
                dualViewer.setChecked(activity, checkedState);
                // handle the activity check to potentially update its
                // category's enablement
                handleActivityCheck(new HashSet(Arrays.asList(dualViewer.getCheckedElements())), activity);
            }
        }

        /**
         * Handle the checking of an activity and update its category's checked
         * state.
         * 
         * @param checked
         *            The set of checked elements in the viewer.
         * @param element
         *            The checked element.
         */
        private void handleActivityCheck(Set checked, Object element) {
            // clicking on an activity can potentially change the check/gray
            // state of its category.
            CategorizedActivity proxy = (CategorizedActivity) element;
            Object[] children = provider.getChildren(proxy.getCategory());
            int state = NONE;
            int count = 0;
            for (int i = 0; i < children.length; i++) {
                if (checked.contains(children[i])) {
                    count++;
                }
            }

            if (count == children.length) {
                state = ALL;
            } else if (count != 0) {
                state = SOME;
            }

            if (state == NONE) {
                checked.remove(proxy.getCategory());
            } else {
                checked.add(proxy.getCategory());
            }

            dualViewer.setGrayed(proxy.getCategory(), state == SOME);
            dualViewer.setCheckedElements(checked.toArray());
            // Check child required activities and uncheck parent required activities
            // if needed
            handleRequiredActivities(checked, element);
        }

        /**
         * Handle the activity's required activities (parent and child).
         * 
         * @param checked
         *            The set of checked elements in the viewer.
         * @param element
         *            The checked element.
         *  
         */
        private void handleRequiredActivities(Set checked, Object element) {
            Object[] requiredActivities = null;
            // An element has been checked - we want to check its child required
            // activities
            if (checked.contains(element)) {
                requiredActivities = provider.getChildRequiredActivities(((CategorizedActivity) element).getId());
                for (int index = 0; index < requiredActivities.length; index++) {
                    // We want to check the element if it is unchecked
                    if (!checked.contains(requiredActivities[index])) {
                        dualViewer.setChecked(requiredActivities[index], true);
                        handleActivityCheck(new HashSet(Arrays.asList(dualViewer.getCheckedElements())),
                                requiredActivities[index]);
                    }
                }
            }
            // An element has been unchecked - we want to uncheck its parent
            // required activities
            else {
                requiredActivities = provider.getParentRequiredActivities(((CategorizedActivity) element).getId());
                for (int index = 0; index < requiredActivities.length; index++) {
                    // We want to uncheck the element if it is checked
                    if (checked.contains(requiredActivities[index])) {
                        dualViewer.setChecked(requiredActivities[index], false);
                        handleActivityCheck(new HashSet(Arrays.asList(dualViewer.getCheckedElements())),
                                requiredActivities[index]);
                    }
                }
            }
        }

    };

    protected CheckboxTreeViewer dualViewer;

    /**
     * The Set of activities that belong to at least one category.
     */
    private Set managedActivities = new HashSet(7);

    /**
     * The content provider.
     */
    protected ActivityCategoryContentProvider provider = new ActivityCategoryContentProvider();

    /**
     * The descriptive text.
     */
    protected Text descriptionText;

    private Properties strings;

    private IMutableActivityManager activitySupport;

    /**
     * Create a new instance.
     * 
     * @param activitySupport
     *            the <code>IMutableActivityMananger</code> to use.
     * @param strings
     *            map of strings to use. See the constants on
     *            {@link org.eclipse.ui.activities.ActivitiesPreferencePage} for
     *            details.
     */
    public ActivityEnabler(IMutableActivityManager activitySupport, Properties strings) {
        this.activitySupport = activitySupport;
        this.strings = strings;
    }

    /**
     * Create the controls.
     * 
     * @param parent
     *            the parent in which to create the controls.
     * @return the composite in which the controls exist.
     */
    public Control createControl(Composite parent) {
        GC gc = new GC(parent);
        gc.setFont(JFaceResources.getDialogFont());
        FontMetrics fontMetrics = gc.getFontMetrics();
        gc.dispose();

        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(createGridLayoutWithoutMargins(1, fontMetrics));

        new Label(composite, SWT.NONE).setText(strings.getProperty(ActivitiesPreferencePage.ACTIVITY_NAME,
                ActivityMessages.ActivityEnabler_activities) + ':');

        dualViewer = new CheckboxTreeViewer(composite);
        dualViewer.setComparator(new ViewerComparator());
        dualViewer.setLabelProvider(new ActivityCategoryLabelProvider());
        dualViewer.setContentProvider(provider);
        dualViewer.setInput(activitySupport);
        GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
        dualViewer.getControl().setLayoutData(data);

        Composite buttonComposite = new Composite(composite, SWT.NONE);
        buttonComposite.setLayout(createGridLayoutWithoutMargins(2, fontMetrics));

        Button selectAllButton = new Button(buttonComposite, SWT.PUSH);
        selectAllButton.setText(ActivityMessages.ActivityEnabler_selectAll);
        selectAllButton.addSelectionListener(new SelectionAdapter() {
            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            public void widgetSelected(SelectionEvent e) {
                toggleTreeEnablement(true);
            }
        });
        setButtonLayoutData(selectAllButton, fontMetrics);

        Button deselectAllButton = new Button(buttonComposite, SWT.PUSH);
        deselectAllButton.setText(ActivityMessages.ActivityEnabler_deselectAll);
        deselectAllButton.addSelectionListener(new SelectionAdapter() {
            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            public void widgetSelected(SelectionEvent e) {
                toggleTreeEnablement(false);
            }
        });
        setButtonLayoutData(deselectAllButton, fontMetrics);

        new Label(composite, SWT.NONE).setText(ActivityMessages.ActivityEnabler_description);

        descriptionText = new Text(composite, SWT.READ_ONLY | SWT.WRAP | SWT.BORDER | SWT.V_SCROLL);
        data = new GridData(SWT.FILL, SWT.FILL, true, false);
        data.heightHint = Dialog.convertHeightInCharsToPixels(fontMetrics, 5);
        descriptionText.setLayoutData(data);
        setInitialStates();

        dualViewer.addCheckStateListener(checkListener);
        dualViewer.addSelectionChangedListener(selectionListener);

        dualViewer.setSelection(new StructuredSelection());

        Dialog.applyDialogFont(composite);

        return composite;
    }

    private GridLayout createGridLayoutWithoutMargins(int nColumns, FontMetrics fontMetrics) {
        GridLayout layout = new GridLayout(nColumns, false);
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        layout.horizontalSpacing = Dialog.convertHorizontalDLUsToPixels(fontMetrics,
                IDialogConstants.HORIZONTAL_SPACING);
        layout.verticalSpacing = Dialog.convertVerticalDLUsToPixels(fontMetrics, IDialogConstants.VERTICAL_SPACING);
        return layout;
    }

    private GridData setButtonLayoutData(Button button, FontMetrics fontMetrics) {
        GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
        int widthHint = Dialog.convertHorizontalDLUsToPixels(fontMetrics, IDialogConstants.BUTTON_WIDTH);
        Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
        data.widthHint = Math.max(widthHint, minSize.x);
        button.setLayoutData(data);
        return data;
    }

    /**
     * Set the enabled category/activity check/grey states based on initial
     * activity enablement.
     */
    private void setInitialStates() {
        Set enabledActivities = activitySupport.getEnabledActivityIds();
        setEnabledStates(enabledActivities);
    }

    private void setEnabledStates(Set enabledActivities) {
        Set categories = activitySupport.getDefinedCategoryIds();
        List checked = new ArrayList(10), grayed = new ArrayList(10);
        for (Iterator i = categories.iterator(); i.hasNext();) {
            String categoryId = (String) i.next();
            ICategory category = activitySupport.getCategory(categoryId);

            int state = NONE;

            Collection activities = InternalActivityHelper.getActivityIdsForCategory(activitySupport, category);
            int foundCount = 0;
            for (Iterator j = activities.iterator(); j.hasNext();) {
                String activityId = (String) j.next();
                managedActivities.add(activityId);
                if (enabledActivities.contains(activityId)) {
                    IActivity activity = activitySupport.getActivity(activityId);
                    checked.add(new CategorizedActivity(category, activity));
                    //add activity proxy
                    foundCount++;
                }
            }

            if (foundCount == activities.size()) {
                state = ALL;
            } else if (foundCount > 0) {
                state = SOME;
            }

            if (state == NONE) {
                continue;
            }
            checked.add(category);

            if (state == SOME) {
                grayed.add(category);
            }
        }

        dualViewer.setCheckedElements(checked.toArray());
        dualViewer.setGrayedElements(grayed.toArray());
    }

    /**
     * Update activity enablement based on the check states of activities in the
     * tree.
     */
    public void updateActivityStates() {
        Set enabledActivities = new HashSet(activitySupport.getEnabledActivityIds());

        // remove all but the unmanaged activities (if any).
        enabledActivities.removeAll(managedActivities);

        Object[] checked = dualViewer.getCheckedElements();
        for (int i = 0; i < checked.length; i++) {
            Object element = checked[i];
            if (element instanceof ICategory || dualViewer.getGrayed(element)) {
                continue;
            }
            enabledActivities.add(((IActivity) element).getId());
        }

        activitySupport.setEnabledActivityIds(enabledActivities);
    }

    /**
     * Restore the default activity states.
     */
    public void restoreDefaults() {
        Set defaultEnabled = new HashSet();
        Set activityIds = activitySupport.getDefinedActivityIds();
        for (Iterator i = activityIds.iterator(); i.hasNext();) {
            String activityId = (String) i.next();
            IActivity activity = activitySupport.getActivity(activityId);
            try {
                if (activity.isDefaultEnabled()) {
                    defaultEnabled.add(activityId);
                }
            } catch (NotDefinedException e) {
                // this can't happen - we're iterating over defined activities.
            }
        }

        setEnabledStates(defaultEnabled);
    }

    /**
     * Toggles the enablement state of all activities.
     * 
     * @param enabled
     *            whether the tree should be enabled
     */
    protected void toggleTreeEnablement(boolean enabled) {
        Object[] elements = provider.getElements(activitySupport);

        //reset grey state to null
        dualViewer.setGrayedElements(new Object[0]);

        //enable all categories
        for (int i = 0; i < elements.length; i++) {
            dualViewer.expandToLevel(elements[i], AbstractTreeViewer.ALL_LEVELS);
            dualViewer.setSubtreeChecked(elements[i], enabled);
        }
    }
}