| /* |
| * 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.framework.detection.impl.ui; |
| |
| import com.intellij.framework.FrameworkType; |
| import com.intellij.framework.detection.DetectedFrameworkDescription; |
| import com.intellij.framework.detection.FrameworkDetectionContext; |
| import com.intellij.framework.detection.impl.FrameworkDetectionUtil; |
| import com.intellij.openapi.vfs.VfsUtil; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.ui.CheckboxTree; |
| import com.intellij.ui.CheckedTreeNode; |
| import com.intellij.util.Consumer; |
| import com.intellij.util.ui.tree.TreeUtil; |
| import org.jetbrains.annotations.NotNull; |
| |
| import javax.swing.*; |
| import javax.swing.tree.DefaultMutableTreeNode; |
| import javax.swing.tree.DefaultTreeModel; |
| import javax.swing.tree.TreeNode; |
| import java.util.*; |
| |
| /** |
| * @author nik |
| */ |
| public class DetectedFrameworksTree extends CheckboxTree { |
| private List<? extends DetectedFrameworkDescription> myDetectedFrameworks; |
| private final FrameworkDetectionContext myContext; |
| private DetectedFrameworksComponent.GroupByOption myGroupByOption; |
| |
| public DetectedFrameworksTree(final FrameworkDetectionContext context, DetectedFrameworksComponent.GroupByOption groupByOption) { |
| super(new DetectedFrameworksTreeRenderer(), new CheckedTreeNode(null), new CheckPolicy(true, true, true, false)); |
| myContext = context; |
| myGroupByOption = groupByOption; |
| setShowsRootHandles(false); |
| setRootVisible(false); |
| } |
| |
| private void createNodesGroupedByDirectory(CheckedTreeNode root, final List<? extends DetectedFrameworkDescription> frameworks) { |
| Map<VirtualFile, FrameworkDirectoryNode> nodes = new HashMap<VirtualFile, FrameworkDirectoryNode>(); |
| List<DetectedFrameworkNode> externalNodes = new ArrayList<DetectedFrameworkNode>(); |
| for (DetectedFrameworkDescription framework : frameworks) { |
| VirtualFile parent = VfsUtil.getCommonAncestor(framework.getRelatedFiles()); |
| if (parent != null && !parent.isDirectory()) { |
| parent = parent.getParent(); |
| } |
| |
| final DetectedFrameworkNode frameworkNode = new DetectedFrameworkNode(framework, myContext); |
| if (parent != null) { |
| createDirectoryNodes(parent, nodes).add(frameworkNode); |
| } |
| else { |
| externalNodes.add(frameworkNode); |
| } |
| } |
| List<FrameworkDirectoryNode> rootDirs = new ArrayList<FrameworkDirectoryNode>(); |
| for (FrameworkDirectoryNode directoryNode : nodes.values()) { |
| if (directoryNode.getParent() == null) { |
| rootDirs.add(directoryNode); |
| } |
| } |
| for (FrameworkDirectoryNode dir : rootDirs) { |
| root.add(collapseDirectoryNode(dir)); |
| } |
| for (DetectedFrameworkNode node : externalNodes) { |
| root.add(node); |
| } |
| } |
| |
| public void processUncheckedNodes(@NotNull final Consumer<DetectedFrameworkTreeNodeBase> consumer) { |
| TreeUtil.traverse(getRoot(), new TreeUtil.Traverse() { |
| @Override |
| public boolean accept(Object node) { |
| if (node instanceof DetectedFrameworkTreeNodeBase) { |
| final DetectedFrameworkTreeNodeBase frameworkNode = (DetectedFrameworkTreeNodeBase)node; |
| if (!frameworkNode.isChecked()) { |
| consumer.consume(frameworkNode); |
| } |
| } |
| return true; |
| } |
| }); |
| } |
| |
| @Override |
| protected void onNodeStateChanged(CheckedTreeNode node) { |
| final List<DetectedFrameworkDescription> checked = Arrays.asList(getCheckedNodes(DetectedFrameworkDescription.class, null)); |
| final List<DetectedFrameworkDescription> disabled = FrameworkDetectionUtil.getDisabledDescriptions(checked, Collections.<DetectedFrameworkDescription>emptyList()); |
| for (DetectedFrameworkDescription description : disabled) { |
| final DefaultMutableTreeNode treeNode = TreeUtil.findNodeWithObject(getRoot(), description); |
| if (treeNode instanceof CheckedTreeNode) { |
| ((CheckedTreeNode)treeNode).setChecked(false); |
| } |
| } |
| } |
| |
| private static FrameworkDirectoryNode collapseDirectoryNode(FrameworkDirectoryNode node) { |
| if (node.getChildCount() == 1) { |
| final TreeNode child = node.getChildAt(0); |
| if (child instanceof FrameworkDirectoryNode) { |
| return collapseDirectoryNode((FrameworkDirectoryNode)child); |
| } |
| } |
| for (int i = 0; i < node.getChildCount(); i++) { |
| TreeNode child = node.getChildAt(i); |
| if (child instanceof FrameworkDirectoryNode) { |
| final FrameworkDirectoryNode collapsed = collapseDirectoryNode((FrameworkDirectoryNode)child); |
| if (collapsed != child) { |
| node.remove(i); |
| node.insert(collapsed, i); |
| } |
| } |
| } |
| return node; |
| } |
| |
| @NotNull |
| private static FrameworkDirectoryNode createDirectoryNodes(@NotNull VirtualFile dir, @NotNull Map<VirtualFile, FrameworkDirectoryNode> nodes) { |
| final FrameworkDirectoryNode node = nodes.get(dir); |
| if (node != null) { |
| return node; |
| } |
| |
| final FrameworkDirectoryNode newNode = new FrameworkDirectoryNode(dir); |
| nodes.put(dir, newNode); |
| final VirtualFile parent = dir.getParent(); |
| if (parent != null) { |
| createDirectoryNodes(parent, nodes).add(newNode); |
| } |
| return newNode; |
| } |
| |
| private void createNodesGroupedByType(CheckedTreeNode root, final List<? extends DetectedFrameworkDescription> frameworks) { |
| Map<FrameworkType, FrameworkTypeNode> groupNodes = new HashMap<FrameworkType, FrameworkTypeNode>(); |
| for (DetectedFrameworkDescription framework : frameworks) { |
| final FrameworkType type = framework.getDetector().getFrameworkType(); |
| FrameworkTypeNode group = groupNodes.get(type); |
| if (group == null) { |
| group = new FrameworkTypeNode(type); |
| groupNodes.put(type, group); |
| root.add(group); |
| } |
| group.add(new DetectedFrameworkNode(framework, myContext)); |
| } |
| } |
| |
| private CheckedTreeNode getRoot() { |
| return ((CheckedTreeNode)getModel().getRoot()); |
| } |
| |
| public void changeGroupBy(DetectedFrameworksComponent.GroupByOption option) { |
| if (myGroupByOption.equals(option)) return; |
| myGroupByOption = option; |
| if (myDetectedFrameworks != null) { |
| rebuildTree(myDetectedFrameworks); |
| } |
| } |
| |
| public void rebuildTree(final List<? extends DetectedFrameworkDescription> frameworks) { |
| final CheckedTreeNode root = getRoot(); |
| root.removeAllChildren(); |
| if (myGroupByOption == DetectedFrameworksComponent.GroupByOption.TYPE) { |
| createNodesGroupedByType(root, frameworks); |
| } |
| else { |
| createNodesGroupedByDirectory(root, frameworks); |
| } |
| ((DefaultTreeModel)getModel()).nodeStructureChanged(root); |
| TreeUtil.expandAll(this); |
| myDetectedFrameworks = frameworks; |
| } |
| |
| private static class DetectedFrameworksTreeRenderer extends CheckboxTreeCellRenderer { |
| private DetectedFrameworksTreeRenderer() { |
| super(true, false); |
| } |
| |
| @Override |
| public void customizeRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { |
| if (value instanceof DetectedFrameworkTreeNodeBase) { |
| ((DetectedFrameworkTreeNodeBase)value).renderNode(getTextRenderer()); |
| } |
| } |
| } |
| } |