diff --git a/platform/dvcs-api/src/com/intellij/dvcs/push/PushTarget.java b/platform/dvcs-api/src/com/intellij/dvcs/push/PushTarget.java
index df6bfaefa79b..8d99a0fa0145 100644
--- a/platform/dvcs-api/src/com/intellij/dvcs/push/PushTarget.java
+++ b/platform/dvcs-api/src/com/intellij/dvcs/push/PushTarget.java
@@ -20,4 +20,12 @@ package com.intellij.dvcs.push;
*/
public interface PushTarget {
+ /**
+ * Returns true if pushing to this target is guaranteed to introduce something new: e.g. new branch or tag.
+ *
+ * Returning false doesn't mean that this target has nothing to push (e.g. commits to push are calculated separately),
+ * it means rather that "we don't know".
+ */
+ boolean hasSomethingToPush();
+
}
diff --git a/platform/dvcs-api/src/com/intellij/dvcs/repo/RepositoryManager.java b/platform/dvcs-api/src/com/intellij/dvcs/repo/RepositoryManager.java
index d27694cd05d0..d5413283309f 100644
--- a/platform/dvcs-api/src/com/intellij/dvcs/repo/RepositoryManager.java
+++ b/platform/dvcs-api/src/com/intellij/dvcs/repo/RepositoryManager.java
@@ -66,4 +66,10 @@ public interface RepositoryManager {
void updateAllRepositories();
void waitUntilInitialized();
+
+ /**
+ * Returns true if repositories under this repository manager are controlled synchronously.
+ */
+ boolean isSyncEnabled();
+
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java
index 395ab3a7ce85..efb078622bc1 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java
@@ -18,19 +18,18 @@ package com.intellij.dvcs.push;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.dvcs.push.ui.*;
import com.intellij.dvcs.repo.Repository;
+import com.intellij.dvcs.repo.RepositoryManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.ui.CheckedTreeNode;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.containers.hash.HashMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.VcsFullCommitDetails;
import org.jetbrains.annotations.NotNull;
@@ -45,6 +44,7 @@ import java.util.concurrent.atomic.AtomicReference;
public class PushController implements Disposable {
@NotNull private final Project myProject;
+ @NotNull private final List extends Repository> myPreselectedRepositories;
@NotNull private final List> myPushSupports;
@NotNull private final PushLog myPushLog;
@NotNull private final VcsPushDialog myDialog;
@@ -59,16 +59,15 @@ public class PushController implements Disposable {
@NotNull VcsPushDialog dialog,
@NotNull List extends Repository> preselectedRepositories) {
myProject = project;
+ myPreselectedRepositories = preselectedRepositories;
myPushSupports = getAffectedSupports(myProject);
mySingleRepoProject = isSingleRepoProject(myPushSupports);
CheckedTreeNode rootNode = new CheckedTreeNode(null);
- createTreeModel(rootNode, preselectedRepositories);
+ createTreeModel(rootNode);
myPushLog = new PushLog(myProject, rootNode);
myDialog = dialog;
- myDialog.updateButtons();
startLoadingCommits();
Disposer.register(dialog.getDisposable(), this);
- selectFirstChecked();
}
private static boolean isSingleRepoProject(@NotNull List> pushSupports) {
@@ -107,39 +106,13 @@ public class PushController implements Disposable {
});
}
- private void selectFirstChecked() {
- Map.Entry selected =
- ContainerUtil.find(myView2Model.entrySet(), new Condition>() {
- @Override
- public boolean value(Map.Entry entry) {
- return entry.getValue().isSelected();
- }
- });
- if (selected != null) {
- myPushLog.selectNode(selected.getKey());
- }
- }
-
- @Nullable
- public ValidationInfo validate() {
- ValidationInfo validInfo = new ValidationInfo("There are no selected repository to push!");
- for (Map.Entry entry : myView2Model.entrySet()) {
- MyRepoModel model = entry.getValue();
- if (model.isSelected()) {
- if (model.hasError()) return new ValidationInfo(model.getError().getText());
- validInfo = null;
- }
- }
- return validInfo;
- }
-
private void startLoadingCommits() {
//todo should be reworked
- Map priorityLoading = new HashMap();
- Map others = new HashMap();
+ Map priorityLoading = ContainerUtil.newLinkedHashMap();
+ Map others = ContainerUtil.newLinkedHashMap();
for (Map.Entry entry : myView2Model.entrySet()) {
MyRepoModel model = entry.getValue();
- if (model.isSelected()) {
+ if (myPreselectedRepositories.contains(model.getRepository())) {
priorityLoading.put(entry.getKey(), model);
}
else if (model.getSupport().shouldRequestIncomingChangesForNotCheckedRepositories()) {
@@ -157,30 +130,27 @@ public class PushController implements Disposable {
}
}
- private void createTreeModel(@NotNull CheckedTreeNode rootNode, @NotNull List extends Repository> preselectedRepositories) {
+ private void createTreeModel(@NotNull CheckedTreeNode rootNode) {
for (PushSupport extends Repository, ? extends PushSource, ? extends PushTarget> support : myPushSupports) {
- createNodesForVcs(support, rootNode, preselectedRepositories);
+ createNodesForVcs(support, rootNode);
}
}
private void createNodesForVcs(
- @NotNull PushSupport pushSupport,
- @NotNull CheckedTreeNode rootNode,
- @NotNull List extends Repository> preselectedRepositories)
+ @NotNull PushSupport pushSupport, @NotNull CheckedTreeNode rootNode)
{
for (R repository : pushSupport.getRepositoryManager().getRepositories()) {
- createRepoNode(pushSupport, repository, rootNode, preselectedRepositories.contains(repository));
+ createRepoNode(pushSupport, repository, rootNode);
}
}
private void createRepoNode(@NotNull final PushSupport support,
@NotNull final R repository,
- @NotNull CheckedTreeNode rootNode,
- boolean isSelected) {
+ @NotNull CheckedTreeNode rootNode) {
T target = support.getDefaultTarget(repository);
String repoName = DvcsUtil.getShortRepositoryName(repository);
S source = support.getSource(repository);
- final MyRepoModel model = new MyRepoModel(repository, support, mySingleRepoProject || isSelected,
+ final MyRepoModel model = new MyRepoModel(repository, support, mySingleRepoProject,
source, target,
DEFAULT_CHILDREN_PRESENTATION_NUMBER);
if (target == null) {
@@ -191,12 +161,13 @@ public class PushController implements Disposable {
source.getPresentation(), pushTargetPanel);
final RepositoryNode repoNode = mySingleRepoProject
? new SingleRepositoryNode(repoPanel)
- : new RepositoryNode(repoPanel);
+ : new RepositoryNode(repoPanel, target != null);
myView2Model.put(repoNode, model);
- repoNode.setChecked(model.isSelected());
repoPanel.addRepoNodeListener(new RepositoryNodeListener() {
@Override
public void onTargetChanged(T newTarget) {
+ model.setSelected(true);
+ repoNode.setChecked(true);
model.setTarget(newTarget);
model.clearErrors();
loadCommits(model, repoNode, false);
@@ -216,27 +187,78 @@ public class PushController implements Disposable {
rootNode.add(repoNode);
}
+ public boolean isPushAllowed() {
+ return ContainerUtil.exists(myPushSupports, new Condition>() {
+ @Override
+ public boolean value(PushSupport, ?, ?> support) {
+ return isPushAllowed(support);
+ }
+ });
+ }
+
+ private boolean isPushAllowed(@NotNull PushSupport, ?, ?> pushSupport) {
+ Collection nodes = getNodesForSupport(pushSupport);
+ if (pushSupport.getRepositoryManager().isSyncEnabled()) {
+ return hasCheckedNode(nodes) && allNodesAreLoaded(nodes);
+ }
+ return hasCheckedNode(nodes);
+ }
+
+ private static boolean allNodesAreLoaded(@NotNull Collection nodes) {
+ return !ContainerUtil.exists(nodes, new Condition() {
+ @Override
+ public boolean value(@NotNull RepositoryNode node) {
+ return node.isLoading();
+ }
+ });
+ }
+
+ private static boolean hasCheckedNode(@NotNull Collection nodes) {
+ return ContainerUtil.exists(nodes, new Condition() {
+ @Override
+ public boolean value(@NotNull RepositoryNode node) {
+ return node.isChecked();
+ }
+ });
+ }
+
+ @NotNull
+ private Collection getNodesForSupport(final PushSupport, ?, ?> support) {
+ return ContainerUtil.mapNotNull(myView2Model.entrySet(), new Function, RepositoryNode>() {
+ @Override
+ public RepositoryNode fun(Map.Entry entry) {
+ return entry.getValue().getSupport().equals(support) ? entry.getKey() : null;
+ }
+ });
+ }
+
private void loadCommits(@NotNull final MyRepoModel model,
@NotNull final RepositoryNode node,
final boolean initial) {
- node.stopLoading();
+ node.cancelLoading();
final T target = model.getTarget();
- if (target == null) return; //todo should be removed when commit loader executor will be modified
- myPushLog.startLoading(node);
+ if (target == null) {
+ node.stopLoading();
+ return;
+ }
+ node.setEnabled(true);
final PushSupport support = model.getSupport();
final AtomicReference result = new AtomicReference();
Runnable task = new Runnable() {
@Override
public void run() {
+ final R repository = model.getRepository();
OutgoingResult outgoing = support.getOutgoingCommitsProvider()
- .getOutgoingCommits(model.getRepository(), new PushSpec(model.getSource(), model.getTarget()), initial);
+ .getOutgoingCommits(repository, new PushSpec(model.getSource(), model.getTarget()), initial);
result.compareAndSet(null, outgoing);
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
OutgoingResult outgoing = result.get();
List errors = outgoing.getErrors();
+ boolean shouldBeSelected;
if (!errors.isEmpty()) {
+ shouldBeSelected = false;
myPushLog.setChildren(node, ContainerUtil.map(errors, new Function() {
@Override
public DefaultMutableTreeNode fun(final VcsError error) {
@@ -256,16 +278,38 @@ public class PushController implements Disposable {
}));
}
else {
- model.setLoadedCommits(outgoing.getCommits());
+ List extends VcsFullCommitDetails> commits = outgoing.getCommits();
+ shouldBeSelected = shouldSelectInitially(target, repository, model.getSupport().getRepositoryManager(), !commits.isEmpty());
+ model.setLoadedCommits(commits);
myPushLog.setChildren(node,
getPresentationForCommits(PushController.this.myProject, model.getLoadedCommits(),
model.getNumberOfShownCommits()));
}
+ node.stopLoading();
+ if (shouldBeSelected) { // never remove selection; initially all checkboxes are not selected
+ node.setChecked(true);
+ }
+ node.fireOnSelectionChange(shouldBeSelected);
}
});
}
};
- node.startLoading(myExecutorService.submit(task, result));
+ node.startLoading(myPushLog.getTree(), myExecutorService.submit(task, result));
+ }
+
+ private boolean shouldSelectInitially(@NotNull PushTarget target, @NotNull Repository repository,
+ @NotNull RepositoryManager repositoryManager, boolean hasCommits) {
+ boolean shouldBeSelected;
+ if (mySingleRepoProject) {
+ shouldBeSelected = true;
+ }
+ else if (repositoryManager.isSyncEnabled()) {
+ shouldBeSelected = hasCommits || target.hasSomethingToPush();
+ }
+ else {
+ shouldBeSelected = (hasCommits || target.hasSomethingToPush()) && myPreselectedRepositories.contains(repository);
+ }
+ return shouldBeSelected;
}
public PushLog getPushPanelLog() {
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java
index aab70818082d..cdc762bca518 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java
@@ -18,6 +18,7 @@ package com.intellij.dvcs.push.ui;
import com.intellij.dvcs.push.OutgoingResult;
import org.jetbrains.annotations.NotNull;
+import javax.swing.*;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
@@ -29,7 +30,7 @@ public interface EditableTreeNode extends CustomRenderedTreeNode {
void fireOnSelectionChange(boolean isSelected);
- void stopLoading();
+ void cancelLoading();
- void startLoading(@NotNull Future> future);
+ void startLoading(@NotNull JTree tree, @NotNull Future> future);
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/LoadingTreeNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/LoadingTreeNode.java
index 67ab197c1543..36958a00c64b 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/LoadingTreeNode.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/LoadingTreeNode.java
@@ -20,27 +20,29 @@ import com.intellij.ui.JBColor;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.ImageLoader;
import com.intellij.util.ui.JBImageIcon;
+import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
-import java.net.URL;
+import java.awt.image.BufferedImage;
public class LoadingTreeNode extends DefaultMutableTreeNode implements CustomRenderedTreeNode {
- @NotNull protected ImageIcon myLoadingIcon;
- private static final String LOADING_ICON = "/icons/loading.gif";
- @NotNull
- public ImageIcon getIcon() {
- return myLoadingIcon;
- }
+ private static final String LOADING_ICON = "/icons/loading.gif";
+ private static final JBImageIcon EMPTY_ICON = new JBImageIcon(UIUtil.createImage(18, 18, BufferedImage.TYPE_3BYTE_BGR));
+ @NotNull private ImageIcon myLoadingIcon;
public LoadingTreeNode() {
super(null, false);
- URL loadingIconUrl = getClass().getResource(LOADING_ICON);
- Image image = ImageLoader.loadFromUrl(loadingIconUrl);
- myLoadingIcon = new JBImageIcon(image);
+ myLoadingIcon = getLoadingIcon();
+ }
+
+ @NotNull
+ public static JBImageIcon getLoadingIcon() {
+ Image image = ImageLoader.loadFromResource(LOADING_ICON);
+ return image == null ? EMPTY_ICON : new JBImageIcon(image);
}
@Override
@@ -50,4 +52,9 @@ public class LoadingTreeNode extends DefaultMutableTreeNode implements CustomRen
renderer.setIconOnTheRight(false);
renderer.append("Loading Commits...", new SimpleTextAttributes(SimpleTextAttributes.STYLE_SMALLER, JBColor.GRAY));
}
+
+ @NotNull
+ public ImageIcon getIcon() {
+ return myLoadingIcon;
+ }
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java
index a3853e3b25aa..370217b9894c 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java
@@ -242,13 +242,12 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
return super.processKeyBinding(ks, e, condition, pressed);
}
- public void startLoading(DefaultMutableTreeNode parentNode) {
- LoadingTreeNode loading = new LoadingTreeNode();
- loading.getIcon().setImageObserver(new NodeImageObserver(myTree, loading));
- setChildren(parentNode, Collections.singleton(loading));
+ public JComponent getPreferredFocusedComponent() {
+ return myTree;
}
- public JComponent getPreferredFocusedComponent() {
+ @NotNull
+ public JTree getTree() {
return myTree;
}
@@ -341,9 +340,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
if (node.getChildCount() <= 0) return;
if (node instanceof RepositoryNode) {
TreePath path = TreeUtil.getPathFromRoot(node);
- if (((RepositoryNode)node).isChecked()) {
- myTree.expandPath(path);
- }
+ myTree.expandPath(path);
return;
}
for (DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)node.getFirstChild();
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java
index 4808064f5c8d..be57fee704c1 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java
@@ -21,31 +21,48 @@ import com.intellij.ui.CheckedTreeNode;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode, Comparable {
- @NotNull private final RepositoryWithBranchPanel myRepositoryPanel;
- private Future> myFuture;
- public RepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel) {
+ private static final int CHECKBOX_WIDTH = new JCheckBox().getPreferredSize().width;
+
+ @NotNull protected final ImageIcon myLoadingIcon;
+ @NotNull protected final AtomicBoolean myLoading = new AtomicBoolean(true);
+
+ @NotNull private final RepositoryWithBranchPanel myRepositoryPanel;
+ @Nullable private Future> myFuture;
+
+ public RepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel, boolean enabled) {
super(repositoryPanel);
+ setChecked(false);
+ setEnabled(enabled);
myRepositoryPanel = repositoryPanel;
+ myLoadingIcon = LoadingTreeNode.getLoadingIcon();
}
public boolean isCheckboxVisible() {
- return true;
+ return !myLoading.get();
}
@Override
public void render(@NotNull ColoredTreeCellRenderer renderer) {
- String repositoryPath = myRepositoryPanel.getRepositoryName();
- renderer.append(repositoryPath, SimpleTextAttributes.GRAY_ATTRIBUTES);
- renderer.appendFixedTextFragmentWidth(120);
+ int repoFixedWidth = 120;
+ if (myLoading.get()) {
+ renderer.setIcon(myLoadingIcon);
+ renderer.setIconOnTheRight(false);
+ renderer.setIconTextGap(CHECKBOX_WIDTH - myLoadingIcon.getIconWidth());
+ repoFixedWidth += CHECKBOX_WIDTH;
+ }
+ renderer.append(myRepositoryPanel.getRepositoryName(), SimpleTextAttributes.GRAY_ATTRIBUTES);
+ renderer.appendFixedTextFragmentWidth(repoFixedWidth);
renderer.append(myRepositoryPanel.getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
renderer.append(myRepositoryPanel.getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel();
@@ -75,15 +92,17 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode,
}
@Override
- public void stopLoading() {
+ public void cancelLoading() {
if (myFuture != null && !myFuture.isDone()) {
myFuture.cancel(true);
}
}
@Override
- public void startLoading(@NotNull Future> future) {
+ public void startLoading(@NotNull JTree tree, @NotNull Future> future) {
myFuture = future;
+ myLoading.set(true);
+ myLoadingIcon.setImageObserver(new NodeImageObserver(tree, this));
}
public int compareTo(@NotNull RepositoryNode repositoryNode) {
@@ -91,4 +110,13 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode,
RepositoryWithBranchPanel panel = (RepositoryWithBranchPanel)repositoryNode.getUserObject();
return name.compareTo(panel.getRepositoryName());
}
+
+ public void stopLoading() {
+ myLoading.set(false);
+ }
+
+ public boolean isLoading() {
+ return myLoading.get();
+ }
+
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java
index 3f5ab8d17496..65fecd19e010 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java
@@ -18,7 +18,6 @@ package com.intellij.dvcs.push.ui;
import com.intellij.dvcs.push.PushTargetPanel;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
-import com.intellij.util.ui.EmptyIcon;
import org.jetbrains.annotations.NotNull;
public class SingleRepositoryNode extends RepositoryNode {
@@ -26,7 +25,7 @@ public class SingleRepositoryNode extends RepositoryNode {
@NotNull private final RepositoryWithBranchPanel myRepositoryPanel;
public SingleRepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel) {
- super(repositoryPanel);
+ super(repositoryPanel, true);
myRepositoryPanel = repositoryPanel;
}
@@ -37,13 +36,14 @@ public class SingleRepositoryNode extends RepositoryNode {
@Override
public void render(@NotNull ColoredTreeCellRenderer renderer) {
+ if (myLoading.get()) {
+ renderer.setIcon(myLoadingIcon);
+ renderer.setIconOnTheRight(false);
+ }
+
renderer.append(myRepositoryPanel.getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
renderer.append(myRepositoryPanel.getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel();
pushTargetPanel.render(renderer);
-
- // hack to fix vertical size of the editor
- renderer.setIcon(EmptyIcon.ICON_18);
- renderer.setIconOnTheRight(true);
}
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsPushDialog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsPushDialog.java
index 86bec903b32b..42287266c161 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsPushDialog.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsPushDialog.java
@@ -16,13 +16,15 @@
package com.intellij.dvcs.push.ui;
import com.intellij.CommonBundle;
-import com.intellij.dvcs.push.*;
+import com.intellij.dvcs.push.PushController;
+import com.intellij.dvcs.push.PushSupport;
+import com.intellij.dvcs.push.VcsPushOptionValue;
+import com.intellij.dvcs.push.VcsPushOptionsPanel;
import com.intellij.dvcs.repo.Repository;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.OptionAction;
-import com.intellij.openapi.ui.ValidationInfo;
import net.miginfocom.swing.MigLayout;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -54,6 +56,7 @@ public class VcsPushDialog extends DialogWrapper {
myListPanel = myController.getPushPanelLog();
init();
+ updateButtons();
setOKButtonText("Push");
setOKButtonMnemonic('P');
setTitle("Push Dialog");
@@ -107,27 +110,17 @@ public class VcsPushDialog extends DialogWrapper {
return myPushAction;
}
- @Nullable
- @Override
- protected ValidationInfo doValidate() {
- return myController.validate();
- }
-
@Override
protected String getHelpId() {
return "reference.mercurial.push.dialog";
}
public void updateButtons() {
+ boolean pushAllowed = myController.isPushAllowed();
+ myPushAction.setEnabled(pushAllowed);
if (myForcePushAction != null) {
- myForcePushAction.setEnabled(myController.isForcePushAllowed());
+ myForcePushAction.setEnabled(pushAllowed && myController.isForcePushAllowed());
}
- initValidation();
- }
-
- @Override
- protected boolean postponeValidation() {
- return false;
}
@Nullable
diff --git a/plugins/git4idea/src/git4idea/actions/GitPushAction.java b/plugins/git4idea/src/git4idea/actions/GitPushAction.java
index d8c478076f00..04e139fa8934 100644
--- a/plugins/git4idea/src/git4idea/actions/GitPushAction.java
+++ b/plugins/git4idea/src/git4idea/actions/GitPushAction.java
@@ -15,7 +15,6 @@
*/
package git4idea.actions;
-import com.intellij.dvcs.branch.DvcsSyncSettings;
import com.intellij.dvcs.push.ui.VcsPushDialog;
import com.intellij.dvcs.repo.RepositoryUtil;
import com.intellij.openapi.actionSystem.AnActionEvent;
@@ -26,55 +25,41 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import git4idea.GitUtil;
import git4idea.branch.GitBranchUtil;
-import git4idea.config.GitVcsSettings;
import git4idea.repo.GitRepository;
import git4idea.repo.GitRepositoryManager;
-import git4idea.ui.branch.GitMultiRootBranchConfig;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
-import java.util.List;
public class GitPushAction extends DumbAwareAction {
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getRequiredData(CommonDataKeys.PROJECT);
Collection repositories = collectRepositories(project, e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY));
-
new VcsPushDialog(project, RepositoryUtil.sortRepositories(repositories)).show();
}
@NotNull
private static Collection collectRepositories(@NotNull Project project, @Nullable VirtualFile[] files) {
+ if (files == null) {
+ return Collections.singletonList(GitBranchUtil.getCurrentRepository(project));
+ }
GitRepositoryManager manager = GitUtil.getRepositoryManager(project);
- Collection repositories;
- if (GitVcsSettings.getInstance(project).getSyncSetting() == DvcsSyncSettings.Value.SYNC && !diverged(manager.getRepositories())) {
- repositories = manager.getRepositories();
- }
- else if (files == null) {
- repositories = Collections.singletonList(GitBranchUtil.getCurrentRepository(project));
- }
- else {
- repositories = ContainerUtil.newHashSet();
- for (VirtualFile file : files) {
- GitRepository repo = manager.getRepositoryForFile(file);
- if (repo != null) {
- repositories.add(repo);
- }
+ Collection repositories = ContainerUtil.newHashSet();
+ for (VirtualFile file : files) {
+ GitRepository repo = manager.getRepositoryForFile(file);
+ if (repo != null) {
+ repositories.add(repo);
}
}
return repositories;
}
- private static boolean diverged(List repositories) {
- return new GitMultiRootBranchConfig(repositories).diverged();
- }
-
@Override
- public void update(AnActionEvent e) {
+ public void update(@NotNull AnActionEvent e) {
super.update(e);
Project project = e.getProject();
e.getPresentation().setEnabledAndVisible(project != null && !GitUtil.getRepositoryManager(project).getRepositories().isEmpty());
diff --git a/plugins/git4idea/src/git4idea/push/GitPushTarget.java b/plugins/git4idea/src/git4idea/push/GitPushTarget.java
index 084eabbad826..032f98169cb4 100644
--- a/plugins/git4idea/src/git4idea/push/GitPushTarget.java
+++ b/plugins/git4idea/src/git4idea/push/GitPushTarget.java
@@ -49,13 +49,22 @@ class GitPushTarget implements PushTarget {
return myRemoteBranch;
}
+ @Override
+ public boolean hasSomethingToPush() {
+ return isNewBranchCreated();
+ }
+
boolean isNewBranchCreated() {
return myIsNewBranchCreated;
}
@NotNull
- static GitPushTarget parse(@NotNull GitRepository repository, @NotNull String remoteName, @NotNull String branchName) throws
+ static GitPushTarget parse(@NotNull GitRepository repository, @Nullable String remoteName, @NotNull String branchName) throws
ParseException {
+ if (remoteName == null) {
+ throw new ParseException("No remotes defined", -1);
+ }
+
if (!GitRefNameValidator.getInstance().checkInput(branchName)) {
throw new ParseException("Invalid destination branch name: " + branchName, -1);
}
diff --git a/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java b/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java
index aa8ce0b54287..a09262c351a7 100644
--- a/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java
+++ b/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java
@@ -52,6 +52,7 @@ class GitPushTargetPanel extends PushTargetPanel {
private static final Comparator REMOTE_BRANCH_COMPARATOR = new MyRemoteBranchComparator();
public static final String SEPARATOR = " \u25BE ";
+ public static final String NO_REMOTES = "No remotes" + SEPARATOR;
private final GitRepository myRepository;
private final PushTargetTextField myTargetTextField;
@@ -69,7 +70,7 @@ class GitPushTargetPanel extends PushTargetPanel {
if (defaultTarget == null) {
// TODO
initialBranch = "";
- initialRemote = "No remotes";
+ initialRemote = NO_REMOTES;
}
else {
initialBranch = getTextFieldText(defaultTarget);
@@ -150,7 +151,7 @@ class GitPushTargetPanel extends PushTargetPanel {
@Override
public void fireOnChange() {
- String remoteName = myRemoteLabel.getText().replace(SEPARATOR, "");
+ String remoteName = getEnteredRemote();
String branchName = myTargetTextField.getText();
try {
myCurrentTarget = GitPushTarget.parse(myRepository, remoteName, branchName);
@@ -164,7 +165,7 @@ class GitPushTargetPanel extends PushTargetPanel {
@Override
public ValidationInfo verify() {
try {
- String remoteLabel = myRemoteLabel.getText().replace(SEPARATOR, "");
+ String remoteLabel = getEnteredRemote();
GitPushTarget.parse(myRepository, remoteLabel, myTargetTextField.getText());
return null;
}
@@ -173,6 +174,12 @@ class GitPushTargetPanel extends PushTargetPanel {
}
}
+ @Nullable
+ private String getEnteredRemote() {
+ String text = myRemoteLabel.getText();
+ return text.equals(NO_REMOTES) ? null : text.replace(SEPARATOR, "");
+ }
+
@NotNull
public static List getTargetNames(@NotNull GitRepository repository) {
List remoteBranches = ContainerUtil.sorted(repository.getBranches().getRemoteBranches(), REMOTE_BRANCH_COMPARATOR);
diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java
index fb40b58045a2..10b9391ff1ab 100644
--- a/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java
+++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryManager.java
@@ -15,17 +15,16 @@
*/
package git4idea.repo;
+import com.intellij.dvcs.branch.DvcsSyncSettings;
import com.intellij.dvcs.repo.AbstractRepositoryManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.GitPlatformFacade;
import git4idea.GitUtil;
+import git4idea.ui.branch.GitMultiRootBranchConfig;
import org.jetbrains.annotations.NotNull;
-/**
- * @author Kirill Likhodedov
- */
public class GitRepositoryManager extends AbstractRepositoryManager {
@NotNull private final GitPlatformFacade myPlatformFacade;
@@ -41,5 +40,11 @@ public class GitRepositoryManager extends AbstractRepositoryManager {
private final List myRepositories = new ArrayList();
@@ -81,4 +78,8 @@ public class GitMockRepositoryManager implements RepositoryManager {
+ private final HgProjectSettings mySettings;
+
public HgRepositoryManager(@NotNull Project project,
@NotNull ProjectLevelVcsManager vcsManager) {
super(project, vcsManager, HgVcs.getInstance(project), HgUtil.DOT_HG);
+ mySettings = ObjectUtils.assertNotNull(HgVcs.getInstance(project)).getProjectSettings();
}
@NotNull
@@ -23,4 +30,10 @@ public class HgRepositoryManager extends AbstractRepositoryManager
protected HgRepository createRepository(@NotNull VirtualFile root) {
return HgRepositoryImpl.getInstance(root, myProject, this);
}
+
+ @Override
+ public boolean isSyncEnabled() {
+ return mySettings.getSyncSetting() == DvcsSyncSettings.Value.SYNC && !new HgMultiRootBranchConfig(getRepositories()).diverged();
+ }
+
}