Package org.eclipse.egit.ui.internal.pull

Source Code of org.eclipse.egit.ui.internal.pull.PullOperationUI

/*******************************************************************************
* Copyright (c) 2011 SAP AG.
* 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:
*    Mathias Kinzler (SAP AG) - initial implementation
*******************************************************************************/
package org.eclipse.egit.ui.internal.pull;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.egit.core.op.PullOperation;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.JobFamilies;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.branch.CleanupUncomittedChangesDialog;
import org.eclipse.egit.ui.internal.credentials.EGitCredentialsProvider;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jgit.api.PullResult;
import org.eclipse.jgit.api.RebaseResult;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;

/**
* UI wrapper for {@link PullOperation}
*/
public class PullOperationUI extends JobChangeAdapter {
  private static final IStatus NOT_TRIED_STATUS = new Status(IStatus.ERROR,
      Activator.getPluginId(), UIText.PullOperationUI_NotTriedMessage);

  private final Repository[] repositories;

  /**
   * Holds the number of PullOperationUIs that need to complete before the
   * pull results can be shown. The number includes this instance of
   * PullOperationUI and all subtasks spawned by it.
   */
  private final AtomicInteger tasksToWaitFor = new AtomicInteger(1);

  /** pull results per repository */
  protected final Map<Repository, Object> results = Collections
      .synchronizedMap(new LinkedHashMap<Repository, Object>());

  private final PullOperation pullOperation;

  /**
   * @param repositories
   */
  public PullOperationUI(Set<Repository> repositories) {
    this.repositories = repositories.toArray(new Repository[repositories
        .size()]);
    int timeout = Activator.getDefault().getPreferenceStore().getInt(
        UIPreferences.REMOTE_CONNECTION_TIMEOUT);
    pullOperation = new PullOperation(repositories, timeout);
    pullOperation.setCredentialsProvider(new EGitCredentialsProvider());
    for (Repository repository : repositories)
      results.put(repository, NOT_TRIED_STATUS);
  }

  /**
   * Starts this operation asynchronously
   */
  public void start() {
    start(this);
  }

  private void start(IJobChangeListener jobChangeListener) {
    // figure out a job name
    String jobName;
    if (this.repositories.length == 1) {
      String repoName = Activator.getDefault().getRepositoryUtil()
          .getRepositoryName(repositories[0]);
      String shortBranchName;
      try {
        shortBranchName = repositories[0].getBranch();
      } catch (IOException e) {
        // ignore here
        shortBranchName = ""; //$NON-NLS-1$
      }
      jobName = NLS.bind(UIText.PullOperationUI_PullingTaskName,
          shortBranchName, repoName);
    } else
      jobName = UIText.PullOperationUI_PullingMultipleTaskName;
    Job job = new WorkspaceJob(jobName) {

      @Override
      public IStatus runInWorkspace(IProgressMonitor monitor) {
        execute(monitor);
        // we always return OK and handle display of errors on our own
        return Status.OK_STATUS;
      }

      @Override
      public boolean belongsTo(Object family) {
        if (JobFamilies.PULL.equals(family))
          return true;
        return super.belongsTo(family);
      }
    };
    job.setRule(ResourcesPlugin.getWorkspace().getRoot());
    job.setUser(true);
    job.addJobChangeListener(jobChangeListener);
    job.schedule();
  }

  /**
   * Starts this operation synchronously.
   *
   * @param monitor
   */
  public void execute(IProgressMonitor monitor) {
    try {
      pullOperation.execute(monitor);
      results.putAll(pullOperation.getResults());
    } catch (CoreException e) {
      if (e.getStatus().getSeverity() == IStatus.CANCEL)
        results.putAll(pullOperation.getResults());
      else
        Activator.handleError(e.getMessage(), e, true);
    }
  }

  public void done(IJobChangeEvent event) {
    PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {

      public void run() {
        Map<Repository, Object> res = new LinkedHashMap<Repository, Object>(
            PullOperationUI.this.results);
        Shell shell = PlatformUI.getWorkbench()
            .getActiveWorkbenchWindow().getShell();
        handlePullResults(res, shell);
      }
    });
  }

  /**
   * Post-process the pull results, allowing the user to deal with uncommitted
   * changes and re-pull if the initial pull failed because of these changes
   *
   * @param resultsMap
   *            a copy of the initial pull results
   * @param shell
   */
  private void handlePullResults(final Map<Repository, Object> resultsMap,
      Shell shell) {
    for (Entry<Repository, Object> entry : resultsMap.entrySet()) {
      Object result = entry.getValue();
      if (result instanceof PullResult) {
        PullResult pullResult = (PullResult) result;
        if (pullResult.getRebaseResult() != null
            && RebaseResult.Status.UNCOMMITTED_CHANGES == pullResult
                .getRebaseResult().getStatus()) {
          handleUncommittedChanges(entry.getKey(), pullResult
              .getRebaseResult().getUncommittedChanges(), shell);
        }
      }
    }

    if (tasksToWaitFor.decrementAndGet() == 0 && !results.isEmpty())
      showResults(shell);
  }

  /**
   * @param repository
   * @param files
   *            uncommitted files that were in the way for the rebase
   * @param shell
   */
  private void handleUncommittedChanges(final Repository repository,
      final List<String> files, Shell shell) {
    String repoName = Activator.getDefault().getRepositoryUtil()
        .getRepositoryName(repository);
    CleanupUncomittedChangesDialog cleanupUncomittedChangesDialog = new CleanupUncomittedChangesDialog(
        shell,
        MessageFormat
            .format(UIText.AbstractRebaseCommandHandler_cleanupDialog_title,
                repoName),
        UIText.AbstractRebaseCommandHandler_cleanupDialog_text,
        repository, files);
    cleanupUncomittedChangesDialog.open();
    if (cleanupUncomittedChangesDialog.shouldContinue()) {
      final PullOperationUI parentOperation = this;
      final PullOperationUI pullOperationUI = new PullOperationUI(
          Collections.singleton(repository));
      tasksToWaitFor.incrementAndGet();
      pullOperationUI.start(new JobChangeAdapter() {

        @Override
        public void done(IJobChangeEvent event) {
          // put the result from this subtask into the result map of
          // the outer PullOperationUI and display the results if all
          // subtasks have reported back
          parentOperation.results.putAll(pullOperationUI.results);
          int missing = parentOperation.tasksToWaitFor.decrementAndGet();
          if (missing == 0)
            parentOperation.showResults();
        }
      });
    }
  }

  private void showResults() {
    PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
      public void run() {
        Shell shell = PlatformUI.getWorkbench()
            .getActiveWorkbenchWindow().getShell();
        showResults(shell);
      }
    });
  }

  private void showResults(final Shell shell) {
    if (this.results.isEmpty())
      // shouldn't really happen, but just in case...
      return;
    else if (this.results.size() == 1) {
      Entry<Repository, Object> entry = this.results.entrySet()
          .iterator().next();
      if (entry.getValue() instanceof PullResult)
        new PullResultDialog(shell, entry.getKey(), (PullResult) entry
            .getValue()).open();
      else {
        IStatus status = (IStatus) entry.getValue();
        if (status == NOT_TRIED_STATUS) {
          MessageDialog
              .openInformation(
                  shell,
                  UIText.PullOperationUI_PullCanceledWindowTitle,
                  UIText.PullOperationUI_PullOperationCanceledMessage);
        } else if (status.getException() instanceof TransportException) {
          ErrorDialog.openError(shell,
              UIText.PullOperationUI_PullFailed,
              UIText.PullOperationUI_ConnectionProblem,
              status);
        } else
          Activator.handleError(status.getMessage(), status
              .getException(), true);
      }
    } else
      new MultiPullResultDialog(shell, results).open();
  }
}
TOP

Related Classes of org.eclipse.egit.ui.internal.pull.PullOperationUI

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.