blob: b3cba24540deee675ee8866fd4acb15633f3f338 [file] [log] [blame]
/*
* 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 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<GitBranch> localBranches = new ArrayList<GitBranch>(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<GitBranch> remoteBranches = new ArrayList<GitBranch>(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<GitRepository> {
public GitNewBranchAction(@NotNull Project project, @NotNull List<GitRepository> 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, 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<GitRepository> myRepositories;
private String myBranchName;
@NotNull private final GitRepository mySelectedRepository;
LocalBranchActions(@NotNull Project project, @NotNull List<GitRepository> 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<GitRepository> 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)
};
}
private static class CheckoutAction extends DumbAwareAction {
private final Project myProject;
private final List<GitRepository> myRepositories;
private final String myBranchName;
CheckoutAction(@NotNull Project project, @NotNull List<GitRepository> 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, myRepositories, null);
}
}
private static class CheckoutAsNewBranch extends DumbAwareAction {
private final Project myProject;
private final List<GitRepository> myRepositories;
private final String myBranchName;
CheckoutAsNewBranch(@NotNull Project project, @NotNull List<GitRepository> 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<GitRepository> myRepositories;
private final String myBranchName;
DeleteAction(Project project, List<GitRepository> 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<GitRepository> myRepositories;
private String myBranchName;
@NotNull private final GitRepository mySelectedRepository;
RemoteBranchActions(@NotNull Project project, @NotNull List<GitRepository> 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)
};
}
private static class CheckoutRemoteBranchAction extends DumbAwareAction {
private final Project myProject;
private final List<GitRepository> myRepositories;
private final String myRemoteBranchName;
public CheckoutRemoteBranchAction(@NotNull Project project, @NotNull List<GitRepository> repositories,
@NotNull String remoteBranchName) {
super("Checkout as new local branch");
myProject = project;
myRepositories = repositories;
myRemoteBranchName = remoteBranchName;
}
@Override
public void actionPerformed(AnActionEvent e) {
final String name = Messages.showInputDialog(myProject, "Enter name of new branch", "Checkout Remote Branch", Messages.getQuestionIcon(),
guessBranchName(), GitNewBranchNameValidator.newInstance(myRepositories));
if (name != null) {
GitBrancher brancher = ServiceManager.getService(myProject, GitBrancher.class);
brancher.checkoutNewBranchStartingFrom(name, myRemoteBranchName, myRepositories, null);
}
}
private String guessBranchName() {
// TODO: check if we already have a branch with that name; check if that branch tracks this remote branch. Show different messages
int slashPosition = myRemoteBranchName.indexOf("/");
// if no slash is found (for example, in the case of git-svn remote branches), propose the whole name.
return myRemoteBranchName.substring(slashPosition+1);
}
}
private static class RemoteDeleteAction extends DumbAwareAction {
private final Project myProject;
private final List<GitRepository> myRepositories;
private final String myBranchName;
RemoteDeleteAction(@NotNull Project project, @NotNull List<GitRepository> 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<GitRepository> myRepositories;
private final String myBranchName;
private final GitRepository mySelectedRepository;
public CompareAction(@NotNull Project project, @NotNull List<GitRepository> 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<GitRepository> myRepositories;
private final String myBranchName;
private final boolean myLocalBranch;
public MergeAction(@NotNull Project project, @NotNull List<GitRepository> 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;
}
}
}