package com.intellij.lang.javascript.flex.actions;
import com.intellij.lang.javascript.flex.FlexModuleType;
import com.intellij.lang.javascript.flex.projectStructure.model.FlexBuildConfiguration;
import com.intellij.lang.javascript.flex.projectStructure.model.FlexBuildConfigurationManager;
import com.intellij.lang.javascript.flex.projectStructure.options.BCUtils;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Pair;
import com.intellij.ui.CheckboxTree;
import com.intellij.ui.CheckedTreeNode;
import com.intellij.ui.TreeSpeedSearch;
import com.intellij.util.CollectConsumer;
import com.intellij.util.Consumer;
import com.intellij.util.EventDispatcher;
import com.intellij.util.ui.tree.TreeUtil;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.tree.DefaultTreeModel;
import java.util.Collection;
import java.util.Enumeration;
public class FlexBCTree extends CheckboxTree {
private final Project myProject;
private final EventDispatcher<ChangeListener> myDispatcher = EventDispatcher.create(ChangeListener.class);
public FlexBCTree(final Project project) {
//noinspection unchecked
this(project, Conditions.alwaysTrue());
}
public FlexBCTree(final Project project, final Condition<FlexBuildConfiguration> bcFilter) {
super(createRenderer(), new CheckedTreeNode(project), new CheckPolicy(true, true, true, true));
myProject = project;
setRootVisible(true);
setShowsRootHandles(false);
final CheckedTreeNode rootNode = (CheckedTreeNode)getModel().getRoot();
addNodes(rootNode, bcFilter);
((DefaultTreeModel)getModel()).reload(rootNode);
TreeUtil.expandAll(this);
}
public void addToggleCheckBoxListener(final ChangeListener listener) {
myDispatcher.addListener(listener);
}
@Override
protected void onNodeStateChanged(CheckedTreeNode node) {
myDispatcher.getMulticaster().stateChanged(new ChangeEvent(node));
}
public Collection<Pair<Module, FlexBuildConfiguration>> getSelectedBCs() {
return getBCs(true);
}
public Collection<Pair<Module, FlexBuildConfiguration>> getDeselectedBCs() {
return getBCs(false);
}
private Collection<Pair<Module, FlexBuildConfiguration>> getBCs(final boolean checked) {
final CollectConsumer<Pair<Module, FlexBuildConfiguration>> consumer =
new CollectConsumer<>();
iterateRecursively((CheckedTreeNode)getModel().getRoot(), checked, consumer);
return consumer.getResult();
}
public void setCheckedStatusForAll(final boolean checked) {
final CheckedTreeNode node = (CheckedTreeNode)getModel().getRoot();
node.setChecked(checked);
setChildrenCheckedRecursively(node, checked);
}
private static void setChildrenCheckedRecursively(final CheckedTreeNode node, final boolean checked) {
final Enumeration children = node.children();
while (children.hasMoreElements()) {
final CheckedTreeNode childNode = (CheckedTreeNode)children.nextElement();
childNode.setChecked(checked);
setChildrenCheckedRecursively(childNode, checked);
}
}
public void setChecked(final String moduleName, final String bcName, final boolean checked) {
final CheckedTreeNode node = getBCNode(moduleName, bcName);
if (node != null) {
node.setChecked(checked);
}
}
private CheckedTreeNode getBCNode(final String moduleName, final String bcName) {
final Enumeration moduleNodes = ((CheckedTreeNode)getModel().getRoot()).children();
while (moduleNodes.hasMoreElements()) {
final CheckedTreeNode moduleNode = (CheckedTreeNode)moduleNodes.nextElement();
final Object userObject = moduleNode.getUserObject();
if (userObject instanceof Module && ((Module)userObject).getName().equals(moduleName)) {
final Enumeration bcNodes = moduleNode.children();
while (bcNodes.hasMoreElements()) {
final CheckedTreeNode bcNode = (CheckedTreeNode)bcNodes.nextElement();
final Object bcUserObject = bcNode.getUserObject();
if (bcUserObject instanceof FlexBuildConfiguration && ((FlexBuildConfiguration)bcUserObject).getName().equals(bcName)) {
return bcNode;
}
}
return null;
}
}
return null;
}
public void selectRow(final Module module, final FlexBuildConfiguration bc) {
clearSelection();
final CheckedTreeNode node = getBCNode(module.getName(), bc.getName());
if (node != null) {
TreeUtil.selectInTree(node, true, this);
}
}
private static void iterateRecursively(final CheckedTreeNode node,
final boolean iterateChecked,
final Consumer<Pair<Module, FlexBuildConfiguration>> consumer) {
if (node.isLeaf()) {
if (node.isChecked() == iterateChecked && node.getParent() instanceof CheckedTreeNode) {
final Object userObject = node.getUserObject();
final Object parentUserObject = ((CheckedTreeNode)node.getParent()).getUserObject();
if (userObject instanceof FlexBuildConfiguration && parentUserObject instanceof Module) {
consumer.consume(Pair.create((Module)parentUserObject, (FlexBuildConfiguration)userObject));
}
}
}
else {
// do not try to optimize asking non-leaf node about its checked status - it may give unexpected result!
final Enumeration children = node.children();
while (children.hasMoreElements()) {
iterateRecursively((CheckedTreeNode)children.nextElement(), iterateChecked, consumer);
}
}
}
private static CheckboxTreeCellRenderer createRenderer() {
return new CheckboxTree.CheckboxTreeCellRenderer() {
public void customizeRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (!(value instanceof CheckedTreeNode)) return;
final CheckedTreeNode node = (CheckedTreeNode)value;
final Object userObject = node.getUserObject();
if (userObject instanceof Project) {
getTextRenderer().append(((Project)userObject).getName());
}
else if (userObject instanceof Module) {
getTextRenderer().setIcon(ModuleType.get((Module)userObject).getIcon());
getTextRenderer().append(((Module)userObject).getName());
}
else if (userObject instanceof FlexBuildConfiguration) {
BCUtils.renderBuildConfiguration((FlexBuildConfiguration)userObject, null, false).appendToComponent(getTextRenderer());
getTextRenderer().setIcon(((FlexBuildConfiguration)userObject).getIcon());
}
}
};
}
private void addNodes(final CheckedTreeNode rootNode, final Condition<FlexBuildConfiguration> bcFilter) {
final FlexModuleType flexModuleType = FlexModuleType.getInstance();
for (Module module : ModuleManager.getInstance(myProject).getModules()) {
if (ModuleType.get(module) != flexModuleType) continue;
final CheckedTreeNode moduleNode = new CheckedTreeNode(module);
for (FlexBuildConfiguration bc : FlexBuildConfigurationManager.getInstance(module).getBuildConfigurations()) {
if (bcFilter.value(bc)) {
moduleNode.add(new CheckedTreeNode(bc));
}
}
if (moduleNode.getChildCount() > 0) {
rootNode.add(moduleNode);
}
}
}
protected void installSpeedSearch() {
new TreeSpeedSearch(this, path -> {
final CheckedTreeNode node = (CheckedTreeNode)path.getLastPathComponent();
final Object userObject = node.getUserObject();
if (userObject instanceof Project) {
return ((Project)userObject).getName();
}
else if (userObject instanceof Module) {
return ((Module)userObject).getName();
}
else if (userObject instanceof FlexBuildConfiguration) {
return ((FlexBuildConfiguration)userObject).getName();
}
return null;
});
}
}