summaryrefslogtreecommitdiff
path: root/plugins/hg4idea/src/org/zmlx/hg4idea/branch
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/hg4idea/src/org/zmlx/hg4idea/branch')
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchAbstractAction.java38
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopup.java119
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopupActions.java270
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchUtil.java77
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchesAction.java34
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgCommonBranchActions.java141
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgMultiRootBranchConfig.java50
7 files changed, 729 insertions, 0 deletions
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchAbstractAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchAbstractAction.java
new file mode 100644
index 000000000000..3998dedd0cc5
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchAbstractAction.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2014 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 org.zmlx.hg4idea.branch;
+
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.zmlx.hg4idea.repo.HgRepository;
+
+import java.util.List;
+
+public abstract class HgBranchAbstractAction extends DumbAwareAction {
+ @NotNull protected final Project myProject;
+ @NotNull protected final List<HgRepository> myRepositories;
+ @NotNull protected final String myBranchName;
+
+ public HgBranchAbstractAction(@NotNull Project project, @NotNull String title,
+ @NotNull List<HgRepository> repositories,
+ @NotNull String branchName) {
+ super(title);
+ myProject = project;
+ myRepositories = repositories;
+ myBranchName = branchName;
+ }
+} \ No newline at end of file
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopup.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopup.java
new file mode 100644
index 000000000000..c0d6f58d5e0e
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopup.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2000-2013 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 org.zmlx.hg4idea.branch;
+
+import com.intellij.dvcs.branch.DvcsBranchPopup;
+import com.intellij.dvcs.repo.AbstractRepositoryManager;
+import com.intellij.dvcs.ui.RootAction;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Condition;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.zmlx.hg4idea.HgProjectSettings;
+import org.zmlx.hg4idea.repo.HgRepository;
+import org.zmlx.hg4idea.repo.HgRepositoryManager;
+import org.zmlx.hg4idea.util.HgUtil;
+
+import javax.swing.*;
+import java.util.List;
+
+/**
+ * <p>
+ * The popup which allows to quickly switch and control Hg branches.
+ * </p>
+ * <p>
+ * Use {@link #asListPopup()} to achieve the {@link com.intellij.openapi.ui.popup.ListPopup} itself.
+ * </p>
+ */
+public class HgBranchPopup extends DvcsBranchPopup<HgRepository> {
+
+ /**
+ * @param currentRepository Current repository, which means the repository of the currently open or selected file.
+ */
+ public static HgBranchPopup getInstance(@NotNull Project project, @NotNull HgRepository currentRepository) {
+
+ HgRepositoryManager manager = HgUtil.getRepositoryManager(project);
+ HgProjectSettings hgProjectSettings = ServiceManager.getService(project, HgProjectSettings.class);
+ HgMultiRootBranchConfig hgMultiRootBranchConfig = new HgMultiRootBranchConfig(manager.getRepositories());
+
+ Condition<AnAction> preselectActionCondition = new Condition<AnAction>() {
+ @Override
+ public boolean value(AnAction action) {
+ return false;
+ }
+ };
+ return new HgBranchPopup(currentRepository, manager, hgMultiRootBranchConfig, hgProjectSettings,
+ preselectActionCondition);
+ }
+
+ private HgBranchPopup(@NotNull HgRepository currentRepository,
+ @NotNull HgRepositoryManager repositoryManager,
+ @NotNull HgMultiRootBranchConfig hgMultiRootBranchConfig, @NotNull HgProjectSettings vcsSettings,
+ @NotNull Condition<AnAction> preselectActionCondition) {
+ super(currentRepository, repositoryManager, hgMultiRootBranchConfig, vcsSettings, preselectActionCondition);
+ }
+
+ protected void setCurrentBranchInfo() {
+ String branchText = "Current branch : ";
+ //always display heavy branch name for additional info //
+ myPopup.setAdText(branchText + myCurrentRepository.getCurrentBranch(), SwingConstants.CENTER);
+ }
+
+ @Override
+ protected void fillWithCommonRepositoryActions(@NotNull DefaultActionGroup popupGroup,
+ @NotNull AbstractRepositoryManager<HgRepository> repositoryManager) {
+ List<HgRepository> allRepositories = repositoryManager.getRepositories();
+ popupGroup.add(new HgBranchPopupActions.HgNewBranchAction(myProject, allRepositories, myCurrentRepository));
+ popupGroup.addAction(new HgBranchPopupActions.HgNewBookmarkAction(myProject, allRepositories, myCurrentRepository));
+ popupGroup.addAction(new HgBranchPopupActions.HgShowUnnamedHeadsForCurrentBranchAction(myProject, myCurrentRepository));
+ popupGroup.addAll(createRepositoriesActions());
+
+ popupGroup.addSeparator("Common Branches");
+ for (String branch : myMultiRootBranchConfig.getLocalBranchNames()) {
+ List<HgRepository> repositories = filterRepositoriesNotOnThisBranch(branch, allRepositories);
+ if (!repositories.isEmpty()) {
+ popupGroup.add(new HgCommonBranchActions(myProject, repositories, branch));
+ }
+ }
+ popupGroup.addSeparator("Common Bookmarks");
+ for (String branch : ((HgMultiRootBranchConfig)myMultiRootBranchConfig).getBookmarkNames()) {
+ List<HgRepository> repositories = filterRepositoriesNotOnThisBranch(branch, allRepositories);
+ if (!repositories.isEmpty()) {
+ popupGroup.add(new HgBranchPopupActions.BookmarkActions(myProject, repositories, branch));
+ }
+ }
+ }
+
+ @NotNull
+ protected DefaultActionGroup createRepositoriesActions() {
+ DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);
+ popupGroup.addSeparator("Repositories");
+ for (HgRepository repository : myRepositoryManager.getRepositories()) {
+ popupGroup.add(new RootAction<HgRepository>(repository, highlightCurrentRepo() ? myCurrentRepository : null,
+ new HgBranchPopupActions(repository.getProject(), repository).createActions(null),
+ HgUtil.getDisplayableBranchOrBookmarkText(repository)));
+ }
+ return popupGroup;
+ }
+
+ protected void fillPopupWithCurrentRepositoryActions(@NotNull DefaultActionGroup popupGroup, @Nullable DefaultActionGroup actions) {
+ popupGroup.addAll(new HgBranchPopupActions(myProject, myCurrentRepository).createActions(actions));
+ }
+}
+
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopupActions.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopupActions.java
new file mode 100644
index 000000000000..10b97235f559
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopupActions.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2000-2013 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 org.zmlx.hg4idea.branch;
+
+import com.intellij.dvcs.DvcsUtil;
+import com.intellij.dvcs.repo.Repository;
+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.application.ApplicationManager;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.Function;
+import com.intellij.util.PlatformIcons;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.vcs.log.Hash;
+import com.intellij.vcs.log.impl.HashImpl;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.zmlx.hg4idea.HgNameWithHashInfo;
+import org.zmlx.hg4idea.HgRevisionNumber;
+import org.zmlx.hg4idea.action.HgAbstractGlobalAction;
+import org.zmlx.hg4idea.action.HgCommandResultNotifier;
+import org.zmlx.hg4idea.command.HgBookmarkCommand;
+import org.zmlx.hg4idea.command.HgBranchCreateCommand;
+import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand;
+import org.zmlx.hg4idea.execution.HgCommandException;
+import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgCommandResultHandler;
+import org.zmlx.hg4idea.repo.HgRepository;
+import org.zmlx.hg4idea.ui.HgBookmarkDialog;
+import org.zmlx.hg4idea.util.HgErrorUtil;
+
+import java.util.*;
+
+import static org.zmlx.hg4idea.util.HgUtil.getNamesWithoutHashes;
+import static org.zmlx.hg4idea.util.HgUtil.getNewBranchNameFromUser;
+
+public class HgBranchPopupActions {
+
+ private final Project myProject;
+ private final HgRepository myRepository;
+
+ HgBranchPopupActions(Project project, HgRepository repository) {
+ myProject = project;
+ myRepository = repository;
+ }
+
+ ActionGroup createActions(@Nullable DefaultActionGroup toInsert) {
+ DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);
+ popupGroup.addAction(new HgNewBranchAction(myProject, Collections.singletonList(myRepository), myRepository));
+ popupGroup.addAction(new HgNewBookmarkAction(myProject, Collections.singletonList(myRepository), myRepository));
+ popupGroup.addAction(new HgShowUnnamedHeadsForCurrentBranchAction(myProject, myRepository));
+ if (toInsert != null) {
+ popupGroup.addAll(toInsert);
+ }
+
+ popupGroup.addSeparator("Bookmarks");
+ List<String> bookmarkNames = getNamesWithoutHashes(myRepository.getBookmarks());
+ String currentBookmark = myRepository.getCurrentBookmark();
+ for (String bookmark : bookmarkNames) {
+ AnAction bookmarkAction = new BookmarkActions(myProject, Collections.singletonList(myRepository), bookmark);
+ if (bookmark.equals(currentBookmark)) {
+ bookmarkAction.getTemplatePresentation().setIcon(PlatformIcons.CHECK_ICON);
+ }
+ popupGroup.add(bookmarkAction);
+ }
+
+ popupGroup.addSeparator("Branches");
+ List<String> branchNamesList = new ArrayList<String>(myRepository.getOpenedBranches());//only opened branches have to be shown
+ Collections.sort(branchNamesList);
+ for (String branch : branchNamesList) {
+ if (!branch.equals(myRepository.getCurrentBranch())) { // don't show current branch in the list
+ popupGroup.add(new HgCommonBranchActions(myProject, Collections.singletonList(myRepository), branch));
+ }
+ }
+ return popupGroup;
+ }
+
+ public static class HgNewBranchAction extends NewBranchAction<HgRepository> {
+ @NotNull final HgRepository myPreselectedRepo;
+
+ HgNewBranchAction(@NotNull Project project, @NotNull List<HgRepository> repositories, @NotNull HgRepository preselectedRepo) {
+ super(project, repositories);
+ myPreselectedRepo = preselectedRepo;
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ final String name = getNewBranchNameFromUser(myPreselectedRepo, "Create New Branch");
+ if (name == null) {
+ return;
+ }
+ for (final HgRepository repository : myRepositories) {
+ try {
+ new HgBranchCreateCommand(myProject, repository.getRoot(), name).execute(new HgCommandResultHandler() {
+ @Override
+ public void process(@Nullable HgCommandResult result) {
+ repository.update();
+ if (HgErrorUtil.hasErrorsInCommandExecution(result)) {
+ new HgCommandResultNotifier(myProject)
+ .notifyError(result, "Creation failed", "Branch creation [" + name + "] failed");
+ }
+ }
+ });
+ }
+ catch (HgCommandException exception) {
+ HgAbstractGlobalAction.handleException(myProject, "Can't create new branch: ", exception);
+ }
+ }
+ }
+ }
+
+ public static class HgNewBookmarkAction extends DumbAwareAction {
+ @NotNull protected final List<HgRepository> myRepositories;
+ @NotNull protected Project myProject;
+ @NotNull final HgRepository myPreselectedRepo;
+
+ HgNewBookmarkAction(@NotNull Project project, @NotNull List<HgRepository> repositories, @NotNull HgRepository preselectedRepo) {
+ super("New Bookmark", "Create new bookmark", null);
+ myProject = project;
+ myRepositories = repositories;
+ myPreselectedRepo = preselectedRepo;
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ if (DvcsUtil.anyRepositoryIsFresh(myRepositories)) {
+ e.getPresentation().setEnabled(false);
+ e.getPresentation().setDescription("Bookmark creation is not possible before the first commit.");
+ }
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+
+ final HgBookmarkDialog bookmarkDialog = new HgBookmarkDialog(myPreselectedRepo);
+ bookmarkDialog.show();
+ if (bookmarkDialog.isOK()) {
+ final String name = bookmarkDialog.getName();
+ for (HgRepository repository : myRepositories) {
+ try {
+ new HgBookmarkCommand(myProject, repository.getRoot(), name).createBookmark(bookmarkDialog.isActive());
+ }
+ catch (HgCommandException exception) {
+ HgAbstractGlobalAction.handleException(myProject, exception);
+ }
+ }
+ }
+ }
+ }
+
+ public static class HgShowUnnamedHeadsForCurrentBranchAction extends ActionGroup {
+ @NotNull final Project myProject;
+ @NotNull final HgRepository myRepository;
+ @NotNull final String myCurrentBranchName;
+ @NotNull Collection<Hash> myHeads = new HashSet<Hash>();
+
+ public HgShowUnnamedHeadsForCurrentBranchAction(@NotNull Project project,
+ @NotNull HgRepository repository) {
+ super(null, true);
+ myProject = project;
+ myRepository = repository;
+ myCurrentBranchName = repository.getCurrentBranch();
+ getTemplatePresentation().setText(String.format("Unnamed heads for %s", myCurrentBranchName));
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ myHeads = filterUnnamedHeads();
+ }
+ });
+ }
+
+ @NotNull
+ private Collection<Hash> filterUnnamedHeads() {
+ Collection<Hash> branchWithHashes = myRepository.getBranches().get(myCurrentBranchName);
+ if (branchWithHashes == null) {
+ // repository is fresh or branch is fresh.
+ return Collections.emptySet();
+ }
+ else {
+ List<HgRevisionNumber> parents = new HgWorkingCopyRevisionsCommand(myProject).parents(myRepository.getRoot());
+ if (parents.size() == 1) {
+ Collection<Hash> bookmarkHashes = ContainerUtil.map(myRepository.getBookmarks(), new Function<HgNameWithHashInfo, Hash>() {
+
+ @Override
+ public Hash fun(HgNameWithHashInfo info) {
+ return info.getHash();
+ }
+ });
+ branchWithHashes.removeAll(bookmarkHashes);
+ branchWithHashes.remove(HashImpl.build(parents.get(0).getChangeset()));
+ }
+ }
+ return branchWithHashes;
+ }
+
+ @NotNull
+ @Override
+ public AnAction[] getChildren(@Nullable AnActionEvent e) {
+ List<AnAction> branchHeadActions = new ArrayList<AnAction>();
+ for (Hash hash : myHeads) {
+ branchHeadActions.add(new HgCommonBranchActions(myProject, Collections.singletonList(myRepository), hash.toShortString()));
+ }
+ return ContainerUtil.toArray(branchHeadActions, new AnAction[branchHeadActions.size()]);
+ }
+
+ @Override
+ public void update(final AnActionEvent e) {
+ if (myRepository.isFresh()) {
+ e.getPresentation().setEnabled(false);
+ e.getPresentation().setDescription("Checkout of a new branch is not possible before the first commit.");
+ }
+ else if (!Repository.State.NORMAL.equals(myRepository.getState())) {
+ e.getPresentation().setEnabled(false);
+ }
+ }
+ }
+
+ /**
+ * Actions available for bookmarks.
+ */
+ static class BookmarkActions extends HgCommonBranchActions {
+
+ BookmarkActions(@NotNull Project project, @NotNull List<HgRepository> repositories, @NotNull String branchName) {
+ super(project, repositories, branchName);
+ }
+
+ @NotNull
+ @Override
+ public AnAction[] getChildren(@Nullable AnActionEvent e) {
+ return ArrayUtil.append(super.getChildren(e), new DeleteBookmarkAction(myProject, myRepositories, myBranchName));
+ }
+
+ private static class DeleteBookmarkAction extends HgBranchAbstractAction {
+
+ DeleteBookmarkAction(@NotNull Project project, @NotNull List<HgRepository> repositories, @NotNull String branchName) {
+ super(project, "Delete", repositories, branchName);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ for (HgRepository repository : myRepositories) {
+ try {
+ new HgBookmarkCommand(myProject, repository.getRoot(), myBranchName).deleteBookmark();
+ }
+ catch (HgCommandException exception) {
+ HgAbstractGlobalAction.handleException(myProject, exception);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchUtil.java
new file mode 100644
index 000000000000..9dbdd3ea7f65
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchUtil.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2014 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 org.zmlx.hg4idea.branch;
+
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.vcs.log.Hash;
+import org.jetbrains.annotations.NotNull;
+import org.zmlx.hg4idea.HgNameWithHashInfo;
+import org.zmlx.hg4idea.repo.HgRepository;
+import org.zmlx.hg4idea.util.HgUtil;
+
+import java.util.*;
+
+public class HgBranchUtil {
+
+ /**
+ * Only common hg heavy branches
+ */
+ @NotNull
+ public static Collection<String> getCommonBranches(@NotNull Collection<HgRepository> repositories) {
+ Collection<String> commonBranches = null;
+ for (HgRepository repository : repositories) {
+ Map<String, Set<Hash>> branchesWithHashes = repository.getBranches();
+ Collection<String> names = branchesWithHashes.keySet();
+ if (commonBranches == null) {
+ commonBranches = names;
+ }
+ else {
+ commonBranches = ContainerUtil.intersection(commonBranches, names);
+ }
+ }
+ if (commonBranches != null) {
+ ArrayList<String> common = new ArrayList<String>(commonBranches);
+ Collections.sort(common);
+ return common;
+ }
+ else {
+ return Collections.emptyList();
+ }
+ }
+
+ @NotNull
+ public static Collection<String> getCommonBookmarks(@NotNull Collection<HgRepository> repositories) {
+ Collection<String> commonBookmarkNames = null;
+ for (HgRepository repository : repositories) {
+ Collection<HgNameWithHashInfo> bookmarksInfo = repository.getBookmarks();
+ Collection<String> names = HgUtil.getNamesWithoutHashes(bookmarksInfo);
+ if (commonBookmarkNames == null) {
+ commonBookmarkNames = names;
+ }
+ else {
+ commonBookmarkNames = ContainerUtil.intersection(commonBookmarkNames, names);
+ }
+ }
+ if (commonBookmarkNames != null) {
+ ArrayList<String> common = new ArrayList<String>(commonBookmarkNames);
+ Collections.sort(common);
+ return common;
+ }
+ else {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchesAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchesAction.java
new file mode 100644
index 000000000000..b078da12548f
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchesAction.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2013 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 org.zmlx.hg4idea.branch;
+
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.zmlx.hg4idea.action.HgAbstractGlobalSingleRepoAction;
+import org.zmlx.hg4idea.repo.HgRepository;
+
+import java.util.Collection;
+
+public class HgBranchesAction extends HgAbstractGlobalSingleRepoAction {
+
+ @Override
+ protected void execute(@NotNull Project project, @NotNull Collection<HgRepository> repositories, @Nullable HgRepository selectedRepo) {
+ if (selectedRepo != null) {
+ HgBranchPopup.getInstance(project, selectedRepo).asListPopup().showInFocusCenter();
+ }
+ }
+}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgCommonBranchActions.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgCommonBranchActions.java
new file mode 100644
index 000000000000..ecba99f7b532
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgCommonBranchActions.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2000-2014 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 org.zmlx.hg4idea.branch;
+
+import com.intellij.openapi.actionSystem.ActionGroup;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.openapi.vcs.VcsNotifier;
+import com.intellij.openapi.vcs.update.UpdatedFiles;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.zmlx.hg4idea.HgVcs;
+import org.zmlx.hg4idea.HgVcsMessages;
+import org.zmlx.hg4idea.action.HgAbstractGlobalAction;
+import org.zmlx.hg4idea.action.HgCommandResultNotifier;
+import org.zmlx.hg4idea.command.HgMergeCommand;
+import org.zmlx.hg4idea.command.HgUpdateCommand;
+import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.provider.update.HgConflictResolver;
+import org.zmlx.hg4idea.provider.update.HgHeadMerger;
+import org.zmlx.hg4idea.repo.HgRepository;
+import org.zmlx.hg4idea.util.HgErrorUtil;
+
+import java.util.List;
+
+public class HgCommonBranchActions extends ActionGroup {
+
+ @NotNull protected final Project myProject;
+ @NotNull protected String myBranchName;
+ @NotNull List<HgRepository> myRepositories;
+
+ HgCommonBranchActions(@NotNull Project project, @NotNull List<HgRepository> repositories, @NotNull String branchName) {
+ super("", true);
+ myProject = project;
+ myBranchName = branchName;
+ myRepositories = repositories;
+ getTemplatePresentation().setText(myBranchName, false); // no mnemonics
+ }
+
+ @NotNull
+ @Override
+ public AnAction[] getChildren(@Nullable AnActionEvent e) {
+ return new AnAction[]{
+ new UpdateAction(myProject, myRepositories, myBranchName),
+ new MergeAction(myProject, myRepositories, myBranchName)
+ };
+ }
+
+ private static class MergeAction extends HgBranchAbstractAction {
+
+ public MergeAction(@NotNull Project project,
+ @NotNull List<HgRepository> repositories,
+ @NotNull String branchName) {
+ super(project, "Merge", repositories, branchName);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ FileDocumentManager.getInstance().saveAllDocuments();
+ final UpdatedFiles updatedFiles = UpdatedFiles.create();
+ for (final HgRepository repository : myRepositories) {
+ final HgMergeCommand hgMergeCommand = new HgMergeCommand(myProject, repository.getRoot());
+ hgMergeCommand.setRevision(myBranchName);//there is no difference between branch or revision or bookmark as parameter to merge,
+ // we need just a string
+ new Task.Backgroundable(myProject, "Merging changes...") {
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ try {
+ new HgHeadMerger(myProject, hgMergeCommand)
+ .merge(repository.getRoot());
+ new HgConflictResolver(myProject, updatedFiles).resolve(repository.getRoot());
+ }
+
+ catch (VcsException exception) {
+ assert myProject != null; // myProject couldn't be null, see annotation for Merge action
+ if (exception.isWarning()) {
+ VcsNotifier.getInstance(myProject).notifyWarning("Warning during merge", exception.getMessage());
+ }
+ else {
+ VcsNotifier.getInstance(myProject).notifyError("Exception during merge", exception.getMessage());
+ }
+ }
+ catch (Exception e1) {
+ HgAbstractGlobalAction.handleException(myProject, e1);
+ }
+ }
+ }.queue();
+ }
+ }
+ }
+
+ private static class UpdateAction extends HgBranchAbstractAction {
+
+ public UpdateAction(@NotNull Project project,
+ @NotNull List<HgRepository> repositories,
+ @NotNull String branchName) {
+ super(project, "Update", repositories, branchName);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ FileDocumentManager.getInstance().saveAllDocuments();
+ for (HgRepository repo : myRepositories) {
+ final VirtualFile repository = repo.getRoot();
+ final HgUpdateCommand hgUpdateCommand = new HgUpdateCommand(myProject, repository);
+ hgUpdateCommand.setBranch(myBranchName);
+ new Task.Backgroundable(myProject, HgVcsMessages.message("action.hg4idea.updateTo.description", myBranchName)) {
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ HgCommandResult result = hgUpdateCommand.execute();
+ assert myProject != null; // myProject couldn't be null, see annotation for updateTo action
+ if (HgErrorUtil.hasErrorsInCommandExecution(result)) {
+ new HgCommandResultNotifier(myProject).notifyError(result, "", "Update failed");
+ new HgConflictResolver(myProject).resolve(repository);
+ }
+ myProject.getMessageBus().syncPublisher(HgVcs.BRANCH_TOPIC).update(myProject, repository);
+ }
+ }.queue();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgMultiRootBranchConfig.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgMultiRootBranchConfig.java
new file mode 100644
index 000000000000..e762fb8992ab
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgMultiRootBranchConfig.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2014 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 org.zmlx.hg4idea.branch;
+
+import com.intellij.dvcs.branch.DvcsMultiRootBranchConfig;
+import org.jetbrains.annotations.NotNull;
+import org.zmlx.hg4idea.repo.HgRepository;
+
+import java.util.Collection;
+
+public class HgMultiRootBranchConfig extends DvcsMultiRootBranchConfig<HgRepository> {
+
+ public HgMultiRootBranchConfig(@NotNull Collection<HgRepository> repositories) {
+ super(repositories);
+ }
+
+ @NotNull
+ @Override
+ public Collection<String> getLocalBranchNames() {
+ return HgBranchUtil.getCommonBranches(myRepositories);
+ }
+
+ @NotNull
+ Collection<String> getBookmarkNames() {
+ return HgBranchUtil.getCommonBookmarks(myRepositories);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (HgRepository repository : myRepositories) {
+ sb.append(repository.getPresentableUrl()).append(":").append(repository.getCurrentBranchName()).append(":")
+ .append(repository.getState());
+ }
+ return sb.toString();
+ }
+}