/* * Copyright 2000-2017 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.execution.impl; import com.intellij.execution.*; import com.intellij.execution.configurations.ConfigurationFactory; import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.Key; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.TreeSpeedSearch; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.StringSetSpinAllocator; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Set; public abstract class BaseExecuteBeforeRunDialog<T extends BeforeRunTask> extends DialogWrapper { private final Project myProject; private DefaultMutableTreeNode myRoot; public BaseExecuteBeforeRunDialog(final Project project) { super(project, true); myProject = project; } @Override protected void init() { super.init(); setTitle(ExecutionBundle.message("execute.before.run.debug.dialog.title", getTargetDisplayString())); } @Override protected JComponent createCenterPanel() { JPanel panel = new JPanel(new BorderLayout()); myRoot = buildNodes(); final Tree tree = new Tree(myRoot); final MyTreeCellRenderer cellRenderer = new MyTreeCellRenderer(); tree.setCellRenderer(cellRenderer); tree.setRootVisible(false); tree.setShowsRootHandles(true); tree.setLineStyleAngled(); TreeUtil.installActions(tree); new TreeSpeedSearch(tree); tree.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { int row = tree.getRowForLocation(e.getX(), e.getY()); if (row >= 0) { Rectangle rowBounds = tree.getRowBounds(row); cellRenderer.setBounds(rowBounds); Rectangle checkBounds = cellRenderer.myCheckbox.getBounds(); checkBounds.setLocation(rowBounds.getLocation()); if (checkBounds.contains(e.getPoint())) { toggleNode(tree, (DefaultMutableTreeNode)tree.getPathForRow(row).getLastPathComponent()); e.consume(); tree.setSelectionRow(row); } } } }); tree.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SPACE) { TreePath treePath = tree.getLeadSelectionPath(); DefaultMutableTreeNode node = (DefaultMutableTreeNode)treePath.getLastPathComponent(); toggleNode(tree, node); e.consume(); } } }); expacndChecked(tree); JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(tree); scrollPane.setPreferredSize(JBUI.size(400, 400)); panel.add(scrollPane, BorderLayout.CENTER); return panel; } private static void expacndChecked(Tree tree) { TreeNode root = (TreeNode)tree.getModel().getRoot(); Enumeration factories = root.children(); ArrayList<TreeNode[]> toExpand = new ArrayList<>(); while (factories.hasMoreElements()) { DefaultMutableTreeNode factoryNode = (DefaultMutableTreeNode)factories.nextElement(); Enumeration configurations = factoryNode.children(); while (configurations.hasMoreElements()) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)configurations.nextElement(); ConfigurationDescriptor config = (ConfigurationDescriptor)node.getUserObject(); if (config.isChecked()) { toExpand.add(factoryNode.getPath()); break; } } } for (TreeNode[] treeNodes : toExpand) { tree.expandPath(new TreePath(treeNodes)); } } private static void toggleNode(JTree tree, DefaultMutableTreeNode node) { Descriptor descriptor = (Descriptor)node.getUserObject(); descriptor.setChecked(!descriptor.isChecked()); tree.repaint(); } private DefaultMutableTreeNode buildNodes() { DefaultMutableTreeNode root = new DefaultMutableTreeNode(new Descriptor()); RunManager runManager = RunManager.getInstance(myProject); for (final ConfigurationType type : runManager.getConfigurationFactories()) { final Icon icon = type.getIcon(); DefaultMutableTreeNode typeNode = new DefaultMutableTreeNode(new ConfigurationTypeDescriptor(type, icon, isConfigurationAssigned(type))); root.add(typeNode); final Set<String> addedNames = StringSetSpinAllocator.alloc(); try { List<RunConfiguration> configurations = runManager.getConfigurationsList(type); for (final RunConfiguration configuration : configurations) { final String configurationName = configuration.getName(); if (addedNames.contains(configurationName)) { // add only the first configuration if more than one has the same name continue; } addedNames.add(configurationName); typeNode.add(new DefaultMutableTreeNode( new ConfigurationDescriptor(configuration, isConfigurationAssigned(configuration)))); } } finally { StringSetSpinAllocator.dispose(addedNames); } } return root; } private boolean isConfigurationAssigned(ConfigurationType type) { final RunManager runManager = RunManager.getInstance(myProject); for (ConfigurationFactory factory : type.getConfigurationFactories()) { final RunnerAndConfigurationSettings settings = ((RunManagerImpl)runManager).getConfigurationTemplate(factory); if (isConfigurationAssigned(settings.getConfiguration())) return true; } return false; } private boolean isConfigurationAssigned(RunConfiguration configuration) { for (T task : RunManagerEx.getInstanceEx(myProject).getBeforeRunTasks(configuration, getTaskID())) { if (isRunning(task)) return true; } return false; } @Override protected void doOKAction() { final RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(myProject); for (Enumeration nodes = myRoot.depthFirstEnumeration(); nodes.hasMoreElements(); ) { final DefaultMutableTreeNode node = (DefaultMutableTreeNode)nodes.nextElement(); final Descriptor descriptor = (Descriptor)node.getUserObject(); final boolean isChecked = descriptor.isChecked(); if (descriptor instanceof ConfigurationTypeDescriptor) { ConfigurationTypeDescriptor typeDesc = (ConfigurationTypeDescriptor)descriptor; for (ConfigurationFactory factory : typeDesc.getConfigurationType().getConfigurationFactories()) { RunnerAndConfigurationSettings settings = runManager.getConfigurationTemplate(factory); update(settings.getConfiguration(), isChecked, runManager); } } else if (descriptor instanceof ConfigurationDescriptor) { ConfigurationDescriptor configDesc = (ConfigurationDescriptor)descriptor; update(configDesc.getConfiguration(), isChecked, runManager); } } RunManagerImpl.getInstanceImpl(myProject).fireBeforeRunTasksUpdated(); close(OK_EXIT_CODE); } protected abstract String getTargetDisplayString(); protected abstract Key<T> getTaskID(); protected abstract boolean isRunning(T task); private void update(RunConfiguration config, boolean enabled, RunManagerImpl runManager) { List<BeforeRunTask<?>> tasks = runManager.getBeforeRunTasks(config); BeforeRunTaskProvider<T> provider = BeforeRunTaskProvider.getProvider(myProject, getTaskID()); if (provider == null) { return; } T task = provider.createTask(config); update(task); task.setEnabled(true); if (enabled) { if (!tasks.contains(task)) { tasks.add(task); } } else { if (tasks.contains(task)) { tasks.remove(task); } } runManager.setBeforeRunTasks(config, tasks, false); } protected abstract void update(T task); protected abstract void clear(T task); private static class Descriptor { private boolean myChecked; public final boolean isChecked() { return myChecked; } public final void setChecked(boolean checked) { myChecked = checked; } } private static final class ConfigurationTypeDescriptor extends Descriptor { private final ConfigurationType myConfigurationType; private final Icon myIcon; public ConfigurationTypeDescriptor(ConfigurationType type, Icon icon, boolean isChecked) { myConfigurationType = type; myIcon = icon; setChecked(isChecked); } public ConfigurationType getConfigurationType() { return myConfigurationType; } public Icon getIcon() { return myIcon; } } private static final class ConfigurationDescriptor extends Descriptor { private final RunConfiguration myConfiguration; public ConfigurationDescriptor(RunConfiguration configuration, boolean isChecked) { myConfiguration = configuration; setChecked(isChecked); } public ConfigurationType getConfigurationFactory() { return myConfiguration.getType(); } public String getName() { return myConfiguration.getName(); } public RunConfiguration getConfiguration() { return myConfiguration; } } private static final class MyTreeCellRenderer extends JPanel implements TreeCellRenderer { private final JLabel myLabel; public final JCheckBox myCheckbox; public MyTreeCellRenderer() { super(new BorderLayout()); myCheckbox = new JCheckBox(); myLabel = new JLabel(); add(myCheckbox, BorderLayout.WEST); add(myLabel, BorderLayout.CENTER); } @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; Descriptor descriptor = (Descriptor)node.getUserObject(); myCheckbox.setSelected(descriptor.isChecked()); myCheckbox.setBackground(UIUtil.getTreeTextBackground()); setBackground(selected ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeTextBackground()); final Color foreground = selected ? UIUtil.getTreeSelectionForeground() : UIUtil.getTreeTextForeground(); setForeground(foreground); myCheckbox.setForeground(foreground); myLabel.setForeground(foreground); myCheckbox.setEnabled(true); if (descriptor instanceof ConfigurationTypeDescriptor) { ConfigurationTypeDescriptor configurationTypeDescriptor = (ConfigurationTypeDescriptor)descriptor; myLabel.setFont(tree.getFont()); myLabel.setText(configurationTypeDescriptor.getConfigurationType().getDisplayName()); myLabel.setIcon(configurationTypeDescriptor.getIcon()); } else if (descriptor instanceof ConfigurationDescriptor) { ConfigurationDescriptor configurationTypeDescriptor = (ConfigurationDescriptor)descriptor; myLabel.setFont(tree.getFont()); myLabel.setText(configurationTypeDescriptor.getName()); myLabel.setIcon(null); if (((ConfigurationTypeDescriptor)((DefaultMutableTreeNode)node.getParent()).getUserObject()).isChecked()) { Color foregrnd = tree.getForeground(); Color backgrnd = tree.getBackground(); if (foregrnd == null) foregrnd = Color.black; if (backgrnd == null) backgrnd = Color.white; int red = (foregrnd.getRed() + backgrnd.getRed()) / 2; int green = (foregrnd.getGreen() + backgrnd.getGreen()) / 2; int blue = (foregrnd.getBlue() + backgrnd.getBlue()) / 2; Color halftone = new Color(red, green, blue); setForeground(halftone); myCheckbox.setForeground(halftone); myLabel.setForeground(halftone); myCheckbox.setEnabled(false); } } return this; } } }