package com.intellij.lang.javascript.flex.projectStructure.ui;
import com.intellij.lang.javascript.flex.FlexModuleType;
import com.intellij.lang.javascript.flex.projectStructure.FlexBCConfigurator;
import com.intellij.lang.javascript.flex.projectStructure.FlexBuildConfigurationsExtension;
import com.intellij.lang.javascript.flex.projectStructure.options.BCUtils;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ui.configuration.projectRoot.ModuleStructureConfigurable;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Condition;
import com.intellij.ui.*;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* @author ksafonov
*/
public class ChooseBuildConfigurationDialog extends DialogWrapper {
private final Map<Module, List<FlexBCConfigurable>> myTreeItems;
private Tree myTree;
private DefaultMutableTreeNode[] mySelection;
private JLabel myLabel;
private JPanel myContentPane;
private final boolean myAllowEmptySelection;
/**
* @param project
* @param filter
* @return <code>null</code> if there's no applicable BC configurables according to the filter provided
*/
@Nullable
public static ChooseBuildConfigurationDialog createForApplicableBCs(String title,
@Nullable String labelText,
Project project,
boolean allowEmptySelection,
Condition<FlexBCConfigurable> filter) {
Map<Module, List<FlexBCConfigurable>> treeItems = new HashMap<>();
FlexBCConfigurator configurator = FlexBuildConfigurationsExtension.getInstance().getConfigurator();
for (Module module : ModuleStructureConfigurable.getInstance(project).getModules()) {
if (ModuleType.get(module) != FlexModuleType.getInstance()) {
continue;
}
for (CompositeConfigurable configurable : configurator.getBCConfigurables(module)) {
FlexBCConfigurable flexBCConfigurable = FlexBCConfigurable.unwrap(configurable);
if (!filter.value(flexBCConfigurable)) {
continue;
}
List<FlexBCConfigurable> list = treeItems.get(module);
if (list == null) {
list = new ArrayList<>();
treeItems.put(module, list);
}
list.add(flexBCConfigurable);
}
}
if (treeItems.isEmpty()) {
return null;
}
return new ChooseBuildConfigurationDialog(title, labelText, project, allowEmptySelection, treeItems);
}
private ChooseBuildConfigurationDialog(String title,
@Nullable final String labelText,
Project project,
final boolean allowEmptySelection,
Map<Module, List<FlexBCConfigurable>> treeItems) {
super(project, true);
myAllowEmptySelection = allowEmptySelection;
if (labelText != null) {
myLabel.setText(labelText);
}
else {
myLabel.setVisible(false);
}
myTreeItems = treeItems;
setTitle(title);
init();
}
@Override
public JComponent getPreferredFocusedComponent() {
return myTree;
}
@Override
protected String getDimensionServiceKey() {
return getClass().getName();
}
@Override
protected JComponent createCenterPanel() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
List<Module> modules = new ArrayList<>(myTreeItems.keySet());
Collections.sort(modules, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName()));
for (Module module : modules) {
DefaultMutableTreeNode moduleNode = new DefaultMutableTreeNode(module, true);
root.add(moduleNode);
List<FlexBCConfigurable> bcs = myTreeItems.get(module);
Collections.sort(bcs, (o1, o2) -> o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName()));
for (FlexBCConfigurable bc : bcs) {
DefaultMutableTreeNode bcNode = new DefaultMutableTreeNode(bc, false);
moduleNode.add(bcNode);
}
}
myTree.setModel(new DefaultTreeModel(root));
myTree.setRootVisible(false);
new TreeSpeedSearch(myTree, o -> {
Object lastPathComponent = o.getLastPathComponent();
return getText((DefaultMutableTreeNode)lastPathComponent);
}, true).setComparator(new SpeedSearchComparator(false));
TreeUIHelper.getInstance().installTreeSpeedSearch(myTree);
myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
updateOnSelectionChange();
}
});
myTree.setCellRenderer(new ColoredTreeCellRenderer() {
@Override
public void customizeCellRenderer(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value;
Object object = treeNode.getUserObject();
if (object instanceof Module) {
Module module = (Module)object;
setIcon(ModuleType.get(module).getIcon());
append(module.getName());
}
else if (object instanceof FlexBCConfigurable) {
FlexBCConfigurable configurable = (FlexBCConfigurable)object;
setIcon(configurable.getIcon());
BCUtils.renderBuildConfiguration(configurable.getEditableObject(), null).appendToComponent(this);
}
}
});
TreeUtil.expandAll(myTree);
new DoubleClickListener() {
@Override
protected boolean onDoubleClick(MouseEvent e) {
if (mySelection != null) {
doOKAction();
return true;
}
return false;
}
}.installOn(myTree);
myTree.addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
doOKAction();
}
}
});
updateOnSelectionChange();
return myContentPane;
}
private void updateOnSelectionChange() {
mySelection = myTree.getSelectedNodes(DefaultMutableTreeNode.class, new Tree.NodeFilter<DefaultMutableTreeNode>() {
@Override
public boolean accept(DefaultMutableTreeNode node) {
return node.getUserObject() instanceof FlexBCConfigurable;
}
});
setOKActionEnabled(myAllowEmptySelection || mySelection.length > 0);
}
private static String getText(DefaultMutableTreeNode node) {
Object object = node.getUserObject();
if (object instanceof Module) {
Module module = (Module)object;
return module.getName();
}
else {
FlexBCConfigurable configurable = (FlexBCConfigurable)object;
return configurable.getTreeNodeText();
}
}
public FlexBCConfigurable[] getSelectedConfigurables() {
if (mySelection == null) {
return new FlexBCConfigurable[0];
}
return ContainerUtil.map2Array(mySelection, FlexBCConfigurable.class, node -> (FlexBCConfigurable)node.getUserObject());
}
}