org.eclipse.ui.ide.markers.compatibility.internal.ExtendedMarkersView.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ui.ide.markers.compatibility.internal.ExtendedMarkersView.java

Source

/*******************************************************************************
 * Copyright (c) 2007 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.ide.markers.compatibility.internal;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.mapping.ResourceMapping;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.ContributionManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.OpenStrategy;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.events.HelpEvent;
import org.eclipse.swt.events.HelpListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.TreeAdapter;
import org.eclipse.swt.events.TreeEvent;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Scrollable;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.contexts.IContext;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.ide.ResourceUtil;
import org.eclipse.ui.ide.markers.compatibility.api.MarkerField;
import org.eclipse.ui.ide.markers.compatibility.api.MarkerItem;
import org.eclipse.ui.ide.markers.compatibility.api.MarkerSupportConstants;
import org.eclipse.ui.internal.ide.IDEInternalPreferences;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.ide.StatusUtil;
import org.eclipse.ui.menus.IMenuService;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.progress.WorkbenchJob;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.ui.views.markers.internal.MarkerMessages;
import org.eclipse.ui.views.markers.internal.MarkerSupportRegistry;
import org.eclipse.ui.views.tasklist.ITaskListResourceAdapter;

/**
 * The ExtendedMarkersView is the internal implementation of the view that shows
 * markers using the markerGenerators extension point.
 * 
 * The ExtendedMarkersView fully supports the markerSupport extension point and
 * is meant to be used as a view to complement them.
 * 
 * The markerContentGenerators to be used by the view can be specified by
 * appending a comma separated list of them after a colon in the class
 * specification of the view. If this list is left out the problems
 * markerContentProvider will be used.
 * 
 * @since 3.4
 * 
 */
public class ExtendedMarkersView extends ViewPart {

    /**
     * MarkerSelectionEntry is a cache of the values for a marker entry.
     * 
     * @since 3.4
     * 
     */
    final class MarkerSelectionEntry {

        Object[] cachedValues;

        MarkerSelectionEntry(MarkerItem item) {
            MarkerField[] fields = builder.getVisibleFields();
            cachedValues = new Object[fields.length];
            for (int i = 0; i < fields.length; i++) {
                cachedValues[i] = fields[i].getValue(item);
            }
        }

        /**
         * Return whether or not the entry is equivalent to the cached state.
         * 
         * @param item
         * @return boolean <code>true</code> if they are equivalent
         */
        boolean isEquivalentTo(MarkerItem item) {
            MarkerField[] fields = builder.getVisibleFields();

            if (cachedValues.length != fields.length)
                return false;

            for (int i = 0; i < fields.length; i++) {
                if (cachedValues[i] == fields[i].getValue(item))
                    continue;
                return false;
            }
            return true;
        }

    }

    private static int instanceCount = 0;

    private static final String TAG_GENERATOR = "markerContentGenerator"; //$NON-NLS-1$
    private static final String TAG_HORIZONTAL_POSITION = "horizontalPosition"; //$NON-NLS-1$
    private static final String TAG_VERTICAL_POSITION = "verticalPosition"; //$NON-NLS-1$
    private static final String MARKER_FIELD = "MARKER_FIELD"; //$NON-NLS-1$

    private static final String TAG_EXPANDED = "expanded"; //$NON-NLS-1$

    private static final String TAG_CATEGORY = "category"; //$NON-NLS-1$

    private static final String TAG_PART_NAME = "partName"; //$NON-NLS-1$
    static {
        Platform.getAdapterManager().registerAdapters(new IAdapterFactory() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object,
             *      java.lang.Class)
             */
            public Object getAdapter(Object adaptableObject, Class adapterType) {
                if (adapterType == IMarker.class && adaptableObject instanceof MarkerEntry)
                    return ((MarkerEntry) adaptableObject).getMarker();

                return null;
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList()
             */
            public Class[] getAdapterList() {
                return new Class[] { IMarker.class };
            }
        }, MarkerEntry.class);
    }

    /**
     * Return the next secondary id.
     * 
     * @return String
     */
    static String newSecondaryID() {
        return String.valueOf(instanceCount);
    }

    /**
     * Open the supplied marker in an editor in page
     * 
     * @param marker
     * @param page
     */
    public static void openMarkerInEditor(IMarker marker, IWorkbenchPage page) {
        // optimization: if the active editor has the same input as
        // the
        // selected marker then
        // RevealMarkerAction would have been run and we only need
        // to
        // activate the editor
        IEditorPart editor = page.getActiveEditor();
        if (editor != null) {
            IEditorInput input = editor.getEditorInput();
            IFile file = ResourceUtil.getFile(input);
            if (file != null) {
                if (marker.getResource().equals(file)) {
                    page.activate(editor);
                }
            }
        }

        if (marker != null && marker.getResource() instanceof IFile) {
            try {
                IDE.openEditor(page, marker, OpenStrategy.activateOnOpen());
            } catch (PartInitException e) {

                // Check for a nested CoreException
                IStatus status = e.getStatus();
                if (status != null && status.getException() instanceof CoreException) {
                    status = ((CoreException) status.getException()).getStatus();
                }

                if (status == null)
                    StatusManager.getManager().handle(StatusUtil.newStatus(IStatus.ERROR, e.getMessage(), e),
                            StatusManager.SHOW);

                else
                    StatusManager.getManager().handle(status, StatusManager.SHOW);

            }
        }
    }

    private CachedMarkerBuilder builder;
    Collection categoriesToExpand;

    private Clipboard clipboard;

    Collection preservedSelection = new ArrayList();

    private Job updateJob;

    private MarkersTreeViewer viewer;
    private IPropertyChangeListener preferenceListener;
    private ISelectionListener pageSelectionListener;
    private IPartListener2 partListener;
    private IMemento memento;

    private String[] defaultGeneratorIds = new String[0];

    /**
     * Return a new instance of the receiver.
     * 
     * @param contentGeneratorId
     *            the id of the generator to load.
     */
    public ExtendedMarkersView(String contentGeneratorId) {
        super();
        instanceCount++;
        defaultGeneratorIds = new String[] { contentGeneratorId };
        preferenceListener = new IPropertyChangeListener() {
            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
             */
            public void propertyChange(PropertyChangeEvent event) {
                String propertyName = event.getProperty();
                if (propertyName.equals(IDEInternalPreferences.USE_MARKER_LIMITS)
                        || propertyName.equals(IDEInternalPreferences.MARKER_LIMITS_VALUE)) {
                    viewer.refresh();
                    updateTitle();
                }
            }
        };
        IDEWorkbenchPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(preferenceListener);
    }

    /**
     * Add all concrete {@link MarkerItem} elements associated with the receiver
     * to allMarkers.
     * 
     * @param markerItem
     * @param allMarkers
     */
    private void addAllConcreteItems(MarkerItem markerItem, Collection allMarkers) {
        if (markerItem.isConcrete()) {
            allMarkers.add(markerItem);
            return;
        }

        MarkerItem[] children = markerItem.getChildren();
        for (int i = 0; i < children.length; i++) {
            addAllConcreteItems(children[i], allMarkers);
        }

    }

    /**
     * Add the category to the list of expanded categories.
     * 
     * @param category
     */
    void addExpandedCategory(MarkerCategory category) {
        getCategoriesToExpand().add(category.getName());

    }

    /**
     * Add all of the markers in markerItem recursively.
     * 
     * @param markerItem
     * @param allMarkers
     *            {@link Collection} of {@link IMarker}
     */
    private void addMarkers(MarkerItem markerItem, Collection allMarkers) {
        if (markerItem.getMarker() != null)
            allMarkers.add(markerItem.getMarker());
        MarkerItem[] children = markerItem.getChildren();
        for (int i = 0; i < children.length; i++) {
            addMarkers(children[i], allMarkers);

        }

    }

    /**
     * Create the columns for the receiver.
     * 
     * @param currentColumns
     *            the columns to refresh
     */
    private void createColumns(TreeColumn[] currentColumns) {

        Tree tree = viewer.getTree();
        TableLayout layout = new TableLayout();

        MarkerField[] fields = builder.getVisibleFields();

        for (int i = 0; i < fields.length; i++) {
            MarkerField markerField = fields[i];

            // Take into account the expansion indicator
            int columnWidth = markerField.getDefaultColumnWidth(tree);

            if (i == 0) {
                // Compute and store a font metric
                GC gc = new GC(tree);
                gc.setFont(tree.getFont());
                FontMetrics fontMetrics = gc.getFontMetrics();
                gc.dispose();
                columnWidth = Math.max(columnWidth, fontMetrics.getAverageCharWidth() * 5);
            }

            layout.addColumnData(new ColumnPixelData(columnWidth, true, true));
            TreeViewerColumn column;
            if (i < currentColumns.length)
                column = new TreeViewerColumn(viewer, currentColumns[i]);
            else {
                column = new TreeViewerColumn(viewer, SWT.NONE);
                column.getColumn().setResizable(true);
                column.getColumn().setMoveable(true);
                column.getColumn().addSelectionListener(getHeaderListener());
            }

            column.getColumn().setData(MARKER_FIELD, markerField);
            // Show the help in the first column
            column.setLabelProvider(new MarkerColumnLabelProvider(markerField, i == 0));
            column.getColumn().setText(markerField.getColumnHeaderText());
            column.getColumn().setToolTipText(markerField.getColumnTooltipText());
            column.getColumn().setImage(markerField.getColumnHeaderImage());

            EditingSupport support = markerField.getEditingSupport(viewer);
            if (support != null)
                column.setEditingSupport(support);

            if (builder.getPrimarySortField().equals(markerField))
                updateDirectionIndicator(column.getColumn(), markerField);

        }

        // Remove extra columns
        if (currentColumns.length > fields.length) {
            for (int i = fields.length; i < currentColumns.length; i++) {
                currentColumns[i].dispose();

            }
        }

        viewer.getTree().setLayout(layout);
        tree.setLinesVisible(true);
        tree.setHeaderVisible(true);
        tree.layout(true);

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
     */
    public void createPartControl(Composite parent) {
        parent.setLayout(new FillLayout());

        viewer = new MarkersTreeViewer(
                new Tree(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION));
        viewer.getTree().setLinesVisible(true);
        viewer.setUseHashlookup(true);

        createColumns(new TreeColumn[0]);

        viewer.setContentProvider(getContentProvider());
        getSite().setSelectionProvider(viewer);

        viewer.setInput(builder);
        if (memento != null) {
            Scrollable scrollable = (Scrollable) viewer.getControl();
            ScrollBar bar = scrollable.getVerticalBar();
            if (bar != null) {
                Integer position = memento.getInteger(TAG_VERTICAL_POSITION);
                if (position != null)
                    bar.setSelection(position.intValue());
            }
            bar = scrollable.getHorizontalBar();
            if (bar != null) {
                Integer position = memento.getInteger(TAG_HORIZONTAL_POSITION);
                if (position != null)
                    bar.setSelection(position.intValue());
            }
        }

        // Initialise any selection based filtering
        pageSelectionListener = getPageSelectionListener();
        getSite().getPage().addPostSelectionListener(pageSelectionListener);

        partListener = getPartListener();
        getSite().getPage().addPartListener(partListener);

        pageSelectionListener.selectionChanged(getSite().getPage().getActivePart(),
                getSite().getPage().getSelection());

        viewer.addOpenListener(new IOpenListener() {
            public void open(OpenEvent event) {
                openSelectedMarkers();
            }

        });

        viewer.getTree().addTreeListener(new TreeAdapter() {
            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.TreeAdapter#treeCollapsed(org.eclipse.swt.events.TreeEvent)
             */
            public void treeCollapsed(TreeEvent e) {
                removeExpandedCategory((MarkerCategory) e.item.getData());
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.TreeAdapter#treeExpanded(org.eclipse.swt.events.TreeEvent)
             */
            public void treeExpanded(TreeEvent e) {
                addExpandedCategory((MarkerCategory) e.item.getData());
            }
        });

        // Set help on the view itself
        viewer.getControl().addHelpListener(new HelpListener() {
            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.swt.events.HelpListener#helpRequested(org.eclipse.swt.events.HelpEvent)
             */
            public void helpRequested(HelpEvent e) {
                Object provider = getAdapter(IContextProvider.class);
                if (provider == null)
                    return;

                IContext context = ((IContextProvider) provider).getContext(viewer.getControl());
                PlatformUI.getWorkbench().getHelpSystem().displayHelp(context);
            }

        });

        registerContextMenu();

    }

    /**
     * Return a part listener for the receiver.
     * 
     * @return IPartListener2
     */
    private IPartListener2 getPartListener() {
        return new IPartListener2() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.IPartListener2#partActivated(org.eclipse.ui.IWorkbenchPartReference)
             */
            public void partActivated(IWorkbenchPartReference partRef) {
                // Do nothing by default

            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.IPartListener2#partBroughtToTop(org.eclipse.ui.IWorkbenchPartReference)
             */
            public void partBroughtToTop(IWorkbenchPartReference partRef) {
                // Do nothing by default

            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.IPartListener2#partClosed(org.eclipse.ui.IWorkbenchPartReference)
             */
            public void partClosed(IWorkbenchPartReference partRef) {
                // Do nothing by default

            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.IPartListener2#partDeactivated(org.eclipse.ui.IWorkbenchPartReference)
             */
            public void partDeactivated(IWorkbenchPartReference partRef) {
                // Do nothing by default

            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.IPartListener2#partHidden(org.eclipse.ui.IWorkbenchPartReference)
             */
            public void partHidden(IWorkbenchPartReference partRef) {
                // Do nothing by default

            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.IPartListener2#partInputChanged(org.eclipse.ui.IWorkbenchPartReference)
             */
            public void partInputChanged(IWorkbenchPartReference partRef) {
                // Do nothing by default

            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.IPartListener2#partOpened(org.eclipse.ui.IWorkbenchPartReference)
             */
            public void partOpened(IWorkbenchPartReference partRef) {
                // Do nothing by default

            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.IPartListener2#partVisible(org.eclipse.ui.IWorkbenchPartReference)
             */
            public void partVisible(IWorkbenchPartReference partRef) {
                if (partRef.getId().equals(ExtendedMarkersView.this.getSite().getId())) {
                    pageSelectionListener.selectionChanged(getSite().getPage().getActivePart(),
                            getSite().getPage().getSelection());
                }

            }

        };
    }

    public void dispose() {
        super.dispose();
        updateJob.cancel();
        instanceCount--;
        if (clipboard != null)
            clipboard.dispose();
        IDEWorkbenchPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(preferenceListener);
        getSite().getPage().removePostSelectionListener(pageSelectionListener);
        getSite().getPage().removePartListener(partListener);
    }

    /**
     * Return all of the marker items in the receiver that are concrete.
     * 
     * @return MarkerItem[]
     */
    MarkerItem[] getAllConcreteItems() {

        MarkerItem[] elements = builder.getElements();
        Collection allMarkers = new ArrayList();
        for (int i = 0; i < elements.length; i++) {
            addAllConcreteItems(elements[i], allMarkers);

        }
        MarkerItem[] markers = new MarkerItem[allMarkers.size()];
        allMarkers.toArray(markers);
        return markers;
    }

    /**
     * Get all of the filters for the receiver.
     * 
     * @return Collection of {@link MarkerFieldFilterGroup}
     */
    Collection getAllFilters() {
        return builder.getAllFilters();
    }

    /**
     * Return all of the markers in the receiver.
     * 
     * @return IMarker[]
     */
    IMarker[] getAllMarkers() {

        MarkerItem[] elements = builder.getElements();
        Collection allMarkers = new ArrayList();
        for (int i = 0; i < elements.length; i++) {
            addMarkers(elements[i], allMarkers);

        }
        IMarker[] markers = new IMarker[allMarkers.size()];
        allMarkers.toArray(markers);
        return markers;

    }

    /**
     * Return the group used for categorisation.
     * 
     * @return MarkerGroup
     */
    MarkerGroup getCategoryGroup() {
        return builder.getCategoryGroup();
    }

    /**
     * Return the clipboard for the receiver.
     * 
     * @return Clipboard
     */
    Clipboard getClipboard() {
        if (clipboard == null)
            clipboard = new Clipboard(viewer.getControl().getDisplay());
        return clipboard;
    }

    /**
     * Return the content provider for the receiver.
     * 
     * @return ITreeContentProvider
     * 
     */
    private ITreeContentProvider getContentProvider() {
        return new ITreeContentProvider() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.IContentProvider#dispose()
             */
            public void dispose() {

            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateChildCount(java.lang.Object,
             *      int)
             */
            // public void updateChildCount(Object element, int
            // currentChildCount) {
            //
            // int length;
            // if (element instanceof MarkerItem)
            // length = ((MarkerItem) element).getChildren().length;
            // else
            // // If it is not a MarkerItem it is the root
            // length = ((CachedMarkerBuilder) element).getElements().length;
            //
            // int markerLimit = MarkerSupportInternalUtilities
            // .getMarkerLimit();
            // length = markerLimit > 0 ? Math.min(length, markerLimit)
            // : length;
            // if (currentChildCount == length)
            // return;
            // viewer.setChildCount(element, length);
            //
            // }
            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#updateElement(java.lang.Object,
             *      int)
             */
            // public void updateElement(Object parent, int index) {
            // MarkerItem newItem;
            //
            // if (parent instanceof MarkerItem)
            // newItem = ((MarkerItem) parent).getChildren()[index];
            // else
            // newItem = ((CachedMarkerBuilder) parent).getElements()[index];
            //
            // viewer.replace(parent, index, newItem);
            // updateChildCount(newItem, -1);
            //
            // if (!newItem.isConcrete()
            // && categoriesToExpand
            // .contains(((MarkerCategory) newItem).getName())) {
            // viewer.expandToLevel(newItem, 1);
            // categoriesToExpand.remove(newItem);
            // }
            //
            // }
            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
             */
            public Object[] getChildren(Object parentElement) {
                MarkerItem[] children = ((MarkerItem) parentElement).getChildren();

                return getLimitedChildren(children);
            }

            /**
             * Get the children limited by the marker limits.
             * 
             * @param children
             * @return Object[]
             */
            private Object[] getLimitedChildren(Object[] children) {
                int newLength = MarkerSupportInternalUtilities.getMarkerLimit();
                if (newLength > 0 && newLength < children.length) {
                    Object[] newChildren = new Object[newLength];
                    System.arraycopy(children, 0, newChildren, 0, newLength);
                    return newChildren;
                }
                return children;
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
             */
            public Object[] getElements(Object inputElement) {

                return getLimitedChildren(((CachedMarkerBuilder) inputElement).getElements());
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.ILazyTreeContentProvider#getParent(java.lang.Object)
             */
            public Object getParent(Object element) {
                Object parent = ((MarkerItem) element).getParent();
                if (parent == null)
                    return builder;
                return parent;
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
             */
            public boolean hasChildren(Object element) {
                return ((MarkerItem) element).getChildren().length > 0;
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
             *      java.lang.Object, java.lang.Object)
             */
            public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {

            }
        };
    }

    /**
     * Return the listener that updates sort values on selection.
     * 
     * @return SelectionListener
     */
    private SelectionListener getHeaderListener() {

        return new SelectionAdapter() {
            /**
             * Handles the case of user selecting the header area.
             */
            public void widgetSelected(SelectionEvent e) {

                final TreeColumn column = (TreeColumn) e.widget;
                final MarkerField field = (MarkerField) column.getData(MARKER_FIELD);
                setPrimarySortField(field, column);
            }

        };

    }

    /**
     * Return the selection listener for the page selection change.
     * 
     * @return ISelectionListener
     */
    private ISelectionListener getPageSelectionListener() {
        return new ISelectionListener() {
            /**
             * Get an ITaskListResourceAdapter for use by the default/
             * 
             * @return ITaskListResourceAdapter
             */
            private ITaskListResourceAdapter getDefaultTaskListAdapter() {
                return new ITaskListResourceAdapter() {

                    /*
                     * (non-Javadoc)
                     * 
                     * @see org.eclipse.ui.views.tasklist.ITaskListResourceAdapter#getAffectedResource(org.eclipse.core.runtime.IAdaptable)
                     */
                    public IResource getAffectedResource(IAdaptable adaptable) {
                        Object resource = adaptable.getAdapter(IResource.class);
                        if (resource == null)
                            resource = adaptable.getAdapter(IFile.class);
                        if (resource == null)
                            return null;
                        return (IResource) resource;

                    }

                };
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart,
             *      org.eclipse.jface.viewers.ISelection)
             */
            public void selectionChanged(IWorkbenchPart part, ISelection selection) {

                // Do not respond to our own selections or if we are not
                // visible
                if (part == ExtendedMarkersView.this || !(getSite().getPage().isPartVisible(part)))
                    return;

                List selectedElements = new ArrayList();
                if (part instanceof IEditorPart) {
                    IEditorPart editor = (IEditorPart) part;
                    IFile file = ResourceUtil.getFile(editor.getEditorInput());
                    if (file == null) {
                        IEditorInput editorInput = editor.getEditorInput();
                        if (editorInput != null) {
                            Object mapping = editorInput.getAdapter(ResourceMapping.class);
                            if (mapping != null) {
                                selectedElements.add(mapping);
                            }
                        }
                    } else {
                        selectedElements.add(file);
                    }
                } else {
                    if (selection instanceof IStructuredSelection) {
                        for (Iterator iterator = ((IStructuredSelection) selection).iterator(); iterator
                                .hasNext();) {
                            Object object = iterator.next();
                            if (object instanceof IAdaptable) {
                                ITaskListResourceAdapter taskListResourceAdapter;
                                Object adapter = ((IAdaptable) object).getAdapter(ITaskListResourceAdapter.class);
                                if (adapter != null && adapter instanceof ITaskListResourceAdapter) {
                                    taskListResourceAdapter = (ITaskListResourceAdapter) adapter;
                                } else {
                                    taskListResourceAdapter = getDefaultTaskListAdapter();
                                }

                                IResource resource = taskListResourceAdapter
                                        .getAffectedResource((IAdaptable) object);
                                if (resource == null) {
                                    Object mapping = ((IAdaptable) object).getAdapter(ResourceMapping.class);
                                    if (mapping != null) {
                                        selectedElements.add(mapping);
                                    }
                                } else {
                                    selectedElements.add(resource);
                                }
                            }
                        }
                    }
                }
                builder.updateForNewSelection(selectedElements.toArray());
            }

        };
    }

    /**
     * Return all of the markers in the current selection
     * 
     * @return Array of {@link IMarker}
     */
    public IMarker[] getSelectedMarkers() {
        ISelection selection = viewer.getSelection();
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection structured = (IStructuredSelection) selection;
            Iterator elements = structured.iterator();
            Collection result = new ArrayList();
            while (elements.hasNext()) {
                MarkerItem next = (MarkerItem) elements.next();
                if (next.isConcrete())
                    result.add(((MarkerEntry) next).getMarker());
            }
            if (result.isEmpty())
                return MarkerSupportInternalUtilities.EMPTY_MARKER_ARRAY;
            IMarker[] markers = new IMarker[result.size()];
            result.toArray(markers);
            return markers;
        }
        return MarkerSupportInternalUtilities.EMPTY_MARKER_ARRAY;

    }

    /**
     * Return the sort direction.
     * 
     * @return boolean
     */
    public boolean getSortAscending() {
        return viewer.getTree().getSortDirection() == SWT.TOP;
    }

    /**
     * Return a job for updating the receiver.
     * 
     * @return Job
     */
    private Job getUpdateJob(final CachedMarkerBuilder builder) {
        updateJob = new WorkbenchJob(MarkerMessages.MarkerView_queueing_updates) {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object)
             */
            public boolean belongsTo(Object family) {
                return family == MarkerContentGenerator.CACHE_UPDATE_FAMILY;
            }

            /**
             * Return the viewer that is being updated.
             * 
             * @return TreeViewer
             */
            private TreeViewer getViewer() {

                return viewer;
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
             */
            public IStatus runInUIThread(IProgressMonitor monitor) {

                if (viewer.getControl().isDisposed()) {
                    return Status.CANCEL_STATUS;
                }

                if (monitor.isCanceled())
                    return Status.CANCEL_STATUS;

                // If there is only one category and the user has no saved state
                // show it
                if (builder.isShowingHierarchy() && getCategoriesToExpand().isEmpty()) {
                    MarkerCategory[] categories = builder.getCategories();
                    if (categories != null && categories.length == 1)
                        getCategoriesToExpand().add(categories[0].getName());
                }

                getViewer().refresh(true);
                updateTitle();

                if (preservedSelection.size() > 0) {

                    Collection newSelection = new ArrayList();
                    MarkerItem[] markerEntries = builder.getMarkerEntries();

                    for (int i = 0; i < markerEntries.length; i++) {
                        Iterator preserved = preservedSelection.iterator();
                        while (preserved.hasNext()) {
                            MarkerSelectionEntry next = (MarkerSelectionEntry) preserved.next();
                            if (next.isEquivalentTo(markerEntries[i])) {
                                newSelection.add(markerEntries[i]);
                                continue;
                            }
                        }
                    }

                    getViewer().setSelection(new StructuredSelection(newSelection.toArray()), true);
                    preservedSelection.clear();
                }
                if (getViewer().getTree().getItemCount() > 0)
                    getViewer().getTree().setTopItem(getViewer().getTree().getItem(0));

                reexpandCategories(builder);
                return Status.OK_STATUS;
            }

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.ui.progress.WorkbenchJob#shouldRun()
             */
            public boolean shouldRun() {
                return !builder.isBuilding();
            }

        };

        updateJob.setSystem(true);
        return updateJob;
    }

    /**
     * Return the object that is the input to the viewer.
     * 
     * @return Object
     */
    Object getViewerInput() {
        return viewer.getInput();
    }

    /**
     * Get all of the fields visible in the receiver.
     * 
     * @return MarkerField[]
     */
    MarkerField[] getVisibleFields() {
        return builder.getVisibleFields();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite,
     *      org.eclipse.ui.IMemento)
     */
    public void init(IViewSite site, IMemento memento) throws PartInitException {
        super.init(site, memento);
        MarkerContentGenerator generator = null;

        if (memento != null) {
            generator = MarkerSupportRegistry.getInstance().getGenerator(memento.getString(TAG_GENERATOR));
        }

        if (generator == null && defaultGeneratorIds.length > 0) {
            generator = MarkerSupportRegistry.getInstance().getGenerator(defaultGeneratorIds[0]);
            if (generator == null)
                logInvalidGenerator(defaultGeneratorIds[0]);
        }

        if (generator == null)
            generator = MarkerSupportRegistry.getInstance().getDefaultGenerator();

        // Add in the entries common to all markers views
        IMenuService menuService = (IMenuService) site.getService(IMenuService.class);

        // Add in the markers view actions

        menuService.populateContributionManager((ContributionManager) site.getActionBars().getMenuManager(), "menu:" //$NON-NLS-1$
                + MarkerSupportRegistry.MARKERS_ID);
        menuService.populateContributionManager((ContributionManager) site.getActionBars().getToolBarManager(),
                "toolbar:" + MarkerSupportRegistry.MARKERS_ID); //$NON-NLS-1$

        String viewId = site.getId();
        if (site.getSecondaryId() != null) {
            viewId = viewId + site.getSecondaryId();
        }
        builder = new CachedMarkerBuilder(generator, viewId, memento);

        builder.setUpdateJob(getUpdateJob(builder));
        Object service = site.getAdapter(IWorkbenchSiteProgressService.class);
        if (service != null)
            builder.setProgressService((IWorkbenchSiteProgressService) service);
        this.memento = memento;

        if (memento == null || memento.getString(TAG_PART_NAME) == null)
            return;

        setPartName(memento.getString(TAG_PART_NAME));
    }

    /**
     * Log that a generator id is invalid.
     * 
     * @param id
     */
    void logInvalidGenerator(String id) {
        StatusManager.getManager()
                .handle(new Status(IStatus.WARNING, IDEWorkbenchPlugin.IDE_WORKBENCH,
                        NLS.bind("Invalid markerContentGenerator {0} ", //$NON-NLS-1$
                                id)));
    }

    /**
     * Return whether or not group is enabled.
     * 
     * @param group
     * @return boolean
     */
    boolean isEnabled(MarkerFieldFilterGroup group) {
        return builder.getEnabledFilters().contains(group);
    }

    /**
     * Return the main sort field for the receiver.
     * 
     * @return {@link MarkerField}
     */
    boolean isPrimarySortField(MarkerField field) {
        return builder.getPrimarySortField().equals(field);
    }

    /**
     * Return whether or not generator is the selected one.
     * 
     * @param generator
     * @return boolean
     */
    boolean isShowing(MarkerContentGenerator generator) {
        return this.builder.getGenerator().equals(generator);
    }

    /**
     * Open the filters dialog for the receiver.
     */
    void openFiltersDialog() {
        FiltersConfigurationDialog dialog = new FiltersConfigurationDialog(
                new SameShellProvider(getSite().getWorkbenchWindow().getShell()), builder);
        if (dialog.open() == Window.OK) {
            builder.updateFrom(dialog);
        }

    }

    /**
     * Open the selected markers
     */
    void openSelectedMarkers() {
        IMarker[] markers = getSelectedMarkers();
        for (int i = 0; i < markers.length; i++) {
            IMarker marker = markers[i];
            IWorkbenchPage page = getSite().getPage();

            openMarkerInEditor(marker, page);
        }
    }

    /**
     * Register the context menu for the receiver so that commands may be added
     * to it.
     */
    private void registerContextMenu() {
        MenuManager contextMenu = new MenuManager();
        contextMenu.setRemoveAllWhenShown(true);
        getSite().registerContextMenu(contextMenu, viewer);
        // Add in the entries for all markers views if this has a different if
        if (!getSite().getId().equals(MarkerSupportRegistry.MARKERS_ID))
            getSite().registerContextMenu(MarkerSupportRegistry.MARKERS_ID, contextMenu, viewer);
        Control control = viewer.getControl();
        Menu menu = contextMenu.createContextMenu(control);

        control.setMenu(menu);
    }

    /**
     * Remove the category from the list of expanded ones.
     * 
     * @param category
     */
    void removeExpandedCategory(MarkerCategory category) {
        getCategoriesToExpand().remove(category.getName());

    }

    /**
     * Preserve the selection for re-selection after the next update.
     * 
     * @param selection
     */
    void saveSelection(ISelection selection) {
        preservedSelection.clear();
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection structured = (IStructuredSelection) selection;
            Iterator iterator = structured.iterator();
            while (iterator.hasNext()) {
                MarkerItem next = (MarkerItem) iterator.next();
                if (next.isConcrete()) {
                    preservedSelection.add(new MarkerSelectionEntry(next));
                    getCategoriesToExpand().add(next.getParent());
                } else
                    getCategoriesToExpand().add(next);
            }
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.ViewPart#saveState(org.eclipse.ui.IMemento)
     */
    public void saveState(IMemento memento) {
        super.saveState(memento);
        memento.putString(TAG_GENERATOR, builder.getGenerator().getId());
        memento.putString(TAG_PART_NAME, getPartName());

        if (!getCategoriesToExpand().isEmpty()) {
            IMemento expanded = memento.createChild(TAG_EXPANDED);
            Iterator categories = getCategoriesToExpand().iterator();
            while (categories.hasNext()) {
                expanded.createChild(TAG_CATEGORY, (String) categories.next());
            }
        }
        builder.saveState(memento);
    }

    /**
     * Select all of the elements in the receiver.
     */
    void selectAll() {
        viewer.getTree().selectAll();

    }

    /**
     * Set the category group for the receiver.
     * 
     * @param group
     */
    void setCategoryGroup(MarkerGroup group) {
        getCategoriesToExpand().clear();
        builder.setCategoryGroup(group);
    }

    /**
     * Set the content generator for the receiver.
     * 
     * @param generator
     */
    void setContentGenerator(MarkerContentGenerator generator) {
        viewer.setSelection(new StructuredSelection());
        viewer.removeAndClearAll();
        builder.setGenerator(generator);
        createColumns(viewer.getTree().getColumns());

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
     */
    public void setFocus() {
        viewer.getControl().setFocus();

    }

    /**
     * Set the primary sort field
     * 
     * @param field
     */
    void setPrimarySortField(MarkerField field) {
        TreeColumn[] columns = viewer.getTree().getColumns();
        for (int i = 0; i < columns.length; i++) {
            TreeColumn treeColumn = columns[i];
            if (columns[i].getData(MARKER_FIELD).equals(field)) {
                setPrimarySortField(field, treeColumn);
                return;
            }
        }
        StatusManager.getManager().handle(StatusUtil.newStatus(IStatus.WARNING, "Sorting by non visible field " //$NON-NLS-1$
                + field.getColumnHeaderText(), null));
    }

    /**
     * Set the primary sort field to field and update the column.
     * 
     * @param field
     * @param column
     */
    private void setPrimarySortField(MarkerField field, TreeColumn column) {
        builder.setPrimarySortField(field);

        IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) getViewSite()
                .getAdapter(IWorkbenchSiteProgressService.class);
        builder.refreshContents(service);
        updateDirectionIndicator(column, field);
        viewer.refresh();
        reexpandCategories(builder);
    }

    /**
     * Add group to the enabled filters.
     * 
     * @param group
     */
    void toggleFilter(MarkerFieldFilterGroup group) {
        builder.toggleFilter(group);

    }

    /**
     * Toggle the sort direction of the primary field
     */
    void toggleSortDirection() {
        setPrimarySortField(builder.getPrimarySortField());

    }

    /**
     * Update the direction indicator as column is now the primary column.
     * 
     * @param column
     * @field {@link MarkerField}
     */
    void updateDirectionIndicator(TreeColumn column, MarkerField field) {
        viewer.getTree().setSortColumn(column);
        if (builder.getSortDirection(field) == MarkerComparator.ASCENDING)
            viewer.getTree().setSortDirection(SWT.UP);
        else
            viewer.getTree().setSortDirection(SWT.DOWN);
    }

    /**
     * Update the title of the view.
     */
    void updateTitle() {

        String status = MarkerSupportConstants.EMPTY_STRING;
        int totalCount = builder.getTotalMarkerCount();
        int filteredCount = 0;
        MarkerCategory[] categories = builder.getCategories();
        // Categories might be null if building is still happening
        if (categories != null && builder.isShowingHierarchy()) {
            int markerLimit = MarkerSupportInternalUtilities.getMarkerLimit();

            for (int i = 0; i < categories.length; i++) {
                filteredCount += markerLimit < 0 ? categories[i].getTotalSize()
                        : Math.min(categories[i].getTotalSize(), markerLimit);
            }
        } else {
            filteredCount = MarkerSupportInternalUtilities.getMarkerLimit();
        }
        if (filteredCount < 0 || filteredCount >= totalCount) {
            status = NLS.bind(MarkerMessages.filter_itemsMessage, new Integer(totalCount));
        } else {
            status = NLS.bind(MarkerMessages.filter_matchedMessage, new Integer(filteredCount),
                    new Integer(totalCount));
        }

        setContentDescription(status);

    }

    /**
     * Set the selection of the receiver. reveal the item if reveal is true.
     * 
     * @param structuredSelection
     * @param reveal
     */
    void setSelection(StructuredSelection structuredSelection, boolean reveal) {

        List newSelection = new ArrayList(structuredSelection.size());

        for (Iterator i = structuredSelection.iterator(); i.hasNext();) {
            Object next = i.next();
            if (next instanceof IMarker) {
                MarkerItem marker = builder.getMarkerItem((IMarker) next);
                if (marker != null) {
                    newSelection.add(marker);
                }
            }
        }

        viewer.setSelection(new StructuredSelection(newSelection), reveal);

    }

    /**
     * Return the ids of the generators specified for the receiver.
     * 
     * @return String[]
     */
    String[] getGeneratorIds() {
        return defaultGeneratorIds;
    }

    /**
     * Turn off all filters in the builder.
     */
    void disableAllFilters() {
        builder.disableAllFilters();

    }

    /**
     * Return the builder for the receiver.
     * 
     * @return CachedMarkerBuilder
     */
    CachedMarkerBuilder getBuilder() {
        return builder;
    }

    /**
     * Get the categories to expand for the receiver.
     * 
     * @return Collection of MarkerCategory.
     */
    private Collection getCategoriesToExpand() {
        if (categoriesToExpand == null) {
            categoriesToExpand = new HashSet();
            if (this.memento != null) {
                IMemento expanded = this.memento.getChild(TAG_EXPANDED);
                if (expanded != null) {
                    IMemento[] mementoCategories = expanded.getChildren(TAG_CATEGORY);
                    MarkerCategory[] markerCategories = builder.getCategories();
                    if (markerCategories != null) {
                        for (int i = 0; i < markerCategories.length; i++) {
                            for (int j = 0; j < mementoCategories.length; j++) {
                                if (markerCategories[i].getName().equals(mementoCategories[j].getID()))
                                    categoriesToExpand.add(markerCategories[i].getName());
                            }
                        }
                    }
                }
            }
        }
        return categoriesToExpand;
    }

    /**
     * Restore the expanded categories.
     * 
     * @param builder
     */
    void reexpandCategories(final CachedMarkerBuilder builder) {
        if (!getCategoriesToExpand().isEmpty() && builder.isShowingHierarchy()) {
            MarkerItem[] items = builder.getElements();
            for (int i = 0; i < items.length; i++) {
                String name = ((MarkerCategory) items[i]).getName();
                if (getCategoriesToExpand().contains(name))
                    viewer.expandToLevel(items[i], 2);

            }
        }
    }

    /**
     * Initialize the title based on the count
     * 
     * @param count
     */
    void initializeTitle(String count) {
        setPartName(NLS.bind(MarkerMessages.newViewTitle, new Object[] { getPartName(), count }));

    }
}