mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
git log: test for checkbox tree for structure chooser (tree where you can select only limited number of nodes)
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.util;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 2/4/11
|
||||
* Time: 3:36 PM
|
||||
*/
|
||||
public enum TreeNodeState {
|
||||
SELECTED,CLEAR,HAVE_SELECTED_ABOVE,HAVE_SELECTED_BELOW
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.util.treeWithCheckedNodes;
|
||||
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.TreeNodeState;
|
||||
import com.intellij.util.containers.SLRUMap;
|
||||
import com.intellij.util.containers.hash.HashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 2/7/11
|
||||
* Time: 10:40 AM
|
||||
*
|
||||
* We can have only limited number of nodes selected in a tree;
|
||||
* and children of selected nodes (any level) cannot change their state
|
||||
* used together with {@link SelectionManager}
|
||||
*/
|
||||
public class SelectedState<T> {
|
||||
private final Set<T> mySelected;
|
||||
private final SLRUMap<T, TreeNodeState> myCache;
|
||||
private final int mySelectedSize;
|
||||
|
||||
public SelectedState(final int selectedSize, final int queueSize) {
|
||||
mySelectedSize = selectedSize;
|
||||
assert queueSize > 0;
|
||||
mySelected = new HashSet<T>();
|
||||
myCache = new SLRUMap<T, TreeNodeState>(queueSize,queueSize);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public TreeNodeState get(final T node) {
|
||||
if (mySelected.contains(node)) return TreeNodeState.SELECTED;
|
||||
return myCache.get(node);
|
||||
}
|
||||
|
||||
public void clear(final T node) {
|
||||
myCache.remove(node);
|
||||
mySelected.remove(node);
|
||||
}
|
||||
|
||||
public void clearAllCachedMatching(final Processor<T> processor) {
|
||||
final Set<Map.Entry<T, TreeNodeState>> entries = myCache.entrySet();
|
||||
for (Map.Entry<T, TreeNodeState> entry: entries){
|
||||
if(processor.process(entry.getKey())) {
|
||||
myCache.remove(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(final T node) {
|
||||
mySelected.remove(node);
|
||||
myCache.remove(node);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TreeNodeState putAndPass(final T node, @NotNull final TreeNodeState state) {
|
||||
if (TreeNodeState.SELECTED.equals(state)) {
|
||||
mySelected.add(node);
|
||||
myCache.remove(node);
|
||||
} else {
|
||||
mySelected.remove(node);
|
||||
myCache.put(node, state);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
public boolean canAddSelection() {
|
||||
return mySelected.size() < mySelectedSize;
|
||||
}
|
||||
|
||||
public Set<T> getSelected() {
|
||||
return Collections.unmodifiableSet(mySelected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.util.treeWithCheckedNodes;
|
||||
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.TreeNodeState;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 2/7/11
|
||||
* Time: 10:43 AM
|
||||
*
|
||||
* see {@link SelectedState}
|
||||
*/
|
||||
public class SelectionManager {
|
||||
private final SelectedState<VirtualFile> myState;
|
||||
private final Convertor<DefaultMutableTreeNode, VirtualFile> myNodeConvertor;
|
||||
|
||||
public SelectionManager(int selectedSize, int queueSize, final Convertor<DefaultMutableTreeNode, VirtualFile> nodeConvertor) {
|
||||
myNodeConvertor = nodeConvertor;
|
||||
myState = new SelectedState<VirtualFile>(selectedSize, queueSize);
|
||||
}
|
||||
|
||||
public void toggleSelection(final DefaultMutableTreeNode node) {
|
||||
final StateWorker stateWorker = new StateWorker(node, myNodeConvertor);
|
||||
if (stateWorker.getVf() == null) return;
|
||||
|
||||
final TreeNodeState state = getStateImpl(stateWorker);
|
||||
if (TreeNodeState.HAVE_SELECTED_ABOVE.equals(state)) return;
|
||||
if (TreeNodeState.CLEAR.equals(state) && (! myState.canAddSelection())) return;
|
||||
|
||||
final TreeNodeState futureState =
|
||||
myState.putAndPass(stateWorker.getVf(), TreeNodeState.SELECTED.equals(state) ? TreeNodeState.CLEAR : TreeNodeState.SELECTED);
|
||||
|
||||
// for those possibly duplicate nodes (i.e. when we have root for module and root for VCS root, each file is shown twice in a tree ->
|
||||
// clear all suspicious cached)
|
||||
if (! TreeNodeState.SELECTED.equals(futureState)) {
|
||||
myState.clearAllCachedMatching(new Processor<VirtualFile>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile virtualFile) {
|
||||
return VfsUtil.isAncestor(virtualFile, stateWorker.getVf(), false);
|
||||
}
|
||||
});
|
||||
}
|
||||
stateWorker.iterateParents(myState, new PairProcessor<VirtualFile, TreeNodeState>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile virtualFile, TreeNodeState state) {
|
||||
if (TreeNodeState.SELECTED.equals(futureState)) {
|
||||
myState.putAndPass(virtualFile, TreeNodeState.HAVE_SELECTED_BELOW);
|
||||
} else {
|
||||
myState.remove(virtualFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
myState.clearAllCachedMatching(new Processor<VirtualFile>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile vf) {
|
||||
return VfsUtil.isAncestor(stateWorker.getVf(), vf, false);
|
||||
}
|
||||
});
|
||||
for (VirtualFile selected : myState.getSelected()) {
|
||||
if (VfsUtil.isAncestor(stateWorker.getVf(), selected, true)) {
|
||||
myState.remove(selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TreeNodeState getState(final DefaultMutableTreeNode node) {
|
||||
return getStateImpl(new StateWorker(node, myNodeConvertor));
|
||||
}
|
||||
|
||||
private TreeNodeState getStateImpl(final StateWorker stateWorker) {
|
||||
if (stateWorker.getVf() == null) return TreeNodeState.CLEAR;
|
||||
|
||||
final TreeNodeState stateSelf = myState.get(stateWorker.getVf());
|
||||
if (stateSelf != null) return stateSelf;
|
||||
|
||||
final Ref<TreeNodeState> result = new Ref<TreeNodeState>();
|
||||
stateWorker.iterateParents(myState, new PairProcessor<VirtualFile, TreeNodeState>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile virtualFile, TreeNodeState state) {
|
||||
if (state != null) {
|
||||
if (TreeNodeState.SELECTED.equals(state) || TreeNodeState.HAVE_SELECTED_ABOVE.equals(state)) {
|
||||
result.set(myState.putAndPass(stateWorker.getVf(), TreeNodeState.HAVE_SELECTED_ABOVE));
|
||||
}
|
||||
return false; // exit
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (! result.isNull()) return result.get();
|
||||
|
||||
for (VirtualFile selected : myState.getSelected()) {
|
||||
if (VfsUtil.isAncestor(stateWorker.getVf(), selected, true)) {
|
||||
return myState.putAndPass(stateWorker.getVf(), TreeNodeState.HAVE_SELECTED_BELOW);
|
||||
}
|
||||
}
|
||||
return TreeNodeState.CLEAR;
|
||||
}
|
||||
|
||||
private static class StateWorker {
|
||||
private final DefaultMutableTreeNode myNode;
|
||||
private final Convertor<DefaultMutableTreeNode, VirtualFile> myConvertor;
|
||||
private VirtualFile myVf;
|
||||
|
||||
private StateWorker(DefaultMutableTreeNode node, final Convertor<DefaultMutableTreeNode, VirtualFile> convertor) {
|
||||
myNode = node;
|
||||
myConvertor = convertor;
|
||||
myVf = myConvertor.convert(node);
|
||||
}
|
||||
|
||||
public VirtualFile getVf() {
|
||||
return myVf;
|
||||
}
|
||||
|
||||
public void iterateParents(final SelectedState<VirtualFile> states, final PairProcessor<VirtualFile, TreeNodeState> parentsProcessor) {
|
||||
DefaultMutableTreeNode current = (DefaultMutableTreeNode) myNode.getParent();
|
||||
// up cycle
|
||||
while (current != null) {
|
||||
final VirtualFile file = myConvertor.convert(current);
|
||||
if (file == null) return;
|
||||
|
||||
final TreeNodeState state = states.get(file);
|
||||
if (! parentsProcessor.process(file, state)) return;
|
||||
current = (DefaultMutableTreeNode)current.getParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user