org.eclipse.egit.ui.internal.reflog.ReflogView.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.egit.ui.internal.reflog.ReflogView.java

Source

/*******************************************************************************
 * Copyright (c) 2011, 2012 Chris Aniszczyk <caniszczyk@gmail.com> 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:
 *   Chris Aniszczyk <caniszczyk@gmail.com> - initial implementation
 *   EclipseSource - Filtered Viewer
 *   Robin Stocker <robin@nibor.org> - Show In support
 *******************************************************************************/
package org.eclipse.egit.ui.internal.reflog;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIUtils;
import org.eclipse.egit.ui.internal.UIIcons;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.commit.CommitEditor;
import org.eclipse.egit.ui.internal.commit.RepositoryCommit;
import org.eclipse.egit.ui.internal.reflog.ReflogViewContentProvider.ReflogInput;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
import org.eclipse.jface.action.ControlContribution;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.util.OpenStrategy;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.window.Window;
import org.eclipse.jgit.events.ListenerHandle;
import org.eclipse.jgit.events.RefsChangedEvent;
import org.eclipse.jgit.events.RefsChangedListener;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.internal.storage.file.ReflogEntry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
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.IFileEditorInput;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.OpenAndLinkWithEditorHelper;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.part.IShowInTarget;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.part.ViewPart;

/**
 * A view that shows reflog entries. The View includes a quick filter that
 * searches on both the commit hashes and commit messages.
 */
public class ReflogView extends ViewPart implements RefsChangedListener, IShowInTarget {

    /**
     * View id
     */
    public static final String VIEW_ID = "org.eclipse.egit.ui.ReflogView"; //$NON-NLS-1$

    /**
     * Context menu id
     */
    public static final String POPUP_MENU_ID = "org.eclipse.egit.ui.internal.reflogview.popup";//$NON-NLS-1$

    private FormToolkit toolkit;

    private Form form;

    private TreeViewer refLogTableTreeViewer;

    private ISelectionListener selectionChangedListener;

    private ListenerHandle addRefsChangedListener;

    private final DateFormat absoluteFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$

    @Override
    public void createPartControl(Composite parent) {
        GridLayoutFactory.fillDefaults().applyTo(parent);

        toolkit = new FormToolkit(parent.getDisplay());
        parent.addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                toolkit.dispose();
            }
        });

        form = toolkit.createForm(parent);

        Image repoImage = UIIcons.REPOSITORY.createImage();
        UIUtils.hookDisposal(form, repoImage);
        final Image branchImage = UIIcons.CHANGESET.createImage();
        UIUtils.hookDisposal(form, branchImage);
        form.setImage(repoImage);
        form.setText(UIText.StagingView_NoSelectionTitle);
        GridDataFactory.fillDefaults().grab(true, true).applyTo(form);
        toolkit.decorateFormHeading(form);
        GridLayoutFactory.fillDefaults().applyTo(form.getBody());

        Composite tableComposite = toolkit.createComposite(form.getBody());
        tableComposite.setLayout(new GridLayout());

        GridDataFactory.fillDefaults().grab(true, true).applyTo(tableComposite);

        final TreeColumnLayout layout = new TreeColumnLayout();

        FilteredTree filteredTree = new FilteredTree(tableComposite, SWT.NONE | SWT.BORDER | SWT.FULL_SELECTION,
                new PatternFilter(), true) {
            @Override
            protected void createControl(Composite composite, int treeStyle) {
                super.createControl(composite, treeStyle);
                treeComposite.setLayout(layout);
            }
        };

        toolkit.adapt(filteredTree);
        refLogTableTreeViewer = filteredTree.getViewer();
        refLogTableTreeViewer.getTree().setLinesVisible(true);
        refLogTableTreeViewer.getTree().setHeaderVisible(true);
        refLogTableTreeViewer.setContentProvider(new ReflogViewContentProvider());

        ColumnViewerToolTipSupport.enableFor(refLogTableTreeViewer);

        TreeViewerColumn toColumn = createColumn(layout, UIText.ReflogView_CommitColumnHeader, 10, SWT.LEFT);
        toColumn.setLabelProvider(new ColumnLabelProvider() {

            @Override
            public String getText(Object element) {
                final ReflogEntry entry = (ReflogEntry) element;
                return entry.getNewId().abbreviate(7).name();
            }

            @Override
            public String getToolTipText(Object element) {
                final ReflogEntry entry = (ReflogEntry) element;
                return entry.getNewId().name();
            }

            @Override
            public Image getImage(Object element) {
                return branchImage;
            }

        });

        TreeViewerColumn commitMessageColumn = createColumn(layout, UIText.ReflogView_CommitMessageColumnHeader, 40,
                SWT.LEFT);
        commitMessageColumn.setLabelProvider(new ColumnLabelProvider() {

            @Override
            public String getText(Object element) {
                final ReflogEntry entry = (ReflogEntry) element;
                RevCommit c = getCommit(entry);
                return c == null ? "" : c.getShortMessage(); //$NON-NLS-1$
            }

            private RevCommit getCommit(final ReflogEntry entry) {
                RevWalk walk = new RevWalk(getRepository());
                walk.setRetainBody(true);
                RevCommit c = null;
                try {
                    c = walk.parseCommit(entry.getNewId());
                } catch (IOException ignored) {
                    // ignore
                } finally {
                    walk.release();
                }
                return c;
            }
        });

        TreeViewerColumn dateColumn = createColumn(layout, UIText.ReflogView_DateColumnHeader, 15, SWT.LEFT);
        dateColumn.setLabelProvider(new ColumnLabelProvider() {

            @Override
            public String getText(Object element) {
                final ReflogEntry entry = (ReflogEntry) element;
                final PersonIdent who = entry.getWho();
                // TODO add option to use RelativeDateFormatter
                return absoluteFormatter.format(who.getWhen());
            }

            @Override
            public Image getImage(Object element) {
                return null;
            }

        });

        TreeViewerColumn messageColumn = createColumn(layout, UIText.ReflogView_MessageColumnHeader, 40, SWT.LEFT);
        messageColumn.setLabelProvider(new ColumnLabelProvider() {

            private ResourceManager resourceManager = new LocalResourceManager(JFaceResources.getResources());

            @Override
            public String getText(Object element) {
                final ReflogEntry entry = (ReflogEntry) element;
                return entry.getComment();
            }

            public Image getImage(Object element) {
                String comment = ((ReflogEntry) element).getComment();
                if (comment.startsWith("commit:") || comment.startsWith("commit (initial):")) //$NON-NLS-1$ //$NON-NLS-2$
                    return (Image) resourceManager.get(UIIcons.COMMIT);
                if (comment.startsWith("commit (amend):")) //$NON-NLS-1$
                    return (Image) resourceManager.get(UIIcons.AMEND_COMMIT);
                if (comment.startsWith("pull")) //$NON-NLS-1$
                    return (Image) resourceManager.get(UIIcons.PULL);
                if (comment.startsWith("clone")) //$NON-NLS-1$
                    return (Image) resourceManager.get(UIIcons.CLONEGIT);
                if (comment.startsWith("rebase")) //$NON-NLS-1$
                    return (Image) resourceManager.get(UIIcons.REBASE);
                if (comment.startsWith("merge")) //$NON-NLS-1$
                    return (Image) resourceManager.get(UIIcons.MERGE);
                if (comment.startsWith("fetch")) //$NON-NLS-1$
                    return (Image) resourceManager.get(UIIcons.FETCH);
                if (comment.startsWith("branch")) //$NON-NLS-1$
                    return (Image) resourceManager.get(UIIcons.CREATE_BRANCH);
                if (comment.startsWith("checkout")) //$NON-NLS-1$
                    return (Image) resourceManager.get(UIIcons.CHECKOUT);
                return null;
            }

            public void dispose() {
                resourceManager.dispose();
                super.dispose();
            }
        });

        new OpenAndLinkWithEditorHelper(refLogTableTreeViewer) {
            @Override
            protected void linkToEditor(ISelection selection) {
                // Not supported

            }

            @Override
            protected void open(ISelection sel, boolean activate) {
                handleOpen(sel, OpenStrategy.activateOnOpen());
            }

            @Override
            protected void activate(ISelection selection) {
                handleOpen(selection, true);
            }

            private void handleOpen(ISelection selection, boolean activateOnOpen) {
                if (selection instanceof IStructuredSelection)
                    if (selection.isEmpty())
                        return;
                Repository repo = getRepository();
                if (repo == null)
                    return;
                RevWalk walk = new RevWalk(repo);
                try {
                    for (Object element : ((IStructuredSelection) selection).toArray()) {
                        ReflogEntry entry = (ReflogEntry) element;
                        ObjectId id = entry.getNewId();
                        if (id == null || id.equals(ObjectId.zeroId()))
                            id = entry.getOldId();
                        if (id != null && !id.equals(ObjectId.zeroId()))
                            CommitEditor.openQuiet(new RepositoryCommit(repo, walk.parseCommit(id)),
                                    activateOnOpen);
                    }
                } catch (IOException e) {
                    Activator.logError(UIText.ReflogView_ErrorOnOpenCommit, e);
                } finally {
                    walk.release();
                }
            }
        };

        selectionChangedListener = new ISelectionListener() {
            public void selectionChanged(IWorkbenchPart part, ISelection selection) {
                if (part instanceof IEditorPart) {
                    IEditorInput input = ((IEditorPart) part).getEditorInput();
                    if (input instanceof IFileEditorInput)
                        reactOnSelection(new StructuredSelection(((IFileEditorInput) input).getFile()));
                } else
                    reactOnSelection(selection);
            }
        };

        IWorkbenchPartSite site = getSite();
        ISelectionService service = (ISelectionService) site.getService(ISelectionService.class);
        service.addPostSelectionListener(selectionChangedListener);

        // Use current selection to populate reflog view
        ISelection selection = service.getSelection();
        if (selection != null && !selection.isEmpty()) {
            IWorkbenchPart part = site.getPage().getActivePart();
            if (part != null)
                selectionChangedListener.selectionChanged(part, selection);
        }

        site.setSelectionProvider(refLogTableTreeViewer);

        addRefsChangedListener = Repository.getGlobalListenerList().addRefsChangedListener(this);

        // register context menu
        MenuManager menuManager = new MenuManager();
        menuManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
        Tree tree = refLogTableTreeViewer.getTree();
        tree.setMenu(menuManager.createContextMenu(tree));
        getSite().registerContextMenu(POPUP_MENU_ID, menuManager, refLogTableTreeViewer);
    }

    @Override
    public void setFocus() {
        refLogTableTreeViewer.getControl().setFocus();
        activateContextService();
    }

    private void activateContextService() {
        IContextService contextService = (IContextService) getSite().getService(IContextService.class);
        if (contextService != null)
            contextService.activateContext(VIEW_ID);

    }

    @Override
    public void dispose() {
        super.dispose();
        ISelectionService service = (ISelectionService) getSite().getService(ISelectionService.class);
        service.removePostSelectionListener(selectionChangedListener);
        if (addRefsChangedListener != null)
            addRefsChangedListener.remove();
    }

    private void reactOnSelection(ISelection selection) {
        if (!(selection instanceof IStructuredSelection))
            return;
        IStructuredSelection ssel = (IStructuredSelection) selection;
        if (ssel.size() != 1)
            return;
        Repository selectedRepo = null;
        Object first = ssel.getFirstElement();
        if (first instanceof IResource) {
            IResource resource = (IResource) ssel.getFirstElement();
            RepositoryMapping mapping = RepositoryMapping.getMapping(resource.getProject());
            if (mapping != null)
                selectedRepo = mapping.getRepository();
        }
        if (selectedRepo == null && first instanceof IAdaptable) {
            IResource adapted = (IResource) ((IAdaptable) ssel.getFirstElement()).getAdapter(IResource.class);
            if (adapted != null) {
                RepositoryMapping mapping = RepositoryMapping.getMapping(adapted);
                if (mapping != null)
                    selectedRepo = mapping.getRepository();
            }
        }
        if (selectedRepo == null && first instanceof RepositoryTreeNode) {
            RepositoryTreeNode repoNode = (RepositoryTreeNode) ssel.getFirstElement();
            selectedRepo = repoNode.getRepository();
        }
        if (selectedRepo == null)
            return;

        // Only update when different repository is selected
        Repository currentRepo = getRepository();
        if (currentRepo == null || !selectedRepo.getDirectory().equals(currentRepo.getDirectory()))
            showReflogFor(selectedRepo);
    }

    private void updateRefLink(final String name) {
        IToolBarManager toolbar = form.getToolBarManager();
        toolbar.removeAll();

        ControlContribution refLabelControl = new ControlContribution("refLabel") { //$NON-NLS-1$
            @Override
            protected Control createControl(Composite cParent) {
                Composite composite = toolkit.createComposite(cParent);
                composite.setLayout(new RowLayout());
                composite.setBackground(null);

                final ImageHyperlink refLink = new ImageHyperlink(composite, SWT.NONE);
                Image image = UIIcons.BRANCH.createImage();
                UIUtils.hookDisposal(refLink, image);
                refLink.setImage(image);
                refLink.setFont(JFaceResources.getBannerFont());
                refLink.setForeground(toolkit.getColors().getColor(IFormColors.TITLE));
                refLink.addHyperlinkListener(new HyperlinkAdapter() {
                    @Override
                    public void linkActivated(HyperlinkEvent event) {
                        Repository repository = getRepository();
                        if (repository == null)
                            return;
                        RefSelectionDialog dialog = new RefSelectionDialog(refLink.getShell(), repository);
                        if (Window.OK == dialog.open())
                            showReflogFor(repository, dialog.getRefName());
                    }
                });
                refLink.setText(Repository.shortenRefName(name));

                return composite;
            }
        };
        toolbar.add(refLabelControl);
        toolbar.update(true);
    }

    /**
     * @return the repository the view is showing the reflog for
     */
    public Repository getRepository() {
        Object input = refLogTableTreeViewer.getInput();
        if (input instanceof ReflogInput)
            return ((ReflogInput) input).getRepository();
        return null;
    }

    public boolean show(ShowInContext context) {
        ISelection selection = context.getSelection();
        if (selection instanceof IStructuredSelection) {
            IStructuredSelection structuredSelection = (IStructuredSelection) selection;
            for (Object element : structuredSelection.toList()) {
                if (element instanceof RepositoryTreeNode) {
                    RepositoryTreeNode node = (RepositoryTreeNode) element;
                    showReflogFor(node.getRepository());
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Defines the repository for the reflog to show.
     *
     * @param repository
     */
    private void showReflogFor(Repository repository) {
        showReflogFor(repository, Constants.HEAD);
    }

    /**
     * Defines the repository for the reflog to show.
     *
     * @param repository
     * @param ref
     */
    private void showReflogFor(Repository repository, String ref) {
        if (repository != null && ref != null) {
            refLogTableTreeViewer.setInput(new ReflogInput(repository, ref));
            updateRefLink(ref);
            form.setText(getRepositoryName(repository));
        }
    }

    private TreeViewerColumn createColumn(final TreeColumnLayout columnLayout, final String text, final int weight,
            final int style) {
        final TreeViewerColumn viewerColumn = new TreeViewerColumn(refLogTableTreeViewer, style);
        final TreeColumn column = viewerColumn.getColumn();
        column.setText(text);
        columnLayout.setColumnData(column, new ColumnWeightData(weight, 10));
        return viewerColumn;
    }

    private static String getRepositoryName(Repository repository) {
        String repoName = Activator.getDefault().getRepositoryUtil().getRepositoryName(repository);
        RepositoryState state = repository.getRepositoryState();
        if (state != RepositoryState.SAFE)
            return repoName + '|' + state.getDescription();
        else
            return repoName;
    }

    public void onRefsChanged(RefsChangedEvent event) {
        PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
            public void run() {
                refLogTableTreeViewer.refresh();
            }
        });
    }

    /**
     * @return selection provider
     */
    public ISelectionProvider getSelectionProvider() {
        return refLogTableTreeViewer;
    }
}