org.eclipse.team.internal.ui.history.LocalHistoryPage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.team.internal.ui.history.LocalHistoryPage.java

Source

/*******************************************************************************
 * Copyright (c) 2006, 2011 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.team.internal.ui.history;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.structuremergeviewer.DiffNode;
import org.eclipse.compare.structuremergeviewer.ICompareInput;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.*;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.OpenStrategy;
import org.eclipse.jface.viewers.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.TeamStatus;
import org.eclipse.team.core.history.IFileHistory;
import org.eclipse.team.core.history.IFileRevision;
import org.eclipse.team.internal.core.history.LocalFileHistory;
import org.eclipse.team.internal.core.history.LocalFileRevision;
import org.eclipse.team.internal.ui.*;
import org.eclipse.team.internal.ui.actions.*;
import org.eclipse.team.internal.ui.synchronize.LocalResourceTypedElement;
import org.eclipse.team.ui.history.*;
import org.eclipse.team.ui.synchronize.SaveableCompareEditorInput;
import org.eclipse.ui.*;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.progress.IProgressConstants;

import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.util.Calendar;

public class LocalHistoryPage extends HistoryPage implements IHistoryCompareAdapter {

    public static final int ON = 1;
    public static final int OFF = 2;
    public static final int ALWAYS = 4;

    /* private */ IFile file;
    /* private */ IFileRevision currentFileRevision;

    // cached for efficiency
    /* private */ LocalFileHistory localFileHistory;

    /* private */ TreeViewer treeViewer;

    /* private */boolean shutdown = false;

    //grouping on
    private boolean groupingOn = true;

    //toggle constants for default click action
    private int compareMode = OFF;

    protected LocalFileHistoryTableProvider historyTableProvider;
    private RefreshFileHistory refreshFileHistoryJob;
    private Composite localComposite;
    private Action groupByDateMode;
    private Action collapseAll;
    private Action compareModeAction;
    private Action getContentsAction;
    private CompareRevisionAction compareAction;
    private OpenRevisionAction openAction;
    private OpenWithMenu openWithMenu;

    private HistoryResourceListener resourceListener;

    private IFileRevision currentSelection;

    private final class LocalHistoryContentProvider implements ITreeContentProvider {
        public Object[] getElements(Object inputElement) {
            if (inputElement instanceof IFileHistory) {
                // The entries of already been fetch so return them
                IFileHistory fileHistory = (IFileHistory) inputElement;
                return fileHistory.getFileRevisions();
            }
            if (inputElement instanceof IFileRevision[]) {
                return (IFileRevision[]) inputElement;
            }
            if (inputElement instanceof AbstractHistoryCategory[]) {
                return (AbstractHistoryCategory[]) inputElement;
            }
            return new Object[0];
        }

        public void dispose() {
            // Nothing to do
        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
            // Nothing to do
        }

        public Object[] getChildren(Object parentElement) {
            if (parentElement instanceof AbstractHistoryCategory) {
                return ((AbstractHistoryCategory) parentElement).getRevisions();
            }

            return new Object[0];
        }

        public Object getParent(Object element) {
            return null;
        }

        public boolean hasChildren(Object element) {
            if (element instanceof AbstractHistoryCategory) {
                return ((AbstractHistoryCategory) element).hasRevisions();
            }
            return false;
        }
    }

    private class LocalFileHistoryTableProvider extends LocalHistoryTableProvider {
        protected IFileRevision adaptToFileRevision(Object element) {
            // Get the log entry for the provided object
            IFileRevision entry = null;
            if (element instanceof IFileRevision) {
                entry = (IFileRevision) element;
            } else if (element instanceof IAdaptable) {
                entry = (IFileRevision) ((IAdaptable) element).getAdapter(IFileRevision.class);
            } else if (element instanceof AbstractHistoryCategory) {
                IFileRevision[] revisions = ((AbstractHistoryCategory) element).getRevisions();
                if (revisions.length > 0)
                    entry = revisions[0];
            }
            return entry;
        }

        private long getCurrentRevision() {
            if (file != null) {
                return file.getLocalTimeStamp();
            }
            return -1;
        }

        protected long getModificationDate(Object element) {
            IFileRevision entry = adaptToFileRevision(element);
            if (entry != null)
                return entry.getTimestamp();
            return -1;
        }

        protected boolean isCurrentEdition(Object element) {
            IFileRevision entry = adaptToFileRevision(element);
            if (entry == null)
                return false;
            long timestamp = entry.getTimestamp();
            long tempCurrentTimeStamp = getCurrentRevision();
            return (tempCurrentTimeStamp != -1 && tempCurrentTimeStamp == timestamp);
        }

        protected boolean isDeletedEdition(Object element) {
            IFileRevision entry = adaptToFileRevision(element);
            return (!entry.exists());
        }
    }

    private class RefreshFileHistory extends Job {
        public RefreshFileHistory() {
            super(TeamUIMessages.LocalHistoryPage_FetchLocalHistoryMessage);
        }

        public IStatus run(IProgressMonitor monitor) {
            try {
                IStatus status = Status.OK_STATUS;
                // Assign the instance variable to a local so it does not get cleared well we are refreshing
                LocalFileHistory fileHistory = localFileHistory;
                if (fileHistory == null || shutdown)
                    return status;
                try {
                    fileHistory.refresh(Policy.subMonitorFor(monitor, 50));
                } catch (CoreException ex) {
                    status = new TeamStatus(ex.getStatus().getSeverity(), TeamUIPlugin.ID, ex.getStatus().getCode(),
                            ex.getMessage(), ex, file);
                }

                update(fileHistory.getFileRevisions(), Policy.subMonitorFor(monitor, 50));

                if (status != Status.OK_STATUS) {
                    this.setProperty(IProgressConstants.KEEP_PROPERTY, Boolean.TRUE);
                    this.setProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY, Boolean.TRUE);
                }

                if (Policy.DEBUG_HISTORY) {
                    String time = new SimpleDateFormat("m:ss.SSS").format(new Date(System.currentTimeMillis())); //$NON-NLS-1$
                    System.out.println(time + ": RefreshFileHistoryJob#run finished, status: " + status); //$NON-NLS-1$
                }

                return status;
            } finally {
                monitor.done();
            }
        }
    }

    private class HistoryResourceListener implements IResourceChangeListener {
        public void resourceChanged(IResourceChangeEvent event) {
            IResourceDelta root = event.getDelta();

            if (file == null)
                return;

            IResourceDelta resourceDelta = root.findMember(file.getFullPath());
            if (resourceDelta != null) {
                Display.getDefault().asyncExec(new Runnable() {
                    public void run() {
                        refresh();
                    }
                });
            }
        }
    }

    public LocalHistoryPage(int compareMode) {
        super();
        this.compareMode = compareMode;
    }

    public LocalHistoryPage() {
        super();
    }

    public boolean inputSet() {
        currentFileRevision = null;
        IFile tempFile = getFile();
        this.file = tempFile;
        if (tempFile == null)
            return false;

        //blank current input only after we're sure that we have a file
        //to fetch history for
        this.treeViewer.setInput(null);

        localFileHistory = new LocalFileHistory(file, !getHistoryPageSite().isModal());

        if (refreshFileHistoryJob == null)
            refreshFileHistoryJob = new RefreshFileHistory();

        //always refresh the history if the input gets set
        refreshHistory(true);
        return true;
    }

    protected IFile getFile() {
        return LocalHistoryPageSource.getFile(getInput());
    }

    private void refreshHistory(boolean refetch) {
        if (Policy.DEBUG_HISTORY) {
            String time = new SimpleDateFormat("m:ss.SSS").format(new Date(System.currentTimeMillis())); //$NON-NLS-1$
            System.out.println(time + ": LocalHistoryPage#refreshHistory, refetch = " + refetch); //$NON-NLS-1$
        }

        if (refreshFileHistoryJob.getState() != Job.NONE) {
            refreshFileHistoryJob.cancel();
        }
        IHistoryPageSite parentSite = getHistoryPageSite();
        Utils.schedule(refreshFileHistoryJob, getWorkbenchSite(parentSite));
    }

    private IWorkbenchPartSite getWorkbenchSite(IHistoryPageSite parentSite) {
        IWorkbenchPart part = parentSite.getPart();
        if (part != null)
            return part.getSite();
        return null;
    }

    public void createControl(Composite parent) {

        localComposite = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginHeight = 0;
        layout.marginWidth = 0;
        localComposite.setLayout(layout);
        GridData data = new GridData(GridData.FILL_BOTH);
        data.grabExcessVerticalSpace = true;
        localComposite.setLayoutData(data);

        treeViewer = createTree(localComposite);

        contributeActions();

        IHistoryPageSite parentSite = getHistoryPageSite();
        if (parentSite != null && parentSite instanceof DialogHistoryPageSite && treeViewer != null)
            parentSite.setSelectionProvider(treeViewer);

        resourceListener = new HistoryResourceListener();
        ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceListener,
                IResourceChangeEvent.POST_CHANGE);

        PlatformUI.getWorkbench().getHelpSystem().setHelp(localComposite, IHelpContextIds.LOCAL_HISTORY_PAGE);
    }

    private void contributeActions() {
        final IPreferenceStore store = TeamUIPlugin.getPlugin().getPreferenceStore();
        //Group by Date
        groupByDateMode = new Action(TeamUIMessages.LocalHistoryPage_GroupRevisionsByDateAction,
                TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_DATES_CATEGORY)) {
            public void run() {
                groupingOn = !groupingOn;
                store.setValue(IPreferenceIds.PREF_GROUPBYDATE_MODE, groupingOn);
                refreshHistory(false);
            }
        };
        groupingOn = store.getBoolean(IPreferenceIds.PREF_GROUPBYDATE_MODE);
        groupByDateMode.setChecked(groupingOn);
        groupByDateMode.setToolTipText(TeamUIMessages.LocalHistoryPage_GroupRevisionsByDateTip);
        groupByDateMode
                .setDisabledImageDescriptor(TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_DATES_CATEGORY));
        groupByDateMode.setHoverImageDescriptor(TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_DATES_CATEGORY));

        //Collapse All
        collapseAll = new Action(TeamUIMessages.LocalHistoryPage_CollapseAllAction,
                TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_COLLAPSE_ALL)) {
            public void run() {
                treeViewer.collapseAll();
            }
        };
        collapseAll.setToolTipText(TeamUIMessages.LocalHistoryPage_CollapseAllTip);
        collapseAll.setDisabledImageDescriptor(TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_COLLAPSE_ALL));
        collapseAll.setHoverImageDescriptor(TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_COLLAPSE_ALL));

        IHistoryPageSite historyPageSite = getHistoryPageSite();
        if (!historyPageSite.isModal()) {
            //Compare Mode Action
            if ((compareMode & ALWAYS) == 0) {
                compareModeAction = new Action(TeamUIMessages.LocalHistoryPage_CompareModeAction,
                        TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_COMPARE_VIEW)) {
                    public void run() {
                        // switch the mode
                        compareMode = compareMode == ON ? OFF : ON;
                        compareModeAction.setChecked(compareMode == ON);
                    }
                };
                compareModeAction.setToolTipText(TeamUIMessages.LocalHistoryPage_CompareModeTip);
                compareModeAction.setDisabledImageDescriptor(
                        TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_COMPARE_VIEW));
                compareModeAction
                        .setHoverImageDescriptor(TeamUIPlugin.getImageDescriptor(ITeamUIImages.IMG_COMPARE_VIEW));
                compareModeAction.setChecked(compareMode == ON);

                getContentsAction = getContextMenuAction(TeamUIMessages.LocalHistoryPage_GetContents,
                        true /* needs progress */, new IWorkspaceRunnable() {
                            public void run(IProgressMonitor monitor) throws CoreException {
                                monitor.beginTask(null, 100);
                                try {
                                    if (confirmOverwrite()) {
                                        IStorage currentStorage = currentSelection
                                                .getStorage(new SubProgressMonitor(monitor, 50));
                                        InputStream in = currentStorage.getContents();
                                        (file).setContents(in, false, true, new SubProgressMonitor(monitor, 50));
                                    }
                                } catch (TeamException e) {
                                    throw new CoreException(e.getStatus());
                                } finally {
                                    monitor.done();
                                }
                            }
                        });
            }

            //TODO: Doc help
            //PlatformUI.getWorkbench().getHelpSystem().setHelp(getContentsAction, );

            // Click Compare action
            compareAction = createCompareAction();
            compareAction.setEnabled(!treeViewer.getSelection().isEmpty());
            treeViewer.getTree().addSelectionListener(new SelectionAdapter() {
                public void widgetSelected(SelectionEvent e) {
                    compareAction.setCurrentFileRevision(getCurrentFileRevision());
                    compareAction.selectionChanged((IStructuredSelection) treeViewer.getSelection());
                }
            });

            // Only add the open action if compare mode is not always on
            if (!((compareMode & (ALWAYS | ON)) == (ALWAYS | ON))) {
                openAction = new OpenRevisionAction(TeamUIMessages.LocalHistoryPage_OpenAction, this);
                openAction.setEnabled(!treeViewer.getSelection().isEmpty());
                treeViewer.getTree().addSelectionListener(new SelectionAdapter() {
                    public void widgetSelected(SelectionEvent e) {
                        openAction.selectionChanged((IStructuredSelection) treeViewer.getSelection());
                    }
                });

                // Add 'Open With...'  sub-menu
                openWithMenu = new OpenWithMenu(this);
                treeViewer.getTree().addSelectionListener(new SelectionAdapter() {
                    public void widgetSelected(SelectionEvent e) {
                        openWithMenu.selectionChanged((IStructuredSelection) treeViewer.getSelection());
                    }
                });
            }

            new OpenAndLinkWithEditorHelper(treeViewer) {
                protected void open(ISelection selection, boolean activate) {
                    if (getSite() != null && selection instanceof IStructuredSelection) {
                        IStructuredSelection structuredSelection = (IStructuredSelection) selection;
                        if ((compareMode & ON) > 0) {
                            StructuredSelection sel = new StructuredSelection(new Object[] {
                                    getCurrentFileRevision(), structuredSelection.getFirstElement() });
                            compareAction.selectionChanged(sel);
                            compareAction.run();
                        } else {
                            //Pass in the entire structured selection to allow for multiple editor openings
                            if (openAction != null) {
                                openAction.selectionChanged(structuredSelection);
                                openAction.run();
                            }
                        }
                    }
                }

                protected void activate(ISelection selection) {
                    int currentMode = OpenStrategy.getOpenMethod();
                    try {
                        OpenStrategy.setOpenMethod(OpenStrategy.DOUBLE_CLICK);
                        open(selection, true);
                    } finally {
                        OpenStrategy.setOpenMethod(currentMode);
                    }
                }

                protected void linkToEditor(ISelection selection) {
                    // XXX: Not yet implemented, see http://bugs.eclipse.org/324185
                }
            };

            //Contribute actions to popup menu
            MenuManager menuMgr = new MenuManager();
            Menu menu = menuMgr.createContextMenu(treeViewer.getTree());
            menuMgr.addMenuListener(new IMenuListener() {
                public void menuAboutToShow(IMenuManager menuMgr) {
                    fillTableMenu(menuMgr);
                }
            });
            menuMgr.setRemoveAllWhenShown(true);
            treeViewer.getTree().setMenu(menu);

            //Don't add the object contribution menu items if this page is hosted in a dialog
            IWorkbenchPart part = historyPageSite.getPart();
            if (part != null) {
                IWorkbenchPartSite workbenchPartSite = part.getSite();
                workbenchPartSite.registerContextMenu(menuMgr, treeViewer);
            }
            IPageSite pageSite = historyPageSite.getWorkbenchPageSite();
            if (pageSite != null) {
                IActionBars actionBars = pageSite.getActionBars();
                // Contribute toggle text visible to the toolbar drop-down
                IMenuManager actionBarsMenu = actionBars.getMenuManager();
                if (actionBarsMenu != null) {
                    actionBarsMenu.removeAll();
                }
                actionBars.updateActionBars();
            }
        }

        //Create the local tool bar
        IToolBarManager tbm = historyPageSite.getToolBarManager();
        if (tbm != null) {
            String fileNameQualifier = getFileNameQualifier();
            //Add groups
            tbm.add(new Separator(fileNameQualifier + "grouping")); //$NON-NLS-1$
            tbm.appendToGroup(fileNameQualifier + "grouping", groupByDateMode); //$NON-NLS-1$
            tbm.add(new Separator(fileNameQualifier + "collapse")); //$NON-NLS-1$
            tbm.appendToGroup(fileNameQualifier + "collapse", collapseAll); //$NON-NLS-1$
            if (compareModeAction != null)
                tbm.appendToGroup(fileNameQualifier + "collapse", compareModeAction); //$NON-NLS-1$
            tbm.update(false);
        }

    }

    protected CompareRevisionAction createCompareAction() {
        return new CompareRevisionAction(this);
    }

    private String getFileNameQualifier() {
        if (file != null)
            return file.getFullPath().toString();

        return ""; //$NON-NLS-1$
    }

    protected void fillTableMenu(IMenuManager manager) {
        // file actions go first (view file)
        IHistoryPageSite parentSite = getHistoryPageSite();
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));

        if (file != null && !parentSite.isModal()) {
            if (openAction != null)
                manager.add(openAction);
            if (openWithMenu != null) {
                MenuManager openWithSubmenu = new MenuManager(TeamUIMessages.LocalHistoryPage_OpenWithMenu);
                openWithSubmenu.add(openWithMenu);
                manager.add(openWithSubmenu);
            }
            if (compareAction != null)
                manager.add(compareAction);
            if (getContentsAction != null) {
                ISelection sel = treeViewer.getSelection();
                if (!sel.isEmpty()) {
                    if (sel instanceof IStructuredSelection) {
                        IStructuredSelection tempSelection = (IStructuredSelection) sel;
                        if (tempSelection.size() == 1) {
                            manager.add(new Separator("getContents")); //$NON-NLS-1$
                            manager.add(getContentsAction);
                        }
                    }
                }
            }
        }
    }

    /**
     * Creates the tree that displays the local file revisions
     * 
     * @param parent the parent composite to contain the group
     * @return the group control
     */
    protected TreeViewer createTree(Composite parent) {
        historyTableProvider = new LocalFileHistoryTableProvider();
        TreeViewer viewer = historyTableProvider.createTree(parent);
        viewer.setContentProvider(new LocalHistoryContentProvider());
        return viewer;
    }

    public Control getControl() {
        return localComposite;
    }

    public void setFocus() {
        localComposite.setFocus();
    }

    public String getDescription() {
        if (getFile() != null)
            return getFile().getFullPath().toString();
        return null;
    }

    public String getName() {
        if (getFile() != null)
            return getFile().getName();
        return ""; //$NON-NLS-1$
    }

    public boolean isValidInput(Object object) {
        return object instanceof IFile;
    }

    public void refresh() {
        refreshHistory(true);
    }

    public Object getAdapter(Class adapter) {
        if (adapter == IHistoryCompareAdapter.class) {
            return this;
        }
        return null;
    }

    public void dispose() {
        shutdown = true;

        if (resourceListener != null) {
            ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceListener);
            resourceListener = null;
        }

        //Cancel any incoming
        if (refreshFileHistoryJob != null) {
            if (refreshFileHistoryJob.getState() != Job.NONE) {
                refreshFileHistoryJob.cancel();
            }
        }
    }

    public IFileRevision getCurrentFileRevision() {
        if (currentFileRevision != null)
            return currentFileRevision;

        if (file != null)
            currentFileRevision = new LocalFileRevision(file);

        return currentFileRevision;
    }

    private Action getContextMenuAction(String title, final boolean needsProgressDialog,
            final IWorkspaceRunnable action) {
        return new Action(title) {
            public void run() {
                try {
                    if (file == null)
                        return;
                    ISelection selection = treeViewer.getSelection();
                    if (!(selection instanceof IStructuredSelection))
                        return;
                    IStructuredSelection ss = (IStructuredSelection) selection;
                    Object o = ss.getFirstElement();

                    if (o instanceof AbstractHistoryCategory)
                        return;

                    currentSelection = (IFileRevision) o;
                    if (needsProgressDialog) {
                        PlatformUI.getWorkbench().getProgressService().run(true, true, new IRunnableWithProgress() {
                            public void run(IProgressMonitor monitor)
                                    throws InvocationTargetException, InterruptedException {
                                try {
                                    action.run(monitor);
                                } catch (CoreException e) {
                                    throw new InvocationTargetException(e);
                                }
                            }
                        });
                    } else {
                        try {
                            action.run(null);
                        } catch (CoreException e) {
                            throw new InvocationTargetException(e);
                        }
                    }
                } catch (InvocationTargetException e) {
                    IHistoryPageSite parentSite = getHistoryPageSite();
                    Utils.handleError(parentSite.getShell(), e, null, null);
                } catch (InterruptedException e) {
                    // Do nothing
                }
            }

            public boolean isEnabled() {
                ISelection selection = treeViewer.getSelection();
                if (!(selection instanceof IStructuredSelection))
                    return false;
                IStructuredSelection ss = (IStructuredSelection) selection;
                if (ss.size() != 1)
                    return false;
                return true;
            }
        };
    }

    private boolean confirmOverwrite() {
        if (file != null && file.exists()) {
            String title = TeamUIMessages.LocalHistoryPage_OverwriteTitle;
            String msg = TeamUIMessages.LocalHistoryPage_OverwriteMessage;
            IHistoryPageSite parentSite = getHistoryPageSite();
            final MessageDialog dialog = new MessageDialog(parentSite.getShell(), title, null, msg,
                    MessageDialog.QUESTION,
                    new String[] { IDialogConstants.YES_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
            final int[] result = new int[1];
            parentSite.getShell().getDisplay().syncExec(new Runnable() {
                public void run() {
                    result[0] = dialog.open();
                }
            });
            if (result[0] != 0) {
                // cancel
                return false;
            }
        }
        return true;
    }

    public void setClickAction(boolean compare) {
        compareMode = compare ? ON : OFF;
        if (compareModeAction != null)
            compareModeAction.setChecked(compareMode == ON);
    }

    public ICompareInput getCompareInput(Object object) {
        if (object instanceof IFileRevision) {
            IFileRevision selectedFileRevision = (IFileRevision) object;
            ITypedElement fileElement = SaveableCompareEditorInput.createFileElement(file);
            FileRevisionTypedElement right = new FileRevisionTypedElement(selectedFileRevision);
            DiffNode node = new DiffNode(fileElement, right);
            return node;
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.eclipse.team.ui.history.IHistoryCompareAdapter#prepareInput(org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.compare.CompareConfiguration, org.eclipse.core.runtime.IProgressMonitor)
     */
    public void prepareInput(ICompareInput input, CompareConfiguration configuration, IProgressMonitor monitor) {
        Object right = input.getRight();
        if (right != null) {
            String label = getLabel(right);
            if (label != null)
                configuration.setRightLabel(label);
            Image image = getImage(right);
            if (image != null)
                configuration.setRightImage(image);
        }
        Object left = input.getLeft();
        if (left != null) {
            String label = getLabel(left);
            if (label != null)
                configuration.setLeftLabel(label);
            Image image = getImage(left);
            if (image != null)
                configuration.setLeftImage(image);
        }
    }

    protected Image getImage(Object right) {
        if (right instanceof FileRevisionTypedElement || right instanceof LocalFileRevision
                || right instanceof IFileRevision) {
            return historyTableProvider.getRevisionImage();
        }
        if (right instanceof ITypedElement) {
            ITypedElement te = (ITypedElement) right;
            return te.getImage();
        }
        return null;
    }

    protected String getLabel(Object object) {
        if (object instanceof IFileRevision) {
            IFileRevision revision = (IFileRevision) object;
            long timestamp = revision.getTimestamp();
            if (timestamp > 0)
                return NLS.bind(TeamUIMessages.LocalHistoryPage_0,
                        historyTableProvider.getDateFormat().format(new Date(timestamp)));
        }
        if (object instanceof FileRevisionTypedElement) {
            FileRevisionTypedElement e = (FileRevisionTypedElement) object;
            return getLabel(e.getRevision());
        }
        if (object instanceof LocalResourceTypedElement) {
            return TeamUIMessages.LocalHistoryPage_1;
        }
        return null;
    }

    /**
     * Method invoked from a background thread to update the viewer with the given revisions.
     * @param revisions the revisions for the file
     * @param monitor a progress monitor
     */
    protected void update(final IFileRevision[] revisions, IProgressMonitor monitor) {
        // Group the revisions (if appropriate) before running in the UI thread
        final AbstractHistoryCategory[] categories = groupRevisions(revisions, monitor);
        // Update the tree in the UI thread
        Utils.asyncExec(new Runnable() {
            public void run() {
                if (Policy.DEBUG_HISTORY) {
                    String time = new SimpleDateFormat("m:ss.SSS").format(new Date(System.currentTimeMillis())); //$NON-NLS-1$
                    System.out.println(
                            time + ": LocalHistoryPage#update, the tree is being updated in the UI thread"); //$NON-NLS-1$
                }
                if (categories != null) {
                    Object[] elementsToExpand = mapExpandedElements(categories, treeViewer.getExpandedElements());
                    treeViewer.getTree().setRedraw(false);
                    treeViewer.setInput(categories);
                    //if user is switching modes and already has expanded elements
                    //selected try to expand those, else expand all
                    if (elementsToExpand.length > 0)
                        treeViewer.setExpandedElements(elementsToExpand);
                    else {
                        treeViewer.expandAll();
                        Object[] el = treeViewer.getExpandedElements();
                        if (el != null && el.length > 0) {
                            treeViewer.setSelection(new StructuredSelection(el[0]));
                            treeViewer.getTree().deselectAll();
                        }
                    }
                    treeViewer.getTree().setRedraw(true);
                } else {
                    if (revisions.length > 0) {
                        treeViewer.setInput(revisions);
                    } else {
                        treeViewer.setInput(new AbstractHistoryCategory[] { getErrorMessage() });
                    }
                }
            }
        }, treeViewer);
    }

    private AbstractHistoryCategory[] groupRevisions(IFileRevision[] revisions, IProgressMonitor monitor) {
        if (groupingOn)
            return sortRevisions(revisions, monitor);
        return null;
    }

    private Object[] mapExpandedElements(AbstractHistoryCategory[] categories, Object[] expandedElements) {
        //store the names of the currently expanded categories in a map
        HashMap elementMap = new HashMap();
        for (int i = 0; i < expandedElements.length; i++) {
            elementMap.put(((DateHistoryCategory) expandedElements[i]).getName(), null);
        }

        //Go through the new categories and keep track of the previously expanded ones
        ArrayList expandable = new ArrayList();
        for (int i = 0; i < categories.length; i++) {
            //check to see if this category is currently expanded
            if (elementMap.containsKey(categories[i].getName())) {
                expandable.add(categories[i]);
            }
        }
        return expandable.toArray(new Object[expandable.size()]);
    }

    private AbstractHistoryCategory[] sortRevisions(IFileRevision[] revisions, IProgressMonitor monitor) {

        try {
            monitor.beginTask(null, 100);
            //Create the 4 categories
            DateHistoryCategory[] tempCategories = new DateHistoryCategory[4];
            //Get a calendar instance initialized to the current time
            Calendar currentCal = Calendar.getInstance();
            tempCategories[0] = new DateHistoryCategory(TeamUIMessages.HistoryPage_Today, currentCal, null);
            //Get yesterday
            Calendar yesterdayCal = Calendar.getInstance();
            yesterdayCal.roll(Calendar.DAY_OF_YEAR, -1);
            tempCategories[1] = new DateHistoryCategory(TeamUIMessages.HistoryPage_Yesterday, yesterdayCal, null);
            //Get this month
            Calendar monthCal = Calendar.getInstance();
            monthCal.set(Calendar.DAY_OF_MONTH, 1);
            tempCategories[2] = new DateHistoryCategory(TeamUIMessages.HistoryPage_ThisMonth, monthCal,
                    yesterdayCal);
            //Everything before after week is previous
            tempCategories[3] = new DateHistoryCategory(TeamUIMessages.HistoryPage_Previous, null, monthCal);

            ArrayList finalCategories = new ArrayList();
            for (int i = 0; i < tempCategories.length; i++) {
                tempCategories[i].collectFileRevisions(revisions, false);
                if (tempCategories[i].hasRevisions())
                    finalCategories.add(tempCategories[i]);
            }

            if (finalCategories.size() == 0) {
                //no revisions found for the current mode, so add a message category
                finalCategories.add(getErrorMessage());
            }

            return (AbstractHistoryCategory[]) finalCategories
                    .toArray(new AbstractHistoryCategory[finalCategories.size()]);
        } finally {
            monitor.done();
        }
    }

    private MessageHistoryCategory getErrorMessage() {
        MessageHistoryCategory messageCategory = new MessageHistoryCategory(getNoChangesMessage());
        return messageCategory;
    }

    protected String getNoChangesMessage() {
        return TeamUIMessages.LocalHistoryPage_NoRevisionsFound;
    }
}