/* * 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 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, 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) }; } private 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, 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) }; } private 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; 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 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; } } }