de.walware.ecommons.ui.workbench.ContainerSelectionComposite.java Source code

Java tutorial

Introduction

Here is the source code for de.walware.ecommons.ui.workbench.ContainerSelectionComposite.java

Source

/*=============================================================================#
 # Copyright (c) 2005-2015 Stephan Wahlbrink (WalWare.de) 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:
 #     Stephan Wahlbrink - initial API and implementation
 #=============================================================================*/

package de.walware.ecommons.ui.workbench;

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

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
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.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.part.DrillDownAdapter;

import de.walware.ecommons.ui.SharedMessages;
import de.walware.ecommons.ui.SharedUIResources;
import de.walware.ecommons.ui.components.StatusInfo;
import de.walware.ecommons.ui.internal.Messages;

/**
 * Workbench-level composite for choosing a container.
 */
public class ContainerSelectionComposite extends Composite {

    public static abstract class ContainerFilter extends ViewerFilter {

        IPath fExcludePath;

        @Override
        public boolean select(final Viewer viewer, final Object parentElement, final Object element) {

            if (!(element instanceof IContainer)) {
                return true; // never
            }

            final IContainer container = (IContainer) element;
            if (fExcludePath != null) {
                if (container.getFullPath().isPrefixOf(fExcludePath)) {
                    return true;
                }
            }

            return select(container);
        }

        public abstract boolean select(IContainer container);
    }

    private class CollapseAllAction extends Action {
        CollapseAllAction() {
            super();
            setText(SharedMessages.CollapseAllAction_label);
            setDescription(SharedMessages.CollapseAllAction_description);
            setToolTipText(SharedMessages.CollapseAllAction_tooltip);
            setImageDescriptor(
                    SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_COLLAPSEALL_IMAGE_ID));
        }

        @Override
        public void run() {

            fTreeViewer.collapseAll();
        }
    }

    private class ExpandAllAction extends Action {
        ExpandAllAction() {
            super();
            setText(SharedMessages.ExpandAllAction_label);
            setDescription(SharedMessages.ExpandAllAction_description);
            setToolTipText(SharedMessages.ExpandAllAction_tooltip);
            setImageDescriptor(
                    SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_EXPANDALL_IMAGE_ID));
        }

        @Override
        public void run() {

            fTreeViewer.expandAll();
        }

    }

    private class ToggleFilterAction extends Action {
        ToggleFilterAction() {
            super();
            setText(Messages.FilterFavouredContainersAction_label);
            setDescription(Messages.FilterFavouredContainersAction_description);
            setToolTipText(Messages.FilterFavouredContainersAction_tooltip);
            setImageDescriptor(
                    SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_FILTER_IMAGE_ID));
            setDisabledImageDescriptor(
                    SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOLD_FILTER_IMAGE_ID));
            setChecked(false);
        }

        @Override
        public void run() {

            final boolean enable = isChecked();
            doToggleFilter(enable);
            fIsToggleFilterActivated = enable;
        }

        void doToggleFilter(final boolean enable) {

            if (enable) {
                fTreeViewer.addFilter(fToggledFilter);
            } else {
                fTreeViewer.removeFilter(fToggledFilter);
            }
        }

    }

    // sizing constants
    private static final int SIZING_SELECTION_PANE_WIDTH = 320;
    //   private static final int SIZING_SELECTION_PANE_HEIGHT = 300;

    // Enable user to type in new container name
    private boolean fAllowNewContainerName = true;

    // show all projects by default
    private boolean fShowClosedProjects = true;

    // Last selection made by user
    private IContainer fSelectedContainer;

    // handle on parts
    private Text fContainerNameField;
    private TreeViewer fTreeViewer;
    private ToolBarManager fRightToolBarMgr;

    private boolean fIsToggleFilterActivated;
    private ContainerFilter fToggledFilter;

    // The listener to notify of events
    private Listener fListener;

    //   /**
    //    * Creates a new instance of the widget.
    //    * 
    //    * @param parent The parent widget of the group.
    //    * @param listener A listener to forward events to. Can be null if
    //    *     no listener is required.
    //    * @param allowNewContainerName Enable the user to type in a new container
    //    *     name instead of just selecting from the existing ones.
    //    */
    //   public ContainerSelectionControl(Composite parent, Listener listener, boolean allowNewContainerName) {
    //      
    //      this(parent, listener, allowNewContainerName, null);
    //   }
    //   
    //   /**
    //    * Creates a new instance of the widget.
    //    * 
    //    * @param parent The parent widget of the group.
    //    * @param listener A listener to forward events to.  Can be null if
    //    *    no listener is required.
    //    * @param allowNewContainerName Enable the user to type in a new container
    //    *  name instead of just selecting from the existing ones.
    //    * @param message The text to present to the user.
    //    */
    //   public ContainerSelectionControl(Composite parent, Listener listener, boolean allowNewContainerName, 
    //         String message) {
    //      
    //      this(parent, listener, allowNewContainerName, message, true);
    //   }
    //   
    //   /**
    //    * Creates a new instance of the widget.
    //    * 
    //    * @param parent The parent widget of the group.
    //    * @param listener A listener to forward events to.  Can be null if
    //    *    no listener is required.
    //    * @param allowNewContainerName Enable the user to type in a new container
    //    *  name instead of just selecting from the existing ones.
    //    * @param message The text to present to the user.
    //    * @param showClosedProjects Whether or not to show closed projects.
    //    */
    //   public ContainerSelectionControl(Composite parent, Listener listener, boolean allowNewContainerName, 
    //         String message, boolean showClosedProjects) {
    //      
    //      this(parent, listener, allowNewContainerName, message,
    //            showClosedProjects, SIZING_SELECTION_PANE_HEIGHT);
    //   }

    /**
     * Creates a new instance of the widget.
     * 
     * @param parent The parent widget of the group.
     * @param listener A listener to forward events to.  Can be null if
     *     no listener is required.
     * @param allowNewContainerName Enable the user to type in a new container
     *     name instead of just selecting from the existing ones.
     * @param message The text to present to the user.
     * @param showClosedProjects Whether or not to show closed projects.
     * @param heightHint height hint for the drill down composite
     */
    public ContainerSelectionComposite(final Composite parent, final boolean allowNewContainerName,
            final boolean showClosedProjects, String message, final int heightHint) {
        super(parent, SWT.NONE);
        fAllowNewContainerName = allowNewContainerName;
        fShowClosedProjects = showClosedProjects;
        if (message == null) {
            if (allowNewContainerName) {
                message = Messages.ContainerSelectionControl_label_EnterOrSelectFolder;
            } else {
                message = Messages.ContainerSelectionControl_label_SelectFolder;
            }
        }
        createContents(message, heightHint);
    }

    /**
     * Creates the contents of the composite.
     * 
     * @param heightHint height hint for the drill down composite
     */
    public void createContents(final String message, final int heightHint) {
        final GridLayout layout = new GridLayout();
        layout.marginWidth = 0;
        setLayout(layout);
        setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        final Label label = new Label(this, SWT.WRAP);
        label.setText(message);

        if (fAllowNewContainerName) {
            fContainerNameField = new Text(this, SWT.SINGLE | SWT.BORDER);
            fContainerNameField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
            fContainerNameField.setFont(this.getFont());
        } else {
            // filler...
            new Label(this, SWT.NONE); // bentigt?
        }

        createTreeViewer(heightHint);
        Dialog.applyDialogFont(this);
    }

    /**
     * Returns a new drill down viewer for this dialog.
     * 
     * @param heightHint height hint for the drill down composite
     * @return a new drill down viewer
     */
    protected void createTreeViewer(final int heightHint) {
        // Create group with dril down toolbar and tree.
        final Composite treeGroup = new Composite(this, SWT.BORDER);

        final GridLayout layout = new GridLayout();
        layout.marginHeight = layout.marginWidth = layout.verticalSpacing = layout.horizontalSpacing = 0;
        layout.numColumns = 2;
        treeGroup.setLayout(layout);

        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.widthHint = SIZING_SELECTION_PANE_WIDTH;
        gd.heightHint = heightHint;
        treeGroup.setLayoutData(gd);

        // Create a toolbars.
        final ToolBarManager leftToolBarMgr = new ToolBarManager(SWT.FLAT);
        ToolBar toolBar = leftToolBarMgr.createControl(treeGroup);
        toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));

        toolBar = new ToolBar(treeGroup, SWT.FLAT);
        toolBar.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, false, 1, 1));
        fRightToolBarMgr = new ToolBarManager(toolBar);

        final Label filler = new Label(treeGroup, SWT.LEFT);
        gd = new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1);
        gd.heightHint = 2;
        filler.setLayoutData(gd);

        // Create tree viewer
        fTreeViewer = new TreeViewer(treeGroup, SWT.NONE);
        fTreeViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));

        // Fill toolbars
        final DrillDownAdapter adapter = new DrillDownAdapter(fTreeViewer);
        adapter.addNavigationActions(leftToolBarMgr);

        fRightToolBarMgr.add(new CollapseAllAction());
        fRightToolBarMgr.add(new ExpandAllAction());

        leftToolBarMgr.update(true);
        fRightToolBarMgr.update(true);

        // layout group
        treeGroup.layout();

        final ContainerContentProvider cp = new ContainerContentProvider();
        cp.showClosedProjects(fShowClosedProjects);
        fTreeViewer.setContentProvider(cp);
        fTreeViewer.setLabelProvider(WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider());
        fTreeViewer.setSorter(new ViewerSorter());
        fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(final SelectionChangedEvent event) {
                final IStructuredSelection selection = (IStructuredSelection) event.getSelection();
                containerSelectionChanged((IContainer) selection.getFirstElement()); // allow null
            }
        });
        fTreeViewer.addDoubleClickListener(new IDoubleClickListener() {
            @Override
            public void doubleClick(final DoubleClickEvent event) {
                final ISelection selection = event.getSelection();
                if (selection instanceof IStructuredSelection) {
                    final Object item = ((IStructuredSelection) selection).getFirstElement();
                    if (item == null) {
                        return;
                    }
                    if (fTreeViewer.getExpandedState(item)) {
                        fTreeViewer.collapseToLevel(item, 1);
                    } else {
                        fTreeViewer.expandToLevel(item, 1);
                    }
                }
            }
        });

        // This has to be done after the viewer has been laid out
        fTreeViewer.setInput(ResourcesPlugin.getWorkspace());
    }

    public void setToggleFilter(final ContainerFilter filter, final boolean initialEnabled) {
        fToggledFilter = filter;
        fIsToggleFilterActivated = initialEnabled;
        final ToggleFilterAction action = new ToggleFilterAction();
        fRightToolBarMgr.add(new Separator());
        fRightToolBarMgr.add(action);

        // check and init
        action.doToggleFilter(true);
        if (fTreeViewer.getTree().getItemCount() == 0) {
            action.doToggleFilter(false);
            action.setChecked(false);
            action.setEnabled(false);
        } else {
            action.setChecked(initialEnabled);
            if (!initialEnabled) {
                action.doToggleFilter(false);
            }
        }

        fRightToolBarMgr.update(true);
        fRightToolBarMgr.getControl().getParent().layout();
    }

    public boolean getToggleFilterSetting() {
        return fIsToggleFilterActivated;
    }

    /**
     * Listener will be notified, if container selection changed.
     * 
     * @param listener
     */
    public void setListener(final Listener listener) {
        fListener = listener;
        if (fContainerNameField != null) {
            fContainerNameField.addListener(SWT.Modify, fListener);
        }
    }

    /**
     * Gives focus to one of the widgets in the group, as determined by the group.
     */
    public void setInitialFocus() {
        if (fAllowNewContainerName) {
            fContainerNameField.setFocus();
        } else {
            fTreeViewer.getTree().setFocus();
        }
    }

    /**
     * The container selection has changed in the
     * tree view. Update the container name field
     * value and notify all listeners.
     */
    public void containerSelectionChanged(final IContainer container) {
        if (fAllowNewContainerName) {
            if (container != null) {
                fSelectedContainer = container;
                fContainerNameField.setText(container.getFullPath().makeRelative().toString());
            }
        } else {
            fSelectedContainer = container;
            // fire an event so the parent can update its controls
            if (fListener != null) {
                final Event changeEvent = new Event();
                changeEvent.type = SWT.Selection;
                changeEvent.widget = this;
                fListener.handleEvent(changeEvent);
            }
        }
    }

    /**
     * Returns the currently entered container name.
     * <p>
     * Note that the container may not exist yet if the user
     * entered a new container name in the field.
     * 
     * @return Path of Container, <code>null</code> if the field is empty.
     */
    public IPath getContainerFullPath() {
        if (fAllowNewContainerName) {
            final String pathName = fContainerNameField.getText();
            if (pathName == null || pathName.length() < 1) {
                return null;
            } else {
                //The user may not have made this absolute so do it for them
                return (new Path(pathName)).makeAbsolute();
            }
        } else {
            if (fSelectedContainer == null) {
                return null;
            } else {
                return fSelectedContainer.getFullPath();
            }
        }
    }

    /**
     * Sets the selected existing container.
     */
    public void selectContainer(final IContainer container) {
        fSelectedContainer = container;

        //expand to and select the specified container
        final List<IContainer> itemsToExpand = new ArrayList<IContainer>();
        IContainer parent = container.getParent();
        while (parent != null) {
            itemsToExpand.add(0, parent);
            parent = parent.getParent();
        }
        // update filter
        if (fToggledFilter != null) {
            fToggledFilter.fExcludePath = container.getFullPath();
            fTreeViewer.refresh();
        }
        // update selection
        fTreeViewer.setExpandedElements(itemsToExpand.toArray());
        fTreeViewer.setSelection(new StructuredSelection(container), true);
    }

    /**
     * Sets the value of this page's container.
     * 
     * @param path Full path to the container.
     */
    public void selectContainer(final IPath path) {
        IResource initial = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
        if (initial != null) {
            if (!(initial instanceof IContainer)) {
                initial = initial.getParent();
            }
            selectContainer((IContainer) initial);
        }
    }

    public static IStatus validate(IPath path) {
        // validate Container
        if (path == null || path.isEmpty()) {
            return new StatusInfo(IStatus.ERROR, Messages.ContainerSelectionControl_error_FolderEmpty);
        }
        final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        final String projectName = path.segment(0);
        if (projectName == null || !root.getProject(projectName).exists()) {
            return new StatusInfo(IStatus.ERROR, Messages.ContainerSelectionControl_error_ProjectNotExists);
        }
        //path is invalid if any prefix is occupied by a file
        while (path.segmentCount() > 1) {
            if (root.getFile(path).exists()) {
                return new StatusInfo(IStatus.ERROR,
                        NLS.bind(Messages.ContainerSelectionControl_error_PathOccupied, path.makeRelative()));
            }
            path = path.removeLastSegments(1);
        }
        return new StatusInfo();
    }

}