com.microsoft.tfs.client.common.ui.controls.vc.ServerItemTreeControl.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.tfs.client.common.ui.controls.vc.ServerItemTreeControl.java

Source

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See License.txt in the repository root.

package com.microsoft.tfs.client.common.ui.controls.vc;

import java.util.List;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IPostSelectionProvider;
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.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;

import com.microsoft.tfs.client.common.codemarker.CodeMarker;
import com.microsoft.tfs.client.common.codemarker.CodeMarkerDispatch;
import com.microsoft.tfs.client.common.ui.Messages;
import com.microsoft.tfs.client.common.ui.framework.action.StandardActionConstants;
import com.microsoft.tfs.client.common.ui.framework.sizing.ControlSize;
import com.microsoft.tfs.client.common.ui.framework.tree.TreeContentProvider;
import com.microsoft.tfs.client.common.ui.framework.validation.ActionValidatorBinding;
import com.microsoft.tfs.client.common.ui.framework.validation.NumericConstraint;
import com.microsoft.tfs.client.common.ui.framework.validation.SelectionProviderValidator;
import com.microsoft.tfs.client.common.ui.helpers.AutomationIDHelper;
import com.microsoft.tfs.client.common.ui.vc.serveritem.ServerItemLabelProvider;
import com.microsoft.tfs.client.common.ui.vc.serveritem.ServerItemSource;
import com.microsoft.tfs.client.common.ui.vc.serveritem.ServerItemType;
import com.microsoft.tfs.client.common.ui.vc.serveritem.TypedServerItem;
import com.microsoft.tfs.util.Check;
import com.microsoft.tfs.util.valid.Validator;

public class ServerItemTreeControl extends Composite implements IPostSelectionProvider, ServerItemControl {
    /**
     * SWT table styles that will always be used.
     */
    private static int TREE_STYLES = SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL;

    /**
     * SWT table styles that will only be used if the client passes them in.
     */
    private static int OPTIONAL_TREE_STYLES = SWT.MULTI | SWT.SINGLE;

    public static final String TREE_VIEWER_ID = "ServerItemTreeControl.viewer"; //$NON-NLS-1$

    public static final CodeMarker CODEMARKER_CHILD_NODES_FETCH_START = new CodeMarker(
            "com.microsoft.tfs.client.common.ui.controls.vc.ServerItemTreeControl#childNodesFetchStart"); //$NON-NLS-1$
    public static final CodeMarker CODEMARKER_CHILD_NODES_FETCH_COMPLETE = new CodeMarker(
            "com.microsoft.tfs.client.common.ui.controls.vc.ServerItemTreeControl#childNodesFetchComplete"); //$NON-NLS-1$

    private final TreeViewer viewer;
    private final MenuManager contextMenu;

    private IAction refreshAction;

    private TypedServerItem[] selectedItems;

    private ServerItemSource serverItemSource;

    public ServerItemTreeControl(final Composite parent, final int style) {
        super(parent, style);

        final FillLayout layout = new FillLayout();
        setLayout(layout);

        viewer = new TreeViewer(this, TREE_STYLES | (style & OPTIONAL_TREE_STYLES));
        AutomationIDHelper.setWidgetID(viewer.getTree(), TREE_VIEWER_ID);

        viewer.setUseHashlookup(true);
        viewer.setContentProvider(new ContentProvider());
        viewer.setLabelProvider(new ServerItemLabelProvider());
        viewer.addFilter(new Filter());
        viewer.setSorter(new ViewerSorter() {
            @Override
            public int compare(final Viewer viewer, final Object e1, final Object e2) {
                final TypedServerItem node1 = (TypedServerItem) e1;
                final TypedServerItem node2 = (TypedServerItem) e2;
                return node1.getName().compareToIgnoreCase(node2.getName());
            }
        });

        contextMenu = createContextMenu();
        createActions();
        contributeActions();

        viewer.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(final SelectionChangedEvent event) {
                final IStructuredSelection selection = (IStructuredSelection) event.getSelection();
                if (selection.size() == 0) {
                    selectedItems = null;
                } else {
                    @SuppressWarnings("unchecked")
                    final List<TypedServerItem> l = selection.toList();
                    selectedItems = l.toArray(new TypedServerItem[l.size()]);
                }
            }
        });

        viewer.addDoubleClickListener(new IDoubleClickListener() {
            @Override
            public void doubleClick(final DoubleClickEvent event) {
                final TypedServerItem doubleClickedElement = (TypedServerItem) ((IStructuredSelection) event
                        .getSelection()).getFirstElement();

                if (ServerItemType.isFolder(doubleClickedElement.getType())) {
                    final boolean expandedState = viewer.getExpandedState(doubleClickedElement);
                    viewer.setExpandedState(doubleClickedElement, !expandedState);
                }
            }
        });
    }

    public MenuManager getContextMenu() {
        return contextMenu;
    }

    public void setServerItemSource(final ServerItemSource serverItemSource) {
        this.serverItemSource = serverItemSource;

        ((ServerItemLabelProvider) viewer.getLabelProvider()).setServerItemSource(serverItemSource);
        viewer.setInput(serverItemSource);

        if (serverItemSource != null) {
            viewer.setExpandedState(TypedServerItem.ROOT, true);
        }
    }

    public void setLabelProvider(final IBaseLabelProvider labelProvider) {
        viewer.setLabelProvider(labelProvider);
    }

    public void setVisibleServerItemTypes(final ServerItemType[] visibleTypes) {
        Check.notNull(visibleTypes, "visibleTypes"); //$NON-NLS-1$

        final ViewerFilter[] filters = viewer.getFilters();
        for (int i = 0; i < filters.length; i++) {
            if (filters[i] instanceof Filter) {
                ((Filter) filters[i]).setVisibleTypes(visibleTypes);
                break;
            }
        }
    }

    private int getVisibleTypeFlags() {
        final ViewerFilter[] filters = viewer.getFilters();
        for (int i = 0; i < filters.length; i++) {
            if (filters[i] instanceof Filter) {
                return ((Filter) filters[i]).getVisibleTypeFlags();
            }
        }

        return -1;
    }

    public TypedServerItem[] getSelectedItems() {
        if (selectedItems == null) {
            return new TypedServerItem[0];
        } else {
            return selectedItems.clone();
        }
    }

    @Override
    public TypedServerItem getSelectedItem() {
        if (selectedItems == null) {
            return null;
        }

        return selectedItems[0];
    }

    @Override
    public void setSelectedItem(final TypedServerItem serverItem) {
        if (serverItem == null) {
            setSelection(StructuredSelection.EMPTY);
        } else {
            setSelection(new StructuredSelection(serverItem));
        }
    }

    public void setSelectedItems(final TypedServerItem[] serverItems) {
        if (serverItems == null) {
            setSelection(StructuredSelection.EMPTY);
        } else {
            setSelection(new StructuredSelection(serverItems), true);
        }
    }

    public void addDoubleClickListener(final IDoubleClickListener listener) {
        viewer.addDoubleClickListener(listener);
    }

    public void removeDoubleClickListener(final IDoubleClickListener listener) {
        viewer.removeDoubleClickListener(listener);
    }

    @Override
    public void addPostSelectionChangedListener(final ISelectionChangedListener listener) {
        viewer.addPostSelectionChangedListener(listener);
    }

    @Override
    public void removePostSelectionChangedListener(final ISelectionChangedListener listener) {
        viewer.removePostSelectionChangedListener(listener);
    }

    @Override
    public void addSelectionChangedListener(final ISelectionChangedListener listener) {
        viewer.addSelectionChangedListener(listener);
    }

    @Override
    public void removeSelectionChangedListener(final ISelectionChangedListener listener) {
        viewer.removeSelectionChangedListener(listener);
    }

    @Override
    public ISelection getSelection() {
        return viewer.getSelection();
    }

    @Override
    public void setSelection(final ISelection selection) {
        viewer.setSelection(selection);
    }

    public void setSelection(final ISelection selection, final boolean reveal) {
        viewer.setSelection(selection, reveal);
    }

    public void expandItem(final TypedServerItem item, final int level) {
        viewer.expandToLevel(item, level);
    }

    public Validator getSelectionValidator() {
        return new SelectionProviderValidator(this, NumericConstraint.ONE_OR_MORE,
                Messages.getString("ServerItemTreeControl.YouMustSelectAtLeastOneServerItem")); //$NON-NLS-1$
    }

    public Validator getSingleSelectionValidator() {
        return new SelectionProviderValidator(this, NumericConstraint.EXACTLY_ONE,
                Messages.getString("ServerItemTreeControl.YouMustSelectExactlyOneServerItem")); //$NON-NLS-1$
    }

    @Override
    public boolean setFocus() {
        return viewer.getControl().setFocus();
    }

    @Override
    public Point computeSize(final int wHint, final int hHint, final boolean changed) {
        return ControlSize.computeCharSize(wHint, hHint, viewer.getControl(), 60, 10);
    }

    private MenuManager createContextMenu() {
        final MenuManager menuManager = new MenuManager("#popup"); //$NON-NLS-1$
        menuManager.setRemoveAllWhenShown(true);
        viewer.getControl().setMenu(menuManager.createContextMenu(viewer.getControl()));
        return menuManager;
    }

    private void createActions() {
        refreshAction = new Action() {
            @Override
            public void run() {
                final TypedServerItem item = getSelectedItem();
                serverItemSource.clearChildCache(item);
                viewer.refresh(item);
            }
        };

        refreshAction.setText(Messages.getString("ServerItemTreeControl.RefreshActionName")); //$NON-NLS-1$

        new ActionValidatorBinding(refreshAction).bind(getSelectionValidator());
    }

    public void refreshTree() {
        final TypedServerItem item = getSelectedItem();
        serverItemSource.clearChildCache(item);
        viewer.refresh(item);
    }

    private void contributeActions() {
        contextMenu.addMenuListener(new IMenuListener() {
            @Override
            public void menuAboutToShow(final IMenuManager manager) {
                manager.add(new Separator(StandardActionConstants.HOSTING_CONTROL_CONTRIBUTIONS));
                manager.add(new Separator(StandardActionConstants.PRIVATE_CONTRIBUTIONS));

                manager.appendToGroup(StandardActionConstants.PRIVATE_CONTRIBUTIONS, refreshAction);
            }
        });
    }

    private static class Filter extends ViewerFilter {
        private int visibleTypeFlags;

        public Filter() {
            setVisibleTypes(ServerItemType.ALL);
        }

        public void setVisibleTypes(final ServerItemType[] visibleTypes) {
            /*
             * Bugfix: parent types must always be visible for children to be
             * visible.
             */

            visibleTypeFlags = 0;
            for (int i = 0; i < visibleTypes.length; i++) {
                visibleTypeFlags |= getVisibleParentTypes(visibleTypes[i]);
            }
        }

        public int getVisibleTypeFlags() {
            return visibleTypeFlags;
        }

        private int getVisibleParentTypes(final ServerItemType visibleType) {
            int flags = visibleType.getFlag();

            if (visibleType == ServerItemType.FILE) {
                flags |= getVisibleParentTypes(ServerItemType.FOLDER);
            }
            if (visibleType == ServerItemType.GIT_BRANCH) {
                flags |= getVisibleParentTypes(ServerItemType.GIT_REPOSITORY);
            } else if (visibleType == ServerItemType.FOLDER || visibleType == ServerItemType.GIT_REPOSITORY) {
                flags |= getVisibleParentTypes(ServerItemType.TEAM_PROJECT);
            } else if (visibleType == ServerItemType.TEAM_PROJECT) {
                flags |= getVisibleParentTypes(ServerItemType.ROOT);
            }

            return flags;
        }

        @Override
        public boolean select(final Viewer viewer, final Object parentElement, final Object element) {
            final TypedServerItem node = (TypedServerItem) element;
            return (visibleTypeFlags & node.getType().getFlag()) > 0;
        }
    }

    private class ContentProvider extends TreeContentProvider {
        private ServerItemSource source;

        @Override
        public Object[] getChildren(final Object parentElement) {
            CodeMarkerDispatch.dispatch(CODEMARKER_CHILD_NODES_FETCH_START);

            final TypedServerItem parent = (TypedServerItem) parentElement;
            final Object[] children = source.getChildren(parent);

            CodeMarkerDispatch.dispatch(CODEMARKER_CHILD_NODES_FETCH_COMPLETE);

            if (children.length == 0) {
                return null;
            }

            return children;
        }

        @Override
        public boolean hasChildren(final Object element) {
            final TypedServerItem item = (TypedServerItem) element;

            if (item.getType().equals(ServerItemType.FILE)) {
                return false;
            }

            if (item.getType().equals(ServerItemType.GIT_REPOSITORY)) {
                return (getVisibleTypeFlags() & ServerItemType.GIT_BRANCH.getFlag()) != 0;
            }

            return true;
        }

        @Override
        public Object[] getElements(final Object inputElement) {
            source = (ServerItemSource) inputElement;

            if (source == null) {
                return new Object[] {};
            } else {
                return new Object[] { TypedServerItem.ROOT };
            }
        }

        @Override
        public Object getParent(final Object element) {
            final TypedServerItem node = (TypedServerItem) element;
            return node.getParent();
        }
    }
}