Package org.eclipse.egit.ui.internal.blame

Source Code of org.eclipse.egit.ui.internal.blame.BlameOperation$RevisionSelectionHandler

/******************************************************************************
*  Copyright (c) 2011, 2013 GitHub Inc 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:
*    Kevin Sawicki (GitHub Inc.) - initial API and implementation
*****************************************************************************/
package org.eclipse.egit.ui.internal.blame;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.egit.core.AdapterUtils;
import org.eclipse.egit.core.op.IEGitOperation;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.internal.history.HistoryPageInput;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.revisions.IRevisionRulerColumn;
import org.eclipse.jface.text.revisions.IRevisionRulerColumnExtension;
import org.eclipse.jface.text.revisions.RevisionInformation;
import org.eclipse.jface.text.source.IVerticalRulerInfo;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jgit.api.BlameCommand;
import org.eclipse.jgit.blame.BlameResult;
import org.eclipse.jgit.diff.RawTextComparator;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.team.ui.history.IHistoryView;
import org.eclipse.team.ui.history.RevisionAnnotationController;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;

/**
* Blame operation
*/
public class BlameOperation implements IEGitOperation {

  static class BlameHistoryPageInput extends HistoryPageInput
      implements IAdaptable {

    private final RevCommit commit;

    BlameHistoryPageInput(Repository repository, RevCommit commit,
        File file) {
      super(repository, new File[] { file });
      this.commit = commit;
    }

    BlameHistoryPageInput(Repository repository, RevCommit commit,
        IResource file) {
      super(repository, new IResource[] { file });
      this.commit = commit;
    }

    BlameHistoryPageInput(Repository repository, RevCommit commit) {
      super(repository);
      this.commit = commit;
    }

    public Object getAdapter(Class adapter) {
      if (RevCommit.class == adapter)
        return commit;
      return Platform.getAdapterManager().getAdapter(this, adapter);
    }
  }

  private static class RevisionSelectionHandler implements
      ISelectionChangedListener {

    private IFile resourceFile;

    private File nonResourceFile;

    private boolean firstSelectionChange = true;

    private RevisionSelectionHandler(Repository repository, String path,
        IStorage storage) {
      if (storage instanceof IFile)
        resourceFile = (IFile) storage;
      else if (!repository.isBare())
        nonResourceFile = new File(repository.getWorkTree(), path);
    }

    public void selectionChanged(SelectionChangedEvent event) {
      // Don't show the commit for the first selection change, as that was
      // not initiated by the user directly. Instead, show the commit the
      // first time the user clicks on a revision or line.
      if (firstSelectionChange) {
        firstSelectionChange = false;
        return;
      }
      ISelection selection = event.getSelection();
      if (selection.isEmpty()
          || !(selection instanceof IStructuredSelection))
        return;
      Object first = ((IStructuredSelection) selection).getFirstElement();
      if (!(first instanceof BlameRevision))
        return;

      IHistoryView part = (IHistoryView) PlatformUI.getWorkbench()
          .getActiveWorkbenchWindow().getActivePage()
          .findView(IHistoryView.VIEW_ID);
      if (part == null)
        return;

      BlameRevision revision = (BlameRevision) first;
      BlameHistoryPageInput input;
      if (resourceFile != null)
        input = new BlameHistoryPageInput(revision.getRepository(),
            revision.getCommit(), resourceFile);
      else if (nonResourceFile != null)
        input = new BlameHistoryPageInput(revision.getRepository(),
            revision.getCommit(), nonResourceFile);
      else
        input = new BlameHistoryPageInput(revision.getRepository(),
            revision.getCommit());
      part.showHistoryFor(input);
    }

  }

  private Repository repository;

  private IStorage storage;

  private String path;

  private RevCommit startCommit;

  private Shell shell;

  private IWorkbenchPage page;

  private int lineNumberToReveal;

  /**
   * Create annotate operation
   *
   * @param repository
   * @param storage
   * @param path
   * @param startCommit
   * @param shell
   * @param page
   */
  public BlameOperation(Repository repository, IStorage storage, String path,
      RevCommit startCommit, Shell shell, IWorkbenchPage page) {
    this(repository, storage, path, startCommit, shell, page, -1);
  }

  /**
   * Create annotate operation
   *
   * @param repository
   * @param storage
   * @param path
   * @param startCommit
   * @param shell
   * @param page
   * @param lineNumberToReveal
   *            0-based line number to reveal, -1 for no reveal
   */
  public BlameOperation(Repository repository, IStorage storage, String path,
      RevCommit startCommit, Shell shell, IWorkbenchPage page,
      int lineNumberToReveal) {
    this.repository = repository;
    this.storage = storage;
    this.path = path;
    this.startCommit = startCommit;
    this.shell = shell;
    this.page = page;
    this.lineNumberToReveal = lineNumberToReveal;
  }

  public void execute(IProgressMonitor monitor) throws CoreException {
    final RevisionInformation info = new RevisionInformation();

    final BlameCommand command = new BlameCommand(repository)
        .setFollowFileRenames(true).setFilePath(path);
    if (startCommit != null)
      command.setStartCommit(startCommit);
    else {
      try {
        command.setStartCommit(repository.resolve(Constants.HEAD));
      } catch (IOException e) {
        Activator
            .error("Error resolving HEAD for showing annotations in repository: " + repository, e); //$NON-NLS-1$
        return;
      }
    }
    if (Activator.getDefault().getPreferenceStore()
        .getBoolean(UIPreferences.BLAME_IGNORE_WHITESPACE))
      command.setTextComparator(RawTextComparator.WS_IGNORE_ALL);

    BlameResult result;
    try {
      result = command.call();
    } catch (Exception e1) {
      Activator.error(e1.getMessage(), e1);
      return;
    }
    if (result == null)
      return;

    Map<RevCommit, BlameRevision> revisions = new HashMap<RevCommit, BlameRevision>();
    int lineCount = result.getResultContents().size();
    BlameRevision previous = null;
    for (int i = 0; i < lineCount; i++) {
      RevCommit commit = result.getSourceCommit(i);
      String sourcePath = result.getSourcePath(i);
      if (commit == null) {
        // Unregister the current revision
        if (previous != null) {
          previous.register();
          previous = null;
        }
        continue;
      }
      BlameRevision revision = revisions.get(commit);
      if (revision == null) {
        revision = new BlameRevision();
        revision.setRepository(repository);
        revision.setCommit(commit);
        revision.setSourcePath(sourcePath);
        revisions.put(commit, revision);
        info.addRevision(revision);
      }
      revision.addSourceLine(i, result.getSourceLine(i));
      if (previous != null)
        if (previous == revision)
          previous.addLine();
        else {
          previous.register();
          previous = revision.reset(i);
        }
      else
        previous = revision.reset(i);
    }
    if (previous != null)
      previous.register();

    shell.getDisplay().asyncExec(new Runnable() {
      public void run() {
        openEditor(info);
      }
    });
  }

  private void openEditor(final RevisionInformation info) {
    AbstractDecoratedTextEditor editor;
    try {
      if (storage instanceof IFile)
        editor = RevisionAnnotationController.openEditor(page,
            (IFile) storage);
      else
        editor = RevisionAnnotationController.openEditor(page, storage,
            storage);
    } catch (PartInitException e) {
      Activator.handleError("Error displaying blame annotations", e, //$NON-NLS-1$
          false);
      return;
    }
    if (editor == null)
      return;

    // Show history view for path
    try {
      IHistoryView part = (IHistoryView) page.showView(
          IHistoryView.VIEW_ID, null, IWorkbenchPage.VIEW_VISIBLE);
      HistoryPageInput input = createHistoryPageInputWhenEditorOpened();
      part.showHistoryFor(input);
    } catch (PartInitException e) {
      Activator.handleError("Error displaying blame annotations", e, //$NON-NLS-1$
          false);
    }

    // IRevisionRulerColumn would also be possible but using
    // IVerticalRulerInfo seems to work in more situations.
    IVerticalRulerInfo rulerInfo = AdapterUtils.adapt(editor,
        IVerticalRulerInfo.class);

    BlameInformationControlCreator creator = new BlameInformationControlCreator(
        rulerInfo);
    info.setHoverControlCreator(creator);
    info.setInformationPresenterControlCreator(creator);

    editor.showRevisionInformation(info,
        "org.eclipse.egit.ui.internal.decorators.GitQuickDiffProvider"); //$NON-NLS-1$

    if (lineNumberToReveal >= 0) {
      IDocument document = editor.getDocumentProvider().getDocument(
          editor.getEditorInput());
      int offset;
      try {
        offset = document.getLineOffset(lineNumberToReveal);
        editor.selectAndReveal(offset, 0);
      } catch (BadLocationException e) {
        Activator.logError(
            "Error revealing line " + lineNumberToReveal, e); //$NON-NLS-1$
      }
    }

    IRevisionRulerColumn revisionRuler = AdapterUtils.adapt(editor,
        IRevisionRulerColumn.class);
    if (revisionRuler instanceof IRevisionRulerColumnExtension)
      ((IRevisionRulerColumnExtension) revisionRuler)
          .getRevisionSelectionProvider()
          .addSelectionChangedListener(
              new RevisionSelectionHandler(repository, path,
                  storage));
  }

  private HistoryPageInput createHistoryPageInputWhenEditorOpened() {
    if (storage instanceof IFile) {
      IResource resource = (IResource) storage;
      if (startCommit != null) {
        return new BlameHistoryPageInput(repository, startCommit,
            resource);
      } else {
        return new HistoryPageInput(repository,
            new IResource[] { resource });
      }
    } else if (!repository.isBare()) {
      File file = new File(repository.getWorkTree(), path);
      if (startCommit != null) {
        return new BlameHistoryPageInput(repository, startCommit,
            file);
      } else {
        return new HistoryPageInput(repository,
            new File[] { file });
      }
    } else {
      return new HistoryPageInput(repository);
    }
  }

  public ISchedulingRule getSchedulingRule() {
    return null;
  }
}
TOP

Related Classes of org.eclipse.egit.ui.internal.blame.BlameOperation$RevisionSelectionHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.