All Downloads are FREE. Search and download functionalities are using the official Maven repository.

git4idea.ui.branch.GitBranchPopupActions Maven / Gradle / Ivy

/*
 * Copyright 2000-2012 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package git4idea.ui.branch;

import com.intellij.dvcs.ui.NewBranchAction;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Condition;
import com.intellij.util.containers.ContainerUtil;
import git4idea.GitBranch;
import git4idea.branch.GitBranchUtil;
import git4idea.branch.GitBrancher;
import git4idea.repo.GitRepository;
import git4idea.validators.GitNewBranchNameValidator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class GitBranchPopupActions {

  private final Project myProject;
  private final GitRepository myRepository;

  GitBranchPopupActions(Project project, GitRepository repository) {
    myProject = project;
    myRepository = repository;
  }

  ActionGroup createActions(@Nullable DefaultActionGroup toInsert) {
    DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);

    popupGroup.addAction(new GitNewBranchAction(myProject,Collections.singletonList(myRepository)));
    popupGroup.addAction(new CheckoutRevisionActions(myProject, myRepository));

    if (toInsert != null) {
      popupGroup.addAll(toInsert);
    }

    popupGroup.addSeparator("Local Branches");
    List localBranches = new ArrayList(myRepository.getBranches().getLocalBranches());
    Collections.sort(localBranches);
    for (GitBranch localBranch : localBranches) {
      if (!localBranch.equals(myRepository.getCurrentBranch())) { // don't show current branch in the list
        popupGroup.add(new LocalBranchActions(myProject, Collections.singletonList(myRepository), localBranch.getName(), myRepository));
      }
    }

    popupGroup.addSeparator("Remote Branches");
    List remoteBranches = new ArrayList(myRepository.getBranches().getRemoteBranches());
    Collections.sort(remoteBranches);
    for (GitBranch remoteBranch : remoteBranches) {
      popupGroup.add(new RemoteBranchActions(myProject, Collections.singletonList(myRepository), remoteBranch.getName(), myRepository));
    }
    
    return popupGroup;
  }

  public static class GitNewBranchAction extends NewBranchAction {

    public GitNewBranchAction(@NotNull Project project, @NotNull List repositories) {
      super(project, repositories);
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
      final String name = GitBranchUtil.getNewBranchNameFromUser(myProject, myRepositories, "Create New Branch");
      if (name != null) {
        GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
        brancher.checkoutNewBranch(name, myRepositories);
      }
    }
  }

  /**
   * Checkout manually entered tag or revision number.
   */
  private static class CheckoutRevisionActions extends DumbAwareAction {
    private final Project myProject;
    private final GitRepository myRepository;

    CheckoutRevisionActions(Project project, GitRepository repository) {
      super("Checkout Tag or Revision");
      myProject = project;
      myRepository = repository;
    }

    @Override public void actionPerformed(AnActionEvent e) {
      // TODO autocomplete branches, tags.
      // on type check ref validity, on OK check ref existence.
      String reference = Messages
        .showInputDialog(myProject, "Enter reference (branch, tag) name or commit hash", "Checkout", Messages.getQuestionIcon());
      if (reference != null) {
        GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
        brancher.checkout(reference, true, Collections.singletonList(myRepository), null);
      }
    }

    @Override
    public void update(AnActionEvent e) {
      if (myRepository.isFresh()) {
        e.getPresentation().setEnabled(false);
        e.getPresentation().setDescription("Checkout is not possible before the first commit");
      }
    }
  }

  /**
   * Actions available for local branches.
   */
  static class LocalBranchActions extends ActionGroup {

    private final Project myProject;
    private final List myRepositories;
    private String myBranchName;
    @NotNull private final GitRepository mySelectedRepository;

    LocalBranchActions(@NotNull Project project, @NotNull List repositories, @NotNull String branchName,
                       @NotNull GitRepository selectedRepository) {
      super("", true);
      myProject = project;
      myRepositories = repositories;
      myBranchName = branchName;
      mySelectedRepository = selectedRepository;
      getTemplatePresentation().setText(calcBranchText(), false); // no mnemonics
    }

    @NotNull
    private String calcBranchText() {
      String trackedBranch = new GitMultiRootBranchConfig(myRepositories).getTrackedBranch(myBranchName);
      if (trackedBranch != null) {
        return myBranchName + " -> " + trackedBranch;
      }
      else {
        return myBranchName;
      }
    }

    @NotNull
    List getRepositories() {
      return myRepositories;
    }

    @NotNull
    public String getBranchName() {
      return myBranchName;
    }

    @NotNull
    @Override
    public AnAction[] getChildren(@Nullable AnActionEvent e) {
      return new AnAction[] {
        new CheckoutAction(myProject, myRepositories, myBranchName),
        new CheckoutAsNewBranch(myProject, myRepositories, myBranchName),
        new CompareAction(myProject, myRepositories, myBranchName, mySelectedRepository),
        new MergeAction(myProject, myRepositories, myBranchName, true),
        new DeleteAction(myProject, myRepositories, myBranchName)
      };
    }

    static class CheckoutAction extends DumbAwareAction {
      private final Project myProject;
      private final List myRepositories;
      private final String myBranchName;

      CheckoutAction(@NotNull Project project, @NotNull List repositories, @NotNull String branchName) {
        super("Checkout");
        myProject = project;
        myRepositories = repositories;
        myBranchName = branchName;
      }

      @Override
      public void actionPerformed(AnActionEvent e) {
        GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
        brancher.checkout(myBranchName, false, myRepositories, null);
      }

    }

    private static class CheckoutAsNewBranch extends DumbAwareAction {
      private final Project myProject;
      private final List myRepositories;
      private final String myBranchName;

      CheckoutAsNewBranch(@NotNull Project project, @NotNull List repositories, @NotNull String branchName) {
        super("Checkout as new branch");
        myProject = project;
        myRepositories = repositories;
        myBranchName = branchName;
      }

      @Override
      public void actionPerformed(AnActionEvent e) {
        final String name = Messages
          .showInputDialog(myProject, "Enter name of new branch", "Checkout New Branch From " + myBranchName,
                           Messages.getQuestionIcon(), "", GitNewBranchNameValidator.newInstance(myRepositories));
        if (name != null) {
          GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
          brancher.checkoutNewBranchStartingFrom(name, myBranchName, myRepositories, null);
        }
      }

    }

    private static class DeleteAction extends DumbAwareAction {
      private final Project myProject;
      private final List myRepositories;
      private final String myBranchName;

      DeleteAction(Project project, List repositories, String branchName) {
        super("Delete");
        myProject = project;
        myRepositories = repositories;
        myBranchName = branchName;
      }

      @Override
      public void actionPerformed(AnActionEvent e) {
        GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
        brancher.deleteBranch(myBranchName, myRepositories);
      }
    }
  }

  /**
   * Actions available for remote branches
   */
  static class RemoteBranchActions extends ActionGroup {

    private final Project myProject;
    private final List myRepositories;
    private String myBranchName;
    @NotNull private final GitRepository mySelectedRepository;

    RemoteBranchActions(@NotNull Project project, @NotNull List repositories, @NotNull String branchName,
                        @NotNull GitRepository selectedRepository) {
      super("", true);
      myProject = project;
      myRepositories = repositories;
      myBranchName = branchName;
      mySelectedRepository = selectedRepository;
      getTemplatePresentation().setText(myBranchName, false); // no mnemonics
    }

    @NotNull
    @Override
    public AnAction[] getChildren(@Nullable AnActionEvent e) {
      return new AnAction[] {
        new CheckoutRemoteBranchAction(myProject, myRepositories, myBranchName),
        new CompareAction(myProject, myRepositories, myBranchName, mySelectedRepository),
        new MergeAction(myProject, myRepositories, myBranchName, false),
        new RemoteDeleteAction(myProject, myRepositories, myBranchName)
      };
    }

    static class CheckoutRemoteBranchAction extends DumbAwareAction {
      private final Project myProject;
      private final List myRepositories;
      private final String myRemoteBranchName;

      public CheckoutRemoteBranchAction(@NotNull Project project, @NotNull List repositories,
                                        @NotNull String remoteBranchName) {
        super("Checkout as new local branch");
        myProject = project;
        myRemoteBranchName = remoteBranchName;
        myRepositories = ContainerUtil.filter(repositories, new Condition() {
          @Override
          public boolean value(GitRepository repository) {
            return !guessBranchName(myRemoteBranchName).equals(repository.getCurrentBranchName());
          }
        });
      }

      @Override
      public void actionPerformed(AnActionEvent e) {
        final String name = Messages.showInputDialog(myProject, "Enter name of new branch", "Checkout Remote Branch", Messages.getQuestionIcon(),
                                                     guessBranchName(myRemoteBranchName),
                                                     GitNewBranchNameValidator.newInstance(myRepositories));
        if (name != null) {
          GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
          brancher.checkoutNewBranchStartingFrom(name, myRemoteBranchName, myRepositories, null);
        }
      }

      private static String guessBranchName(@NotNull String remoteBranchName) {
        // TODO: check if we already have a branch with that name; check if that branch tracks this remote branch. Show different messages
        int slashPosition = remoteBranchName.indexOf("/");
        // if no slash is found (for example, in the case of git-svn remote branches), propose the whole name.
        return remoteBranchName.substring(slashPosition + 1);
      }
    }

    private static class RemoteDeleteAction extends DumbAwareAction {
      private final Project myProject;
      private final List myRepositories;
      private final String myBranchName;

      RemoteDeleteAction(@NotNull Project project, @NotNull List repositories, @NotNull String branchName) {
        super("Delete");
        myProject = project;
        myRepositories = repositories;
        myBranchName = branchName;
      }

      @Override
      public void actionPerformed(AnActionEvent e) {
        GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
        brancher.deleteRemoteBranch(myBranchName, myRepositories);
      }
    }

  }
  
  private static class CompareAction extends DumbAwareAction {

    private final Project myProject;
    private final List myRepositories;
    private final String myBranchName;
    private final GitRepository mySelectedRepository;

    public CompareAction(@NotNull Project project, @NotNull List repositories, @NotNull String branchName,
                         @NotNull GitRepository selectedRepository) {
      super("Compare");
      myProject = project;
      myRepositories = repositories;
      myBranchName = branchName;
      mySelectedRepository = selectedRepository;
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
      GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
      brancher.compare(myBranchName, myRepositories, mySelectedRepository);
    }

  }

  private static class MergeAction extends DumbAwareAction {

    private final Project myProject;
    private final List myRepositories;
    private final String myBranchName;
    private final boolean myLocalBranch;

    public MergeAction(@NotNull Project project, @NotNull List repositories, @NotNull String branchName,
                       boolean localBranch) {
      super("Merge");
      myProject = project;
      myRepositories = repositories;
      myBranchName = branchName;
      myLocalBranch = localBranch;
    }

    @Override
    public void actionPerformed(AnActionEvent e) {
      GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
      brancher.merge(myBranchName, deleteOnMerge(), myRepositories);
    }

    private GitBrancher.DeleteOnMergeOption deleteOnMerge() {
      if (myLocalBranch && !myBranchName.equals("master")) {
        return GitBrancher.DeleteOnMergeOption.PROPOSE;
      }
      return GitBrancher.DeleteOnMergeOption.NOTHING;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy