blob: 09c079f6c68263c2472a7e07270c5601aefec557 [file] [log] [blame]
/*
* Copyright 2000-2009 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 org.jetbrains.idea.svn.dialogs;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.util.NotNullFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.dialogs.browserCache.Expander;
import org.jetbrains.idea.svn.dialogs.browserCache.NodeLoadState;
import org.tmatesoft.svn.core.SVNDirEntry;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
public class RepositoryTreeNode implements TreeNode, Disposable {
private TreeNode myParentNode;
private List<TreeNode> myChildren;
private final RepositoryTreeModel myModel;
private final SVNURL myURL;
private final Object myUserObject;
private final NodeLoadState myLoadState;
private NodeLoadState myChildrenLoadState;
public RepositoryTreeNode(RepositoryTreeModel model, TreeNode parentNode,
@NotNull SVNURL url, Object userObject, final NodeLoadState state) {
myParentNode = parentNode;
myURL = url;
myModel = model;
myUserObject = userObject;
myLoadState = state;
myChildrenLoadState = NodeLoadState.EMPTY;
}
public RepositoryTreeNode(RepositoryTreeModel model, TreeNode parentNode, @NotNull SVNURL url, Object userObject) {
// created outside: only roots
this(model, parentNode, url, userObject, NodeLoadState.REFRESHED);
}
public Object getUserObject() {
return myUserObject;
}
public int getChildCount() {
return getChildren().size();
}
public Enumeration children() {
return Collections.enumeration(getChildren());
}
public TreeNode getChildAt(int childIndex) {
return (TreeNode) getChildren().get(childIndex);
}
public int getIndex(TreeNode node) {
return getChildren().indexOf(node);
}
public boolean getAllowsChildren() {
return !isLeaf();
}
public boolean isLeaf() {
return myUserObject instanceof SVNDirEntry ? ((SVNDirEntry) myUserObject).getKind() == SVNNodeKind.FILE : false;
}
public TreeNode getParent() {
return myParentNode;
}
public void reload(final boolean removeCurrentChildren) {
// todo lazyLoading as explicit: keeping...
reload(removeCurrentChildren ? myModel.getSelectionKeepingExpander() : myModel.getLazyLoadingExpander(), removeCurrentChildren);
}
@Nullable
public TreeNode getNextChildByKey(final String key, final boolean isFolder) {
final ByKeySelectedSearcher searcher = (isFolder) ? new FolderByKeySelectedSearcher(key, myChildren) :
new FileByKeySelectedSearcher(key, myChildren);
return searcher.getNextSelectedByKey();
}
public String toString() {
if (myParentNode instanceof RepositoryTreeRootNode) {
return myURL.toString();
}
return SVNPathUtil.tail(myURL.getPath());
}
public void reload(final Expander expander, final boolean removeCurrentChildren) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (removeCurrentChildren || (myChildren == null)) {
initChildren();
}
myModel.getCacheLoader().load(this, expander);
}
private void initChildren() {
myChildren = new ArrayList<TreeNode>();
myChildren.add(new DefaultMutableTreeNode("Loading"));
myChildrenLoadState = NodeLoadState.LOADING;
}
private List getChildren() {
ApplicationManager.getApplication().assertIsDispatchThread();
if (myChildren == null) {
initChildren();
myModel.getCacheLoader().load(this, myModel.getLazyLoadingExpander());
}
return myChildren;
}
public SVNURL getURL() {
return myURL;
}
@Nullable
public SVNDirEntry getSVNDirEntry() {
if (myUserObject instanceof SVNDirEntry) {
return (SVNDirEntry) myUserObject;
}
return null;
}
public void dispose() {
}
public TreeNode[] getSelfPath() {
return myModel.getPathToRoot(this);
}
public boolean isRepositoryRoot() {
return ! (myUserObject instanceof SVNDirEntry);
}
@NotNull
public List<TreeNode> getAllAlreadyLoadedChildren() {
if (myChildren != null) {
final List<TreeNode> result = new ArrayList<TreeNode>(myChildren.size());
for (TreeNode child : myChildren) {
result.add(child);
}
return result;
}
return Collections.emptyList();
}
@NotNull
public List<RepositoryTreeNode> getAlreadyLoadedChildren() {
if (myChildren != null) {
final List<RepositoryTreeNode> result = new ArrayList<RepositoryTreeNode>(myChildren.size());
for (TreeNode child : myChildren) {
if (child instanceof RepositoryTreeNode) {
result.add((RepositoryTreeNode) child);
}
}
return result;
}
return Collections.emptyList();
}
public boolean isDisposed() {
return myModel.isDisposed();
}
public void setChildren(final List<SVNDirEntry> children, final NodeLoadState state) {
final List<TreeNode> nodes = new ArrayList<TreeNode>();
for (final SVNDirEntry entry : children) {
if (!myModel.isShowFiles() && entry.getKind() != SVNNodeKind.DIR) {
continue;
}
nodes.add(new RepositoryTreeNode(myModel, this, entry.getURL(), entry, state));
}
myChildrenLoadState = state;
myChildren.clear();
myChildren.addAll(nodes);
myModel.reload(this);
}
public void setParentNode(final TreeNode parentNode) {
myParentNode = parentNode;
}
public void setAlienChildren(final List<TreeNode> children, final NodeLoadState oldState) {
if (myChildren == null) {
myChildren = new ArrayList<TreeNode>();
} else {
myChildren.clear();
}
for (TreeNode child : children) {
if (child instanceof RepositoryTreeNode) {
((RepositoryTreeNode) child).setParentNode(this);
myChildren.add(child);
myChildrenLoadState = oldState;
} else if (child instanceof DefaultMutableTreeNode) {
myChildren.add(new DefaultMutableTreeNode(((DefaultMutableTreeNode) child).getUserObject()));
myChildrenLoadState = oldState;
}
}
myModel.reload(this);
}
public void setErrorNode(final SVNErrorMessage text, final NodeLoadState state) {
if (myChildren == null) {
myChildren = new ArrayList<TreeNode>();
}
myChildren.clear();
myChildren.add(new DefaultMutableTreeNode(text));
myChildrenLoadState = NodeLoadState.ERROR;
myModel.reload(this);
}
public SvnVcs getVcs() {
return myModel.getVCS();
}
public boolean isCached() {
return NodeLoadState.CACHED.equals(myLoadState);
}
@Nullable
public RepositoryTreeNode getNodeWithSamePathUnderModelRoot() {
return myModel.findByUrl(this);
}
public RepositoryTreeModel getModel() {
return myModel;
}
public NodeLoadState getChildrenLoadState() {
return myChildrenLoadState;
}
public void doOnSubtree(final NotNullFunction<RepositoryTreeNode, Object> function) {
final SubTreeWalker walker = new SubTreeWalker(this, function);
walker.execute();
}
private static class SubTreeWalker {
private final RepositoryTreeNode myNode;
private final NotNullFunction<RepositoryTreeNode, Object> myFunction;
private SubTreeWalker(final RepositoryTreeNode node, final NotNullFunction<RepositoryTreeNode, Object> function) {
myNode = node;
myFunction = function;
}
public void execute() {
executeImpl(myNode);
}
private void executeImpl(final RepositoryTreeNode node) {
myFunction.fun(node);
for (RepositoryTreeNode child : node.getAlreadyLoadedChildren()) {
myFunction.fun(child);
}
}
}
}