| /* |
| * 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.CommonBundle; |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.util.NotNullFunction; |
| import com.intellij.util.containers.ContainerUtil; |
| import com.intellij.util.containers.FilteringIterator; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.idea.svn.SvnVcs; |
| import org.jetbrains.idea.svn.browse.DirectoryEntry; |
| import org.jetbrains.idea.svn.dialogs.browserCache.Expander; |
| import org.jetbrains.idea.svn.dialogs.browserCache.NodeLoadState; |
| import org.tmatesoft.svn.core.SVNURL; |
| import org.tmatesoft.svn.core.internal.util.SVNPathUtil; |
| |
| 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; |
| @NotNull private final List<TreeNode> myChildren; |
| private final RepositoryTreeModel myModel; |
| private final SVNURL myURL; |
| private final Object myUserObject; |
| |
| @NotNull private final NodeLoadState myLoadState; |
| private NodeLoadState myChildrenLoadState; |
| |
| public RepositoryTreeNode(RepositoryTreeModel model, TreeNode parentNode, |
| @NotNull SVNURL url, Object userObject, @NotNull NodeLoadState state) { |
| myParentNode = parentNode; |
| |
| myURL = url; |
| myModel = model; |
| myUserObject = userObject; |
| |
| myLoadState = state; |
| myChildren = ContainerUtil.newArrayList(); |
| 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 DirectoryEntry && ((DirectoryEntry)myUserObject).isFile(); |
| } |
| |
| 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(@NotNull Expander expander, boolean removeCurrentChildren) { |
| ApplicationManager.getApplication().assertIsDispatchThread(); |
| |
| if (removeCurrentChildren || NodeLoadState.EMPTY.equals(myChildrenLoadState)) { |
| initChildren(); |
| } |
| |
| myModel.getCacheLoader().load(this, expander); |
| } |
| |
| private void initChildren() { |
| myChildren.clear(); |
| myChildren.add(new SimpleTextNode(CommonBundle.getLoadingTreeNodeText())); |
| myChildrenLoadState = NodeLoadState.LOADING; |
| } |
| |
| private List getChildren() { |
| ApplicationManager.getApplication().assertIsDispatchThread(); |
| |
| if (NodeLoadState.EMPTY.equals(myChildrenLoadState)) { |
| initChildren(); |
| myModel.getCacheLoader().load(this, myModel.getLazyLoadingExpander()); |
| } |
| return myChildren; |
| } |
| |
| public SVNURL getURL() { |
| return myURL; |
| } |
| |
| @Nullable |
| public DirectoryEntry getSVNDirEntry() { |
| return myUserObject instanceof DirectoryEntry ? (DirectoryEntry)myUserObject : null; |
| } |
| |
| public void dispose() { |
| } |
| |
| public TreeNode[] getSelfPath() { |
| return myModel.getPathToRoot(this); |
| } |
| |
| public boolean isRepositoryRoot() { |
| return ! (myUserObject instanceof DirectoryEntry); |
| } |
| |
| @NotNull |
| public List<TreeNode> getAllAlreadyLoadedChildren() { |
| return ContainerUtil.newArrayList(myChildren); |
| } |
| |
| @NotNull |
| public List<RepositoryTreeNode> getAlreadyLoadedChildren() { |
| return ContainerUtil.collect(myChildren.iterator(), FilteringIterator.instanceOf(RepositoryTreeNode.class)); |
| } |
| |
| public boolean isDisposed() { |
| return myModel.isDisposed(); |
| } |
| |
| public void setChildren(@NotNull List<DirectoryEntry> children, @NotNull NodeLoadState state) { |
| final List<TreeNode> nodes = new ArrayList<TreeNode>(); |
| for (final DirectoryEntry entry : children) { |
| if (!myModel.isShowFiles() && !entry.isDirectory()) { |
| 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) { |
| myChildren.clear(); |
| |
| for (TreeNode child : children) { |
| if (child instanceof RepositoryTreeNode) { |
| ((RepositoryTreeNode) child).setParentNode(this); |
| myChildren.add(child); |
| myChildrenLoadState = oldState; |
| } |
| else if (child instanceof SimpleTextNode) { |
| SimpleTextNode node = (SimpleTextNode)child; |
| myChildren.add(new SimpleTextNode(node.getText(), node.isError())); |
| myChildrenLoadState = oldState; |
| } |
| } |
| |
| myModel.reload(this); |
| } |
| |
| public void setErrorNode(@NotNull String text) { |
| myChildren.clear(); |
| myChildren.add(new SimpleTextNode(text, true)); |
| 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 NodeLoadState getChildrenLoadState() { |
| return myChildrenLoadState; |
| } |
| |
| public void doOnSubtree(@NotNull NotNullFunction<RepositoryTreeNode, Object> function) { |
| new SubTreeWalker(this, function).execute(); |
| } |
| |
| private static class SubTreeWalker { |
| |
| @NotNull private final RepositoryTreeNode myNode; |
| @NotNull private final NotNullFunction<RepositoryTreeNode, Object> myFunction; |
| |
| private SubTreeWalker(@NotNull RepositoryTreeNode node, @NotNull 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); |
| } |
| } |
| } |
| } |