RemoteTarget validation improved

* validation method api changed: now  only user's string input validation performed for selected repo;
* not null target created only if user's input is valid;
* postpone validation for dialog switched off;
* request focus added to repository panel renderer;
* tree root became inline;
* annotations added
This commit is contained in:
Nadya Zabrodina
2014-08-18 03:23:06 +04:00
parent 91aec5d024
commit ce014e6088
6 changed files with 54 additions and 27 deletions
@@ -18,7 +18,6 @@ package com.intellij.dvcs.push;
import com.intellij.dvcs.repo.Repository;
import com.intellij.dvcs.repo.RepositoryManager;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.vcs.AbstractVcs;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -31,7 +30,8 @@ import java.util.Collection;
public abstract class PushSupport<Repo extends Repository> {
public static final ExtensionPointName<PushSupport<? extends Repository>> PUSH_SUPPORT_EP = ExtensionPointName.create("com.intellij.pushSupport");
public static final ExtensionPointName<PushSupport<? extends Repository>> PUSH_SUPPORT_EP =
ExtensionPointName.create("com.intellij.pushSupport");
@NotNull
public abstract AbstractVcs getVcs();
@@ -63,6 +63,7 @@ public abstract class PushSupport<Repo extends Repository> {
/**
* Parse user input string, and create the valid target for push,
* or return <code><b>null</b></code> if the target name is not valid.
*
* @see #validateSpec(Repository, PushSpec)
*/
@Nullable
@@ -80,8 +81,8 @@ public abstract class PushSupport<Repo extends Repository> {
}
/**
* @return null if push spec are valid for selected repository
* @return null if target is valid for selected repository
*/
@Nullable
public abstract ValidationInfo validateSpec(@NotNull Repository repository, @NotNull PushSpec spec);
public abstract VcsError validate(@NotNull Repository repository, @Nullable String targetToValidate);
}
@@ -38,6 +38,7 @@ 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;
@@ -76,14 +77,18 @@ public class PushController implements Disposable {
@Nullable
public ValidationInfo validate() {
ValidationInfo validInfo = new ValidationInfo("There are no selected repository to push!");
for (MyRepoModel model : myView2Model.values()) {
for (Map.Entry<RepositoryNode, MyRepoModel> entry : myView2Model.entrySet()) {
MyRepoModel model = entry.getValue();
if (model.isSelected()) {
//has one or more selected roots
PushSupport support = model.getSupport();
validInfo = support.validateSpec(model.getRepository(), model.getSpec());
if (validInfo != null) {
// return first non valid node
return validInfo;
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);
}
}
}
@@ -91,6 +96,7 @@ public class PushController implements Disposable {
}
private void startLoadingCommits() {
//todo should be reworked
Map<RepositoryNode, MyRepoModel> priorityLoading = new HashMap<RepositoryNode, MyRepoModel>();
Map<RepositoryNode, MyRepoModel> others = new HashMap<RepositoryNode, MyRepoModel>();
for (Map.Entry<RepositoryNode, MyRepoModel> entry : myView2Model.entrySet()) {
@@ -152,9 +158,16 @@ public class PushController implements Disposable {
repoPanel.addRepoNodeListener(new RepositoryNodeListener() {
@Override
public void onTargetChanged(String newValue) {
myView2Model.get(repoNode).setSpec(new PushSpec(model.getSpec().getSource(), support.createTarget(repository, newValue)));
VcsError validationError = support.validate(model.getRepository(), newValue);
if (validationError == null) {
myView2Model.get(repoNode).setSpec(new PushSpec(model.getSpec().getSource(), support.createTarget(repository, newValue)));
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));
}
myDialog.updateButtons();
loadCommits(model, repoNode, false);
}
@Override
@@ -31,16 +31,14 @@ 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;
import javax.swing.event.ChangeEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
@@ -57,15 +55,13 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
private static final String START_EDITING = "startEditing";
private final ChangesBrowser myChangesBrowser;
private final CheckboxTree myTree;
private final CheckedTreeNode myRootNode;
private final MyTreeCellRenderer myTreeCellRenderer;
public PushLog(Project project, CheckedTreeNode root) {
myRootNode = root;
DefaultTreeModel treeModel = new DefaultTreeModel(myRootNode);
treeModel.nodeStructureChanged(myRootNode);
DefaultTreeModel treeModel = new DefaultTreeModel(root);
treeModel.nodeStructureChanged(root);
myTreeCellRenderer = new MyTreeCellRenderer();
myTree = new CheckboxTree(myTreeCellRenderer, myRootNode) {
myTree = new CheckboxTree(myTreeCellRenderer, root) {
public boolean isPathEditable(TreePath path) {
return isEditable() && path.getLastPathComponent() instanceof DefaultMutableTreeNode;
@@ -217,7 +213,10 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
return tag instanceof EditorTextField;
}
//if keyboard event - then anEvent will be null =( See BasicTreeUi
Object treeNode = myTree.getAnchorSelectionPath().getLastPathComponent();
TreePath treePath = myTree.getAnchorSelectionPath();
//there is no selection path if we start editing during initial validation//
if (treePath == null) return true;
Object treeNode = treePath.getLastPathComponent();
return treeNode instanceof EditableTreeNode;
}
@@ -277,4 +276,14 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
TREE_CONSTRUCTION_LOCK.writeLock().unlock();
}
}
@Nullable
public JComponent startEditNode(@NotNull TreeNode node) {
TreePath path = TreeUtil.getPathFromRoot(node);
if (!myTree.isEditing()) {
myTree.startEditingAtPath(path);
}
return (JComponent)myTree.getCellEditor()
.getTreeCellEditorComponent(myTree, node, false, false, false, myTree.getRowForPath(path));
}
}
@@ -159,6 +159,8 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
if (bounds != null) {
setPreferredSize(new Dimension(tree.getWidth() - bounds.x, bounds.height));
}
myDestBranchTextField.grabFocus();
myDestBranchTextField.requestFocus();
revalidate();
return this;
}
@@ -103,6 +103,11 @@ public class VcsPushDialog extends DialogWrapper {
initValidation();
}
@Override
protected boolean postponeValidation() {
return false;
}
private class DvcsPushAction extends AbstractAction implements OptionAction {
private Action[] myOptions = new Action[0];
private final boolean myForce;
@@ -19,7 +19,6 @@ import com.intellij.dvcs.push.*;
import com.intellij.dvcs.repo.Repository;
import com.intellij.dvcs.repo.RepositoryManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.util.Function;
@@ -104,9 +103,7 @@ public class HgPushSupport extends PushSupport<HgRepository> {
@Override
@Nullable
public ValidationInfo validateSpec(@NotNull Repository repository, @NotNull PushSpec spec) {
PushTarget target = spec.getTarget();
return (target == null || StringUtil.isEmptyOrSpaces(target.getPresentation())) ? new ValidationInfo(
"Please, specify remote push path for selected repos!") : null;
public VcsError validate(@NotNull Repository repository, @Nullable String targetToValidate) {
return StringUtil.isEmptyOrSpaces(targetToValidate) ? new VcsError("Please, specify remote push path for repository!") : null;
}
}