blob: eab0ea6bcb363d7254a8519c4e694e8298d14c42 [file] [log] [blame]
package com.intellij.coverage.actions;
import com.intellij.coverage.*;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ComboBoxAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.*;
import com.intellij.util.IconUtil;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.HashMap;
import com.intellij.util.text.DateFormatUtil;
import com.intellij.util.ui.tree.TreeUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.*;
import java.util.List;
/**
* User: anna
* Date: 11/27/10
*/
public class CoverageSuiteChooserDialog extends DialogWrapper {
@NonNls private static final String LOCAL = "Local";
private final Project myProject;
private final CheckboxTree mySuitesTree;
private final CoverageDataManager myCoverageManager;
private static final Logger LOG = Logger.getInstance("#" + CoverageSuiteChooserDialog.class.getName());
private final CheckedTreeNode myRootNode;
private CoverageEngine myEngine;
public CoverageSuiteChooserDialog(Project project) {
super(project, true);
myProject = project;
myCoverageManager = CoverageDataManager.getInstance(project);
myRootNode = new CheckedTreeNode("");
initTree();
mySuitesTree = new CheckboxTree(new SuitesRenderer(), myRootNode) {
protected void installSpeedSearch() {
new TreeSpeedSearch(this, new Convertor<TreePath, String>() {
public String convert(TreePath path) {
final DefaultMutableTreeNode component = (DefaultMutableTreeNode)path.getLastPathComponent();
final Object userObject = component.getUserObject();
if (userObject instanceof CoverageSuite) {
return ((CoverageSuite)userObject).getPresentableName();
}
return userObject.toString();
}
});
}
};
mySuitesTree.getEmptyText().appendText("No coverage suites configured.");
mySuitesTree.setRootVisible(false);
mySuitesTree.setShowsRootHandles(false);
TreeUtil.installActions(mySuitesTree);
TreeUtil.expandAll(mySuitesTree);
TreeUtil.selectFirstNode(mySuitesTree);
mySuitesTree.setMinimumSize(new Dimension(25, -1));
setOKButtonText("Show selected");
init();
setTitle("Choose Coverage Suite to Display");
}
@Override
protected JComponent createCenterPanel() {
return ScrollPaneFactory.createScrollPane(mySuitesTree);
}
@Override
public JComponent getPreferredFocusedComponent() {
return mySuitesTree;
}
@Override
protected JComponent createNorthPanel() {
final DefaultActionGroup group = new DefaultActionGroup();
group.add(new AddExternalSuiteAction());
group.add(new DeleteSuiteAction());
group.add(new SwitchEngineAction());
return ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true).getComponent();
}
@Override
protected void doOKAction() {
final List<CoverageSuite> suites = collectSelectedSuites();
myCoverageManager.chooseSuitesBundle(suites.isEmpty() ? null : new CoverageSuitesBundle(suites.toArray(new CoverageSuite[suites.size()])));
super.doOKAction();
}
@NotNull
@Override
protected Action[] createActions() {
return new Action[]{getOKAction(), new NoCoverageAction(), getCancelAction()};
}
private Set<CoverageEngine> collectEngines() {
final Set<CoverageEngine> engines = new HashSet<CoverageEngine>();
for (CoverageSuite suite : myCoverageManager.getSuites()) {
engines.add(suite.getCoverageEngine());
}
return engines;
}
private static String getCoverageRunnerTitle(CoverageRunner coverageRunner) {
return coverageRunner.getPresentableName() + " Coverage";
}
@Nullable
private static CoverageRunner getCoverageRunner(VirtualFile file) {
for (CoverageRunner runner : Extensions.getExtensions(CoverageRunner.EP_NAME)) {
if (Comparing.strEqual(file.getExtension(), runner.getDataFileExtension())) return runner;
}
return null;
}
private List<CoverageSuite> collectSelectedSuites() {
final List<CoverageSuite> suites = new ArrayList<CoverageSuite>();
TreeUtil.traverse(myRootNode, new TreeUtil.Traverse() {
@Override
public boolean accept(Object treeNode) {
if (treeNode instanceof CheckedTreeNode && ((CheckedTreeNode)treeNode).isChecked()) {
final Object userObject = ((CheckedTreeNode)treeNode).getUserObject();
if (userObject instanceof CoverageSuite) {
suites.add((CoverageSuite)userObject);
}
}
return true;
}
});
return suites;
}
private void initTree() {
myRootNode.removeAllChildren();
final HashMap<CoverageRunner, Map<String, List<CoverageSuite>>> grouped =
new HashMap<CoverageRunner, Map<String, List<CoverageSuite>>>();
groupSuites(grouped, myCoverageManager.getSuites(), myEngine);
final CoverageSuitesBundle currentSuite = myCoverageManager.getCurrentSuitesBundle();
final List<CoverageRunner> runners = new ArrayList<CoverageRunner>(grouped.keySet());
Collections.sort(runners, new Comparator<CoverageRunner>() {
@Override
public int compare(CoverageRunner o1, CoverageRunner o2) {
return o1.getPresentableName().compareToIgnoreCase(o2.getPresentableName());
}
});
for (CoverageRunner runner : runners) {
final DefaultMutableTreeNode runnerNode = new DefaultMutableTreeNode(getCoverageRunnerTitle(runner));
final Map<String, List<CoverageSuite>> providers = grouped.get(runner);
final DefaultMutableTreeNode remoteNode = new DefaultMutableTreeNode("Remote");
if (providers.size() == 1) {
final String providersKey = providers.keySet().iterator().next();
DefaultMutableTreeNode suitesNode = runnerNode;
if (!Comparing.strEqual(providersKey, DefaultCoverageFileProvider.class.getName())) {
suitesNode = remoteNode;
runnerNode.add(remoteNode);
}
final List<CoverageSuite> suites = providers.get(providersKey);
Collections.sort(suites, new Comparator<CoverageSuite>() {
@Override
public int compare(CoverageSuite o1, CoverageSuite o2) {
return o1.getPresentableName().compareToIgnoreCase(o2.getPresentableName());
}
});
for (CoverageSuite suite : suites) {
final CheckedTreeNode treeNode = new CheckedTreeNode(suite);
treeNode.setChecked(currentSuite != null && currentSuite.contains(suite) ? Boolean.TRUE : Boolean.FALSE);
suitesNode.add(treeNode);
}
}
else {
final DefaultMutableTreeNode localNode = new DefaultMutableTreeNode(LOCAL);
runnerNode.add(localNode);
runnerNode.add(remoteNode);
for (String aClass : providers.keySet()) {
DefaultMutableTreeNode node = Comparing.strEqual(aClass, DefaultCoverageFileProvider.class.getName()) ? localNode : remoteNode;
for (CoverageSuite suite : providers.get(aClass)) {
final CheckedTreeNode treeNode = new CheckedTreeNode(suite);
treeNode.setChecked(currentSuite != null && currentSuite.contains(suite) ? Boolean.TRUE : Boolean.FALSE);
node.add(treeNode);
}
}
}
myRootNode.add(runnerNode);
}
}
private static void groupSuites(final HashMap<CoverageRunner, Map<String, List<CoverageSuite>>> grouped,
final CoverageSuite[] suites,
final CoverageEngine engine) {
for (CoverageSuite suite : suites) {
if (engine != null && suite.getCoverageEngine() != engine) continue;
final CoverageFileProvider provider = suite.getCoverageDataFileProvider();
if (provider instanceof DefaultCoverageFileProvider &&
Comparing.strEqual(((DefaultCoverageFileProvider)provider).getSourceProvider(), DefaultCoverageFileProvider.class.getName())) {
if (!provider.ensureFileExists()) continue;
}
final CoverageRunner runner = suite.getRunner();
Map<String, List<CoverageSuite>> byProviders = grouped.get(runner);
if (byProviders == null) {
byProviders = new HashMap<String, List<CoverageSuite>>();
grouped.put(runner, byProviders);
}
final String sourceProvider = provider instanceof DefaultCoverageFileProvider
? ((DefaultCoverageFileProvider)provider).getSourceProvider()
: provider.getClass().getName();
List<CoverageSuite> list = byProviders.get(sourceProvider);
if (list == null) {
list = new ArrayList<CoverageSuite>();
byProviders.put(sourceProvider, list);
}
list.add(suite);
}
}
private void updateTree() {
((DefaultTreeModel)mySuitesTree.getModel()).reload();
TreeUtil.expandAll(mySuitesTree);
}
private static class SuitesRenderer extends CheckboxTree.CheckboxTreeCellRenderer {
@Override
public void customizeRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (value instanceof CheckedTreeNode) {
final Object userObject = ((CheckedTreeNode)value).getUserObject();
if (userObject instanceof CoverageSuite) {
CoverageSuite suite = (CoverageSuite)userObject;
getTextRenderer().append(suite.getPresentableName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
final String date = " (" + DateFormatUtil.formatPrettyDateTime(suite.getLastCoverageTimeStamp()) + ")";
getTextRenderer().append(date, SimpleTextAttributes.GRAY_ATTRIBUTES);
}
}
else if (value instanceof DefaultMutableTreeNode) {
final Object userObject = ((DefaultMutableTreeNode)value).getUserObject();
if (userObject instanceof String) {
getTextRenderer().append((String)userObject);
}
}
}
}
private class NoCoverageAction extends DialogWrapperAction {
public NoCoverageAction() {
super("&No Coverage");
}
@Override
protected void doAction(ActionEvent e) {
myCoverageManager.chooseSuitesBundle(null);
CoverageSuiteChooserDialog.this.close(DialogWrapper.OK_EXIT_CODE);
}
}
private class AddExternalSuiteAction extends AnAction {
public AddExternalSuiteAction() {
super("Add", "Add", IconUtil.getAddIcon());
registerCustomShortcutSet(CommonShortcuts.INSERT, mySuitesTree);
}
@Override
public void actionPerformed(AnActionEvent e) {
final VirtualFile file =
FileChooser.chooseFile(new FileChooserDescriptor(true, false, false, false, false, false) {
@Override
public boolean isFileSelectable(VirtualFile file) {
return getCoverageRunner(file) != null;
}
}, myProject, null);
if (file != null) {
final CoverageRunner coverageRunner = getCoverageRunner(file);
LOG.assertTrue(coverageRunner != null);
final CoverageSuite coverageSuite = myCoverageManager
.addExternalCoverageSuite(file.getName(), file.getTimeStamp(), coverageRunner,
new DefaultCoverageFileProvider(file.getPath()));
final String coverageRunnerTitle = getCoverageRunnerTitle(coverageRunner);
DefaultMutableTreeNode node = TreeUtil.findNodeWithObject(myRootNode, coverageRunnerTitle);
if (node == null) {
node = new DefaultMutableTreeNode(coverageRunnerTitle);
myRootNode.add(node);
}
if (node.getChildCount() > 0) {
final TreeNode childNode = node.getChildAt(0);
if (!(childNode instanceof CheckedTreeNode)) {
if (LOCAL.equals(((DefaultMutableTreeNode)childNode).getUserObject())) {
node = (DefaultMutableTreeNode)childNode;
} else {
final DefaultMutableTreeNode localNode = new DefaultMutableTreeNode(LOCAL);
node.add(localNode);
node = localNode;
}
}
}
final CheckedTreeNode suiteNode = new CheckedTreeNode(coverageSuite);
suiteNode.setChecked(true);
node.add(suiteNode);
TreeUtil.sort(node, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof CheckedTreeNode && o2 instanceof CheckedTreeNode) {
final Object userObject1 = ((CheckedTreeNode)o1).getUserObject();
final Object userObject2 = ((CheckedTreeNode)o2).getUserObject();
if (userObject1 instanceof CoverageSuite && userObject2 instanceof CoverageSuite) {
final String presentableName1 = ((CoverageSuite)userObject1).getPresentableName();
final String presentableName2 = ((CoverageSuite)userObject2).getPresentableName();
return presentableName1.compareToIgnoreCase(presentableName2);
}
}
return 0;
}
});
updateTree();
TreeUtil.selectNode(mySuitesTree, suiteNode);
}
}
}
private class DeleteSuiteAction extends AnAction {
public DeleteSuiteAction() {
super("Delete", "Delete", PlatformIcons.DELETE_ICON);
registerCustomShortcutSet(CommonShortcuts.getDelete(), mySuitesTree);
}
@Override
public void actionPerformed(AnActionEvent e) {
final CheckedTreeNode[] selectedNodes = mySuitesTree.getSelectedNodes(CheckedTreeNode.class, null);
for (CheckedTreeNode selectedNode : selectedNodes) {
final Object userObject = selectedNode.getUserObject();
if (userObject instanceof CoverageSuite) {
final CoverageSuite selectedSuite = (CoverageSuite)userObject;
if (selectedSuite.getCoverageDataFileProvider() instanceof DefaultCoverageFileProvider &&
Comparing.strEqual(((DefaultCoverageFileProvider)selectedSuite.getCoverageDataFileProvider()).getSourceProvider(),
DefaultCoverageFileProvider.class.getName())) {
myCoverageManager.removeCoverageSuite(selectedSuite);
TreeUtil.removeLastPathComponent(mySuitesTree, new TreePath(selectedNode.getPath()));
}
}
}
}
@Override
public void update(AnActionEvent e) {
final CheckedTreeNode[] selectedSuites = mySuitesTree.getSelectedNodes(CheckedTreeNode.class, null);
final Presentation presentation = e.getPresentation();
presentation.setEnabled(false);
for (CheckedTreeNode node : selectedSuites) {
final Object userObject = node.getUserObject();
if (userObject instanceof CoverageSuite) {
final CoverageSuite selectedSuite = (CoverageSuite)userObject;
if (selectedSuite.getCoverageDataFileProvider() instanceof DefaultCoverageFileProvider &&
Comparing.strEqual(((DefaultCoverageFileProvider)selectedSuite.getCoverageDataFileProvider()).getSourceProvider(),
DefaultCoverageFileProvider.class.getName())) {
presentation.setEnabled(true);
}
}
}
}
}
private class SwitchEngineAction extends ComboBoxAction {
@NotNull
@Override
protected DefaultActionGroup createPopupActionGroup(JComponent button) {
final DefaultActionGroup engChooser = new DefaultActionGroup();
for (final CoverageEngine engine : collectEngines()) {
engChooser.add(new AnAction(engine.getPresentableText()) {
@Override
public void actionPerformed(AnActionEvent e) {
myEngine = engine;
initTree();
updateTree();
}
});
}
return engChooser;
}
@Override
public void update(AnActionEvent e) {
super.update(e);
e.getPresentation().setVisible(collectEngines().size() > 1);
}
}
}