Errors listeners structure improved, ui separated from VcsError, link created from markup text.

This commit is contained in:
Nadya Zabrodina
2014-08-17 14:24:57 +04:00
parent 64b2637d18
commit 5ae414b1a3
9 changed files with 168 additions and 93 deletions
@@ -15,8 +15,6 @@
*/
package com.intellij.dvcs.push;
public class MoreCommitsLink extends VcsLinkedText {
MoreCommitsLink() {
super("", "...");
}
public interface CommitLoader {
void reloadCommits();
}
@@ -16,13 +16,28 @@
package com.intellij.dvcs.push;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class VcsError {
@NotNull String myErrorText;
@Nullable private final VcsErrorHandler myErrorHandleListener;
public class VcsError extends VcsLinkedText {
public VcsError(@NotNull String text) {
super(text, "");
this(text, null);
}
public VcsError(@NotNull String text, @NotNull String link) {
super(text, link);
public VcsError(@NotNull String text, @Nullable VcsErrorHandler listener) {
myErrorText = text;
myErrorHandleListener = listener;
}
public String getText() {
return myErrorText;
}
public void handleError(@NotNull CommitLoader loader) {
if (myErrorHandleListener != null) {
myErrorHandleListener.handleError(loader);
}
}
}
@@ -0,0 +1,22 @@
/*
* 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 com.intellij.dvcs.push;
import org.jetbrains.annotations.NotNull;
public interface VcsErrorHandler {
void handleError(@NotNull CommitLoader loader);
}
@@ -1,54 +0,0 @@
/*
* 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 com.intellij.dvcs.push;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.tree.DefaultMutableTreeNode;
import java.util.List;
public class VcsLinkedText {
@NotNull String myText;
@NotNull String myHandledLink;
private final List<TreeNodeLinkListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
public VcsLinkedText(@NotNull String text, @NotNull String link) {
myText = text;
myHandledLink = link;
}
@NotNull
public String getText() {
return myText;
}
@NotNull
public String getLinkText() {
return myHandledLink;
}
public void addClickListener(@NotNull TreeNodeLinkListener listener) {
myListeners.add(listener);
}
public void fireOnClick(@NotNull DefaultMutableTreeNode relatedNode) {
for (TreeNodeLinkListener listener : myListeners) {
listener.onClick(relatedNode);
}
}
}
@@ -39,7 +39,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
@@ -110,7 +109,6 @@ public class PushController implements Disposable {
private void loadCommitsFromMap(@NotNull Map<RepositoryNode, MyRepoModel> items) {
for (Map.Entry<RepositoryNode, MyRepoModel> entry : items.entrySet()) {
RepositoryNode node = entry.getKey();
myPushLog.startLoading(node);
loadCommits(entry.getValue(), node, true);
}
}
@@ -156,7 +154,6 @@ public class PushController implements Disposable {
public void onTargetChanged(String newValue) {
myView2Model.get(repoNode).setSpec(new PushSpec(model.getSpec().getSource(), support.createTarget(repository, newValue)));
myDialog.updateButtons();
myPushLog.startLoading(repoNode);
loadCommits(model, repoNode, false);
}
@@ -173,6 +170,7 @@ public class PushController implements Disposable {
@NotNull final RepositoryNode node,
final boolean initial) {
node.stopLoading();
myPushLog.startLoading(node);
final ProgressIndicator indicator = node.startLoading();
final PushSupport support = model.getSupport();
final AtomicReference<OutgoingResult> result = new AtomicReference<OutgoingResult>();
@@ -187,10 +185,22 @@ public class PushController implements Disposable {
public void onSuccess() {
OutgoingResult outgoing = result.get();
if (outgoing.hasErrors()) {
final CommitLoader loader = new CommitLoader() {
@Override
public void reloadCommits() {
loadCommits(model, node, false);
}
};
myPushLog.setChildren(node, ContainerUtil.map(outgoing.getErrors(), new Function<VcsError, DefaultMutableTreeNode>() {
@Override
public DefaultMutableTreeNode fun(VcsError error) {
return new TextWithLinkNode(error);
public DefaultMutableTreeNode fun(final VcsError error) {
VcsLinkedText errorLinkText = new VcsLinkedText(error.getText(), new VcsLinkListener() {
@Override
public void hyperlinkActivated(@NotNull DefaultMutableTreeNode sourceNode) {
error.handleError(loader);
}
});
return new TextWithLinkNode(errorLinkText);
}
}), model.isSelected());
}
@@ -288,14 +298,10 @@ public class PushController implements Disposable {
List<DefaultMutableTreeNode> childrenToShown = new ArrayList<DefaultMutableTreeNode>();
for (int i = 0; i < commits.size(); ++i) {
if (i >= commitsNum) {
final MoreCommitsLink moreCommitsLink = new MoreCommitsLink();
moreCommitsLink.addClickListener(new TreeNodeLinkListener() {
final VcsLinkedText moreCommitsLink = new VcsLinkedText("<a href='loadMore'>...</a>", new VcsLinkListener() {
@Override
public void onClick(@NotNull DefaultMutableTreeNode source) {
TreeNode parentNode = source.getParent();
if (parentNode instanceof RepositoryNode) {
addMoreCommits((RepositoryNode)parentNode);
}
public void hyperlinkActivated(@NotNull DefaultMutableTreeNode sourceNode) {
addMoreCommits((RepositoryNode)sourceNode);
}
});
childrenToShown.add(new TextWithLinkNode(moreCommitsLink));
@@ -16,13 +16,13 @@
package com.intellij.dvcs.push.ui;
import com.intellij.dvcs.push.VcsLinkedText;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import org.jetbrains.annotations.NotNull;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
public class TextWithLinkNode extends DefaultMutableTreeNode implements CustomRenderedTreeNode {
@@ -32,18 +32,21 @@ public class TextWithLinkNode extends DefaultMutableTreeNode implements CustomRe
myLinkedText = linkedText;
}
public void fireOnClick(@NotNull TextWithLinkNode relatedNode) {
myLinkedText.fireOnClick(relatedNode);
TreeNode parent = relatedNode.getParent();
if (parent instanceof RepositoryNode) {
myLinkedText.hyperLinkActivate((RepositoryNode)parent);
}
}
@Override
public void render(@NotNull ColoredTreeCellRenderer renderer) {
renderer.append(myLinkedText.getText(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
renderer.append(myLinkedText.getTextBefore(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
String linkedText = myLinkedText.getLinkText();
if (!StringUtil.isEmptyOrSpaces(linkedText)) {
renderer.append(" ");
renderer.append(myLinkedText.getLinkText(), SimpleTextAttributes.SYNTHETIC_ATTRIBUTES, this);
}
renderer.append(myLinkedText.getTextAfter(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
}
@@ -0,0 +1,24 @@
/*
* 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 com.intellij.dvcs.push.ui;
import org.jetbrains.annotations.NotNull;
import javax.swing.tree.DefaultMutableTreeNode;
public interface VcsLinkListener {
void hyperlinkActivated(@NotNull DefaultMutableTreeNode sourceNode);
}
@@ -0,0 +1,70 @@
/*
* 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 com.intellij.dvcs.push.ui;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.tree.DefaultMutableTreeNode;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class VcsLinkedText {
private static final Pattern HREF_PATTERN = Pattern.compile("<a(?:\\s+href\\s*=\\s*[\"']([^\"']*)[\"'])?\\s*>([^<]*)</a>");
@NotNull private String myTextBefore;
@NotNull private String myTextAfter;
@NotNull private String myHandledLink;
@Nullable private final VcsLinkListener myLinkListener;
public VcsLinkedText(@NotNull String text, @Nullable VcsLinkListener listener) {
Matcher aMatcher = HREF_PATTERN.matcher(text);
if (aMatcher.find()) {
myTextBefore = text.substring(0, aMatcher.start());
myHandledLink = aMatcher.group(2);
myTextAfter = text.substring(aMatcher.end(), text.length());
}
else {
myTextBefore = text;
myHandledLink = "";
myTextAfter = "";
}
myLinkListener = listener;
}
@NotNull
public String getTextBefore() {
return myTextBefore;
}
@NotNull
public String getTextAfter() {
return myTextAfter;
}
@NotNull
public String getLinkText() {
return myHandledLink;
}
public void hyperLinkActivate(@NotNull DefaultMutableTreeNode relatedNode) {
if (myLinkListener != null) {
myLinkListener.hyperlinkActivated(relatedNode);
}
}
}
@@ -16,7 +16,6 @@
package org.zmlx.hg4idea.push;
import com.intellij.dvcs.push.*;
import com.intellij.dvcs.push.ui.RepositoryNode;
import com.intellij.dvcs.repo.Repository;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
@@ -32,8 +31,6 @@ import org.zmlx.hg4idea.util.HgChangesetUtil;
import org.zmlx.hg4idea.util.HgErrorUtil;
import org.zmlx.hg4idea.util.HgVersion;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -73,18 +70,12 @@ public class HgOutgoingCommitsProvider extends OutgoingCommitsProvider {
for (String error : resultErrors) {
if (HgErrorUtil.isAbortLine(error)) {
if (HgErrorUtil.isAuthorizationError(error)) {
VcsError authorizationError = new VcsError(error, LOGIN_AND_REFRESH_LINK);
authorizationError.addClickListener(new TreeNodeLinkListener() {
@Override
public void onClick(@NotNull DefaultMutableTreeNode source) {
TreeNode parent = source.getParent();
if (parent instanceof RepositoryNode) {
//todo change value to something special, or create force refreshNode method
((RepositoryNode)parent).fireOnChange(((RepositoryNode)parent).getValue());
}
}
}
);
VcsError authorizationError =
new VcsError(error + "<a href='authentificate'>" + LOGIN_AND_REFRESH_LINK + "</a>", new VcsErrorHandler() {
public void handleError(@NotNull CommitLoader commitLoader) {
commitLoader.reloadCommits();
}
});
errors.add(authorizationError);
}
else {