diff options
Diffstat (limited to 'platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java')
-rw-r--r-- | platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java | 184 |
1 files changed, 120 insertions, 64 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) { |