summaryrefslogtreecommitdiff
path: root/platform/dvcs-impl/src/com/intellij/dvcs/push
diff options
context:
space:
mode:
Diffstat (limited to 'platform/dvcs-impl/src/com/intellij/dvcs/push')
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java184
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java4
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java53
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java53
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java30
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java9
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsFullCommitDetailsNode.java12
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsPushDialog.java25
8 files changed, 257 insertions, 113 deletions
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 2a409e12c854..45f5c68e1d0a 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java
@@ -29,8 +29,11 @@ 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.util.text.StringUtil;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.ui.CheckedTreeNode;
+import com.intellij.ui.SimpleColoredText;
+import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.hash.HashMap;
@@ -38,7 +41,6 @@ import com.intellij.vcs.log.VcsFullCommitDetails;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -48,15 +50,15 @@ import java.util.concurrent.atomic.AtomicReference;
public class PushController implements Disposable {
@NotNull private final Project myProject;
- @NotNull private final List<PushSupport<? extends Repository>> myPushSupports;
+ @NotNull private final List<PushSupport<? extends Repository, ? extends PushSource, ? extends PushTarget>> myPushSupports;
@NotNull private final PushLog myPushLog;
@NotNull private final VcsPushDialog myDialog;
private boolean mySingleRepoProject;
private static final int DEFAULT_CHILDREN_PRESENTATION_NUMBER = 20;
private final Map<PushSupport, MyPushOptionValueModel> myAdditionalValuesMap;
- private final Map<RepositoryNode, MyRepoModel> myView2Model = new HashMap<RepositoryNode, MyRepoModel>();
-
+ private final Map<RepositoryNode, MyRepoModel> myView2Model = new TreeMap<RepositoryNode, MyRepoModel>();
+ //todo need to sort repositories in ui tree using natural order
public PushController(@NotNull Project project,
@NotNull VcsPushDialog dialog,
@@ -72,6 +74,20 @@ public class PushController implements Disposable {
myDialog.updateButtons();
startLoadingCommits();
Disposer.register(dialog.getDisposable(), this);
+ selectFirstChecked();
+ }
+
+ private void selectFirstChecked() {
+ Map.Entry<RepositoryNode, MyRepoModel> selected =
+ ContainerUtil.find(myView2Model.entrySet(), new Condition<Map.Entry<RepositoryNode, MyRepoModel>>() {
+ @Override
+ public boolean value(Map.Entry<RepositoryNode, MyRepoModel> entry) {
+ return entry.getValue().isSelected();
+ }
+ });
+ if (selected != null) {
+ myPushLog.selectNode(selected.getKey());
+ }
}
@Nullable
@@ -80,16 +96,8 @@ public class PushController implements Disposable {
for (Map.Entry<RepositoryNode, MyRepoModel> entry : myView2Model.entrySet()) {
MyRepoModel model = entry.getValue();
if (model.isSelected()) {
- //has one or more selected roots
+ if (model.hasError()) return new ValidationInfo(model.getError().getText());
validInfo = null;
- RepositoryNode node = entry.getKey();
- PushTarget target = model.getSpec().getTarget();
- //todo add validation for model -> hasErrors, too
- if (target == null) {
- JComponent editingComponent = myPushLog.startEditNode(node);
- return new ValidationInfo("Invalid remote for repository " + DvcsUtil.getShortRepositoryName(model.getRepository()),
- editingComponent);
- }
}
}
return validInfo;
@@ -123,36 +131,44 @@ public class PushController implements Disposable {
private boolean createTreeModel(@NotNull CheckedTreeNode rootNode, @NotNull List<? extends Repository> preselectedRepositories) {
if (myPushSupports.isEmpty()) return true;
int repoCount = 0;
- for (PushSupport<? extends Repository> support : myPushSupports) {
+ for (PushSupport<? extends Repository, ? extends PushSource, ? extends PushTarget> support : myPushSupports) {
repoCount += createNodesForVcs(support, rootNode, preselectedRepositories);
}
return repoCount == 1;
}
- private <T extends Repository> int createNodesForVcs(@NotNull PushSupport<T> pushSupport,
- @NotNull CheckedTreeNode rootNode,
- @NotNull List<? extends Repository> preselectedRepositories) {
- RepositoryManager<T> repositoryManager = pushSupport.getRepositoryManager();
- List<T> repositories = repositoryManager.getRepositories();
- for (T repository : repositories) {
+ private <R extends Repository, S extends PushSource, T extends PushTarget> int createNodesForVcs(
+ @NotNull PushSupport<R, S, T> pushSupport,
+ @NotNull CheckedTreeNode rootNode,
+ @NotNull List<? extends Repository> preselectedRepositories) {
+ RepositoryManager<R> repositoryManager = pushSupport.getRepositoryManager();
+ List<R> repositories = repositoryManager.getRepositories();
+ for (R repository : repositories) {
createRepoNode(pushSupport, repository, rootNode, preselectedRepositories.contains(repository), repositories.size() == 1);
}
return repositories.size();
}
- private <T extends Repository> void createRepoNode(@NotNull final PushSupport<T> support,
- @NotNull final T repository,
- @NotNull CheckedTreeNode rootNode,
- boolean isSelected,
- boolean isSingleRepositoryProject) {
- PushTarget target = support.getDefaultTarget(repository);
- final MyRepoModel model = new MyRepoModel(repository, support, isSelected, new PushSpec(support.getSource(repository), target),
- DEFAULT_CHILDREN_PRESENTATION_NUMBER);
- RepositoryWithBranchPanel repoPanel = new RepositoryWithBranchPanel(myProject, DvcsUtil.getShortRepositoryName(repository),
+ private <R extends Repository, S extends PushSource, T extends PushTarget> void createRepoNode(@NotNull final PushSupport<R, S, T> support,
+ @NotNull final R repository,
+ @NotNull CheckedTreeNode rootNode,
+ boolean isSelected,
+ boolean isSingleRepositoryProject) {
+ T target = support.getDefaultTarget(repository);
+ String repoName = DvcsUtil.getShortRepositoryName(repository);
+ final MyRepoModel<R, S, T> model = new MyRepoModel<R, S, T>(repository, support, isSingleRepositoryProject || isSelected,
+ support.getSource(repository), target,
+ DEFAULT_CHILDREN_PRESENTATION_NUMBER);
+ if (target == null) {
+ model.setError(VcsError.createEmptyTargetError(repoName));
+ }
+ RepositoryWithBranchPanel repoPanel = new RepositoryWithBranchPanel(myProject, repoName,
support.getSource(repository).getPresentation(),
target == null ? "" : target.getPresentation(),
support.getTargetNames(repository));
- final RepositoryNode repoNode = isSingleRepositoryProject ? new SingleRepositoryNode(repoPanel) : new RepositoryNode(repoPanel);
+ final RepositoryNode repoNode = isSingleRepositoryProject
+ ? new SingleRepositoryNode(repoPanel, support.renderTarget(target))
+ : new RepositoryNode(repoPanel, support.renderTarget(target));
myView2Model.put(repoNode, model);
repoNode.setChecked(model.isSelected());
repoPanel.addRepoNodeListener(new RepositoryNodeListener() {
@@ -160,19 +176,25 @@ public class PushController implements Disposable {
public void onTargetChanged(String newValue) {
VcsError validationError = support.validate(model.getRepository(), newValue);
if (validationError == null) {
- myView2Model.get(repoNode).setSpec(new PushSpec(model.getSpec().getSource(), support.createTarget(repository, newValue)));
+ T newTarget = support.createTarget(repository, newValue);
+ repoNode.setTargetPresentation(support.renderTarget(newTarget));
+ model.setTarget(newTarget);
+ model.clearErrors();
loadCommits(model, repoNode, false);
}
else {
- //todo may be should store validation errors in model and get errors during dialog validation
- myView2Model.get(repoNode).setSpec(new PushSpec(model.getSpec().getSource(), null));
+ repoNode.setTargetPresentation(StringUtil.isEmptyOrSpaces(newValue)
+ ? support.renderTarget(null)
+ : new SimpleColoredText(newValue, SimpleTextAttributes.ERROR_ATTRIBUTES));
+ model.setError(validationError); // todo may be should accept and store errors collection, now store one major target error
+ model.setTarget(null);
}
myDialog.updateButtons();
}
@Override
public void onSelectionChanged(boolean isSelected) {
- myView2Model.get(repoNode).setSelected(isSelected);
+ model.setSelected(isSelected);
repoNode.setChecked(isSelected);
myDialog.updateButtons();
}
@@ -180,13 +202,15 @@ public class PushController implements Disposable {
rootNode.add(repoNode);
}
- private void loadCommits(@NotNull final MyRepoModel model,
- @NotNull final RepositoryNode node,
- final boolean initial) {
+ private <R extends Repository, S extends PushSource, T extends PushTarget> void loadCommits(@NotNull final MyRepoModel<R, S, T> model,
+ @NotNull final RepositoryNode node,
+ final boolean initial) {
node.stopLoading();
+ final T target = model.getTarget();
+ if (target == null) return; //todo should be removed when commit loader executor will be modified
myPushLog.startLoading(node);
final ProgressIndicator indicator = node.startLoading();
- final PushSupport support = model.getSupport();
+ final PushSupport<R, S, T> support = model.getSupport();
final AtomicReference<OutgoingResult> result = new AtomicReference<OutgoingResult>();
Task.Backgroundable task = new Task.Backgroundable(myProject, "Loading Commits", true) {
@@ -229,7 +253,7 @@ public class PushController implements Disposable {
@Override
public void run(@NotNull ProgressIndicator indicator) {
OutgoingResult outgoing = support.getOutgoingCommitsProvider()
- .getOutgoingCommits(model.getRepository(), model.getSpec(), initial);
+ .getOutgoingCommits(model.getRepository(), new PushSpec<S, T>(model.getSource(), model.getTarget()), initial);
result.compareAndSet(null, outgoing);
}
};
@@ -237,8 +261,7 @@ public class PushController implements Disposable {
ProgressManagerImpl.runProcessWithProgressAsynchronously(task, indicator, null, ModalityState.any());
}
-
- public PushLog getPushPanelInfo() {
+ public PushLog getPushPanelLog() {
return myPushLog;
}
@@ -247,22 +270,32 @@ public class PushController implements Disposable {
@Override
public void run(@NotNull ProgressIndicator indicator) {
for (PushSupport support : myPushSupports) {
- MyPushOptionValueModel additionalOptionsModel = myAdditionalValuesMap.get(support);
- support.getPusher()
- .push(collectPushInfoForVcs(support), additionalOptionsModel == null ? null : additionalOptionsModel.getCurrentValue(), force);
+ doPush(support, force);
}
}
};
task.queue();
}
+ private <R extends Repository, S extends PushSource, T extends PushTarget> void doPush(@NotNull PushSupport<R, S, T> support,
+ boolean force) {
+ MyPushOptionValueModel additionalOptionsModel = myAdditionalValuesMap.get(support);
+ VcsPushOptionValue options = additionalOptionsModel == null ? null : additionalOptionsModel.getCurrentValue();
+ Pusher<R, S, T> pusher = support.getPusher();
+ pusher.push(collectPushSpecsForVcs(support), options, force);
+ }
+
@NotNull
- private Map<Repository, PushSpec> collectPushInfoForVcs(@NotNull final PushSupport pushSupport) {
- Map<Repository, PushSpec> pushSpecs = new HashMap<Repository, PushSpec>();
+ private <R extends Repository, S extends PushSource, T extends PushTarget> Map<R, PushSpec<S, T>> collectPushSpecsForVcs(@NotNull PushSupport<R, S, T> pushSupport) {
+ Map<R, PushSpec<S, T>> pushSpecs = ContainerUtil.newHashMap();
Collection<MyRepoModel> repositoriesInformation = getSelectedRepoNode();
for (MyRepoModel repoModel : repositoriesInformation) {
if (pushSupport.equals(repoModel.getSupport())) {
- pushSpecs.put(repoModel.getRepository(), repoModel.getSpec());
+ //todo improve generics: unchecked casts
+ T target = (T)repoModel.getTarget();
+ if (target != null) {
+ pushSpecs.put((R)repoModel.getRepository(), new PushSpec<S, T>((S)repoModel.getSource(), target));
+ }
}
}
return pushSpecs;
@@ -356,38 +389,53 @@ public class PushController implements Disposable {
});
}
- private static class MyRepoModel {
- @NotNull final Repository myRepository;
- @NotNull private PushSupport mySupport;
+ private static class MyRepoModel<Repo extends Repository, S extends PushSource, T extends PushTarget> {
+ @NotNull final Repo myRepository;
+ @NotNull private PushSupport<Repo, S, T> mySupport;
+ @NotNull private final S mySource;
+ @Nullable private T myTarget;
+ @Nullable VcsError myTargetError;
- @NotNull PushSpec mySpec;
int myNumberOfShownCommits;
-
List<? extends VcsFullCommitDetails> myLoadedCommits;
boolean myIsSelected;
- public MyRepoModel(@NotNull Repository repository,
- @NotNull PushSupport supportForRepo,
- boolean isSelected,
- @NotNull PushSpec spec,
+ public MyRepoModel(@NotNull Repo repository,
+ @NotNull PushSupport<Repo, S, T> supportForRepo,
+ boolean isSelected, @NotNull S source, @Nullable T target,
int num) {
myRepository = repository;
mySupport = supportForRepo;
myIsSelected = isSelected;
- mySpec = spec;
+ mySource = source;
+ myTarget = target;
myNumberOfShownCommits = num;
}
@NotNull
- public Repository getRepository() {
+ public Repo getRepository() {
return myRepository;
}
@NotNull
- public PushSupport getSupport() {
+ public PushSupport<Repo, S, T> getSupport() {
return mySupport;
}
+ @NotNull
+ public S getSource() {
+ return mySource;
+ }
+
+ @Nullable
+ public T getTarget() {
+ return myTarget;
+ }
+
+ public void setTarget(@Nullable T target) {
+ myTarget = target;
+ }
+
public boolean isSelected() {
return myIsSelected;
}
@@ -396,13 +444,21 @@ public class PushController implements Disposable {
return myRepository.getVcs();
}
- @NotNull
- public PushSpec getSpec() {
- return mySpec;
+ @Nullable
+ public VcsError getError() {
+ return myTargetError;
+ }
+
+ public void setError(@Nullable VcsError error) {
+ myTargetError = error;
+ }
+
+ public void clearErrors() {
+ myTargetError = null;
}
- public void setSpec(@NotNull PushSpec spec) {
- mySpec = spec;
+ public boolean hasError() {
+ return myTargetError != null;
}
public void setSelected(boolean isSelected) {
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 5d0d20cdc4c0..b5747de91bf7 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
@@ -20,7 +20,9 @@ import org.jetbrains.annotations.NotNull;
public interface EditableTreeNode extends CustomRenderedTreeNode {
- void fireOnChange(@NotNull String value);
+ void fireOnChange();
+
+ void fireOnCancel();
void fireOnSelectionChange(boolean isSelected);
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 b07bf9243f8a..0b4bcb0fbef0 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
@@ -31,7 +31,6 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.vcs.log.VcsFullCommitDetails;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.CellEditorListener;
@@ -56,6 +55,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
private final ChangesBrowser myChangesBrowser;
private final CheckboxTree myTree;
private final MyTreeCellRenderer myTreeCellRenderer;
+ //private final AtomicBoolean myIgnoreStopEditing = new AtomicBoolean(false);
public PushLog(Project project, CheckedTreeNode root) {
DefaultTreeModel treeModel = new DefaultTreeModel(root);
@@ -96,14 +96,17 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
treeCellEditor.addCellEditorListener(new CellEditorListener() {
@Override
public void editingStopped(ChangeEvent e) {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode)myTree.getLastSelectedPathComponent();
+ if (node != null && node instanceof EditableTreeNode) {
+ ((EditableTreeNode)node).fireOnChange();
+ }
}
@Override
public void editingCanceled(ChangeEvent e) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)myTree.getLastSelectedPathComponent();
if (node != null && node instanceof EditableTreeNode) {
- //todo restore from appropriate editor
- ((EditableTreeNode)node).fireOnChange(((EditableTreeNode)node).getValue());
+ ((EditableTreeNode)node).fireOnCancel();
}
}
});
@@ -119,10 +122,13 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
TreePath[] nodes = myTree.getSelectionPaths();
if (nodes != null) {
ArrayList<Change> changes = new ArrayList<Change>();
- for (TreePath node : nodes) {
- Object nodeInfo = ((DefaultMutableTreeNode)node.getLastPathComponent()).getUserObject();
- if (nodeInfo instanceof VcsFullCommitDetails) {
- changes.addAll(((VcsFullCommitDetails)nodeInfo).getChanges());
+ for (TreePath path : nodes) {
+ if (path.getLastPathComponent() instanceof VcsFullCommitDetailsNode) {
+ VcsFullCommitDetailsNode commitDetailsNode = (VcsFullCommitDetailsNode)path.getLastPathComponent();
+ changes.addAll(commitDetailsNode.getUserObject().getChanges());
+ }
+ else if (path.getLastPathComponent() instanceof RepositoryNode) {
+ changes.addAll(collectAllChanges((RepositoryNode)path.getLastPathComponent()));
}
}
myChangesBrowser.getViewer().setEmptyText("No differences");
@@ -151,10 +157,29 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
add(splitter);
}
+ @NotNull
+ private static Collection<? extends Change> collectAllChanges(@NotNull RepositoryNode rootNode) {
+ ArrayList<Change> changes = new ArrayList<Change>();
+ if (rootNode.getChildCount() <= 0) return changes;
+ for (DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)rootNode.getFirstChild();
+ childNode != null;
+ childNode = (DefaultMutableTreeNode)rootNode.getChildAfter(childNode)) {
+ if (childNode instanceof VcsFullCommitDetailsNode) {
+ changes.addAll(((VcsFullCommitDetailsNode)childNode).getUserObject().getChanges());
+ }
+ }
+ return changes;
+ }
+
private void setDefaultEmptyText() {
myChangesBrowser.getViewer().setEmptyText("No commits selected");
}
+ public void selectNode(@NotNull DefaultMutableTreeNode node) {
+ TreePath selectionPath = new TreePath(node.getPath());
+ myTree.addSelectionPath(selectionPath);
+ }
+
// Make changes available for diff action
@Override
public void calcData(DataKey key, DataSink sink) {
@@ -173,7 +198,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
@Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if (e.getKeyCode() == KeyEvent.VK_ENTER && myTree.isEditing()) {
- myTree.cancelEditing();
+ myTree.stopEditing();
return true;
}
return super.processKeyBinding(ks, e, condition, pressed);
@@ -185,6 +210,10 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
setChildren(parentNode, Collections.singleton(loading));
}
+ public JComponent getPreferredFocusedComponent() {
+ return myTree;
+ }
+
private class MyTreeCellEditor extends DefaultCellEditor {
public MyTreeCellEditor(JTextField field) {
@@ -265,6 +294,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
final DefaultTreeModel model = ((DefaultTreeModel)myTree.getModel());
model.nodeStructureChanged(parentNode);
TreePath path = TreeUtil.getPathFromRoot(parentNode);
+ //myIgnoreStopEditing.set(true);
if (shouldExpand) {
myTree.expandPath(path);
}
@@ -274,16 +304,15 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
}
finally {
TREE_CONSTRUCTION_LOCK.writeLock().unlock();
+ //myIgnoreStopEditing.set(false);
}
}
- @Nullable
- public JComponent startEditNode(@NotNull TreeNode node) {
+ public void startEditNode(@NotNull TreeNode node) {
TreePath path = TreeUtil.getPathFromRoot(node);
if (!myTree.isEditing()) {
+ myTree.setSelectionPath(path);
myTree.startEditingAtPath(path);
}
- return (JComponent)myTree.getCellEditor()
- .getTreeCellEditorComponent(myTree, node, false, false, false, myTree.getRowForPath(path));
}
}
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 24a26ece96d9..05e752c4be85 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
@@ -17,26 +17,27 @@ package com.intellij.dvcs.push.ui;
import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.ui.CheckedTreeNode;
-import com.intellij.ui.ColoredTreeCellRenderer;
-import com.intellij.ui.EditorTextField;
-import com.intellij.ui.SimpleTextAttributes;
+import com.intellij.ui.*;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
+import java.util.ArrayList;
-public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode {
- protected final static String ENTER_REMOTE = "Enter Remote";
+public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode, Comparable<RepositoryNode> {
@NotNull private final RepositoryWithBranchPanel myRepositoryPanel;
-
+ @NotNull protected SimpleColoredText myTargetPresentation;
private ProgressIndicator myCurrentIndicator;
- public RepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel) {
+ public RepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel, @NotNull SimpleColoredText targetPresentation) {
super(repositoryPanel);
myRepositoryPanel = repositoryPanel;
+ myTargetPresentation = targetPresentation;
+ }
+
+ public void setTargetPresentation(@NotNull SimpleColoredText targetPresentation) {
+ myTargetPresentation = targetPresentation;
}
public boolean isCheckboxVisible() {
@@ -51,30 +52,38 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode
renderer.append(myRepositoryPanel.getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
renderer.append(myRepositoryPanel.getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
EditorTextField textField = myRepositoryPanel.getRemoteTextFiled();
- renderTargetName(renderer, textField, myRepositoryPanel.getRemoteTargetName());
+ renderTargetName(renderer, textField);
Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(textField);
renderer.setBorder(new EmptyBorder(insets));
}
- protected void renderTargetName(@NotNull ColoredTreeCellRenderer renderer, @NotNull EditorTextField textField,
- @NotNull String targetName) {
- if (StringUtil.isEmptyOrSpaces(targetName)) {
- renderer.append(ENTER_REMOTE, SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES, textField);
- }
- else {
- renderer.append(targetName, SimpleTextAttributes.SYNTHETIC_ATTRIBUTES, textField);
+ protected void renderTargetName(@NotNull ColoredTreeCellRenderer renderer, @NotNull EditorTextField textField) {
+ ArrayList<String> strings = myTargetPresentation.getTexts();
+ ArrayList<SimpleTextAttributes> attributes = myTargetPresentation.getAttributes();
+ for (int i = 0; i < strings.size(); i++) {
+ renderer.append(strings.get(i), attributes.get(i), textField);
}
}
@Override
+ public Object getUserObject() {
+ return myRepositoryPanel;
+ }
+
+ @Override
@NotNull
public String getValue() {
return myRepositoryPanel.getRemoteTargetName();
}
@Override
- public void fireOnChange(@NotNull String value) {
- myRepositoryPanel.fireOnChange(value);
+ public void fireOnChange() {
+ myRepositoryPanel.fireOnChange();
+ }
+
+ @Override
+ public void fireOnCancel() {
+ myRepositoryPanel.fireOnCancel();
}
@Override
@@ -94,4 +103,10 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode
public ProgressIndicator startLoading() {
return myCurrentIndicator = new EmptyProgressIndicator();
}
+
+ public int compareTo(@NotNull RepositoryNode repositoryNode) {
+ String name = myRepositoryPanel.getRepositoryName();
+ RepositoryWithBranchPanel panel = (RepositoryWithBranchPanel)repositoryNode.getUserObject();
+ return name.compareTo(panel.getRepositoryName());
+ }
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java
index c1afcdd52839..cd93d0653c36 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java
@@ -36,7 +36,6 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
-import java.util.Collection;
import java.util.List;
public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCellRenderer {
@@ -48,12 +47,14 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
private final JLabel myRepositoryLabel;
private final ColoredTreeCellRenderer myTextRenderer;
@NotNull private final List<RepositoryNodeListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
+ private String myOldDestination;
public RepositoryWithBranchPanel(Project project, @NotNull String repoName,
- @NotNull String sourceName, String targetName, @NotNull Collection<String> targetVariants) {
+ @NotNull String sourceName, String targetName, @NotNull final List<String> targetVariants) {
super();
setLayout(new BorderLayout());
myRepositoryCheckbox = new JBCheckBox();
+ myRepositoryCheckbox.setFocusable(false);
myRepositoryCheckbox.setOpaque(false);
myRepositoryCheckbox.addActionListener(new ActionListener() {
@Override
@@ -64,8 +65,14 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
myRepositoryLabel = new JLabel(repoName);
myLocalBranch = new JBLabel(sourceName);
myArrowLabel = new JLabel(" -> ");
+ myOldDestination = targetName;
TextFieldWithAutoCompletionListProvider<String> provider =
- new TextFieldWithAutoCompletion.StringsCompletionProvider(targetVariants, null);
+ new TextFieldWithAutoCompletion.StringsCompletionProvider(targetVariants, null) {
+ @Override
+ public int compare(String item1, String item2) {
+ return Integer.valueOf(ContainerUtil.indexOf(targetVariants, item1)).compareTo(ContainerUtil.indexOf(targetVariants, item2));
+ }
+ };
myDestBranchTextField = new TextFieldWithAutoCompletion<String>(project, provider, true, targetName) {
@Override
@@ -77,15 +84,17 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
protected void updateBorder(@NotNull final EditorEx editor) {
}
};
- myDestBranchTextField.setBorder(UIUtil.getTableFocusCellHighlightBorder());//getTextFieldBorder());
+ myDestBranchTextField.setBorder(UIUtil.getTableFocusCellHighlightBorder());
myDestBranchTextField.setOneLineMode(true);
myDestBranchTextField.setOpaque(true);
- myDestBranchTextField.addFocusListener(new FocusAdapter() {
+ FocusAdapter focusListener = new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
myDestBranchTextField.selectAll();
}
- });
+ };
+ myDestBranchTextField.addFocusListener(focusListener);
+ addFocusListener(focusListener);
myTextRenderer = new ColoredTreeCellRenderer() {
public void customizeCellRenderer(@NotNull JTree tree,
@@ -169,9 +178,10 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
myListeners.add(listener);
}
- public void fireOnChange(@NotNull String newValue) {
+ public void fireOnChange() {
+ myOldDestination = myDestBranchTextField.getText();
for (RepositoryNodeListener listener : myListeners) {
- listener.onTargetChanged(newValue);
+ listener.onTargetChanged(myOldDestination);
}
}
@@ -180,6 +190,10 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
listener.onSelectionChanged(isSelected);
}
}
+
+ public void fireOnCancel() {
+ myDestBranchTextField.setText(myOldDestination);
+ }
}
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 c566dd6f2867..81fb2bd1a9d0 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
@@ -17,6 +17,7 @@ package com.intellij.dvcs.push.ui;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.EditorTextField;
+import com.intellij.ui.SimpleColoredText;
import com.intellij.ui.SimpleTextAttributes;
import org.jetbrains.annotations.NotNull;
@@ -28,8 +29,8 @@ public class SingleRepositoryNode extends RepositoryNode {
@NotNull private final RepositoryWithBranchPanel myRepositoryPanel;
- public SingleRepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel) {
- super(repositoryPanel);
+ public SingleRepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel, @NotNull SimpleColoredText customTargetPresentation) {
+ super(repositoryPanel, customTargetPresentation);
myRepositoryPanel = repositoryPanel;
}
@@ -43,10 +44,8 @@ public class SingleRepositoryNode extends RepositoryNode {
renderer.append(myRepositoryPanel.getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
renderer.append(myRepositoryPanel.getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
EditorTextField textField = myRepositoryPanel.getRemoteTextFiled();
- String targetName = myRepositoryPanel.getRemoteTargetName();
- renderTargetName(renderer, textField, targetName);
+ renderTargetName(renderer, textField);
Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(textField);
renderer.setBorder(new EmptyBorder(insets));
}
-
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsFullCommitDetailsNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsFullCommitDetailsNode.java
index 0df7af05d496..51e8aaf3e9db 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsFullCommitDetailsNode.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsFullCommitDetailsNode.java
@@ -17,6 +17,7 @@ package com.intellij.dvcs.push.ui;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkHtmlRenderer;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
@@ -30,16 +31,21 @@ public class VcsFullCommitDetailsNode extends DefaultMutableTreeNode implements
@NotNull private final Project myProject;
private final VcsFullCommitDetails myCommit;
- public VcsFullCommitDetailsNode(@NotNull Project project, VcsFullCommitDetails commit) {
+ public VcsFullCommitDetailsNode(@NotNull Project project, @NotNull VcsFullCommitDetails commit) {
super(commit, false);
myProject = project;
myCommit = commit;
}
@Override
+ public VcsFullCommitDetails getUserObject() {
+ return myCommit;
+ }
+
+ @Override
public void render(@NotNull ColoredTreeCellRenderer renderer) {
- renderer
- .append(myCommit.getSubject(), new SimpleTextAttributes(SimpleTextAttributes.STYLE_SMALLER, renderer.getForeground()));
+ String subject = StringUtil.shortenTextWithEllipsis(myCommit.getSubject(), 80, 0);
+ renderer.append(subject, new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, renderer.getForeground()));
}
public String getTooltip() {
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 b441952f7a43..22f1e74abbbd 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
@@ -15,11 +15,13 @@
*/
package com.intellij.dvcs.push.ui;
+import com.intellij.CommonBundle;
import com.intellij.dvcs.push.PushController;
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;
@@ -32,8 +34,11 @@ import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
+import static com.intellij.openapi.ui.Messages.OK;
+
public class VcsPushDialog extends DialogWrapper {
+ @NotNull private final Project myProject;
private final PushLog myListPanel;
private final PushController myController;
private final Action[] myExecutorActions = {new DvcsPushAction("&Force Push", true)};
@@ -43,8 +48,9 @@ public class VcsPushDialog extends DialogWrapper {
public VcsPushDialog(@NotNull Project project, @NotNull List<? extends Repository> selectedRepositories) {
super(project);
+ myProject = project;
myController = new PushController(project, this, selectedRepositories);
- myListPanel = myController.getPushPanelInfo();
+ myListPanel = myController.getPushPanelLog();
myAdditionalOptionsFromVcsPanel = new JPanel(new MigLayout("ins 0 0, flowx"));
init();
setOKButtonText("Push");
@@ -82,6 +88,12 @@ public class VcsPushDialog extends DialogWrapper {
return actions.toArray(new Action[actions.size()]);
}
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return myListPanel.getPreferredFocusedComponent();
+ }
+
@NotNull
@Override
protected Action getOKAction() {
@@ -127,6 +139,12 @@ public class VcsPushDialog extends DialogWrapper {
@Override
public void actionPerformed(ActionEvent e) {
+ if (myForce) {
+ int answer = Messages.showOkCancelDialog(myProject, getConfirmationMessage(),
+ "Force Push",
+ "&Force Push", CommonBundle.getCancelButtonText(), Messages.getWarningIcon());
+ if (answer != OK) return;
+ }
myController.push(myForce);
close(OK_EXIT_CODE);
}
@@ -141,4 +159,9 @@ public class VcsPushDialog extends DialogWrapper {
myOptions = actions;
}
}
+
+ @NotNull
+ private static String getConfirmationMessage() {
+ return "You're going to force push. It will overwrite commits at the remote. Are you sure you want to proceed?";
+ }
}