diff options
Diffstat (limited to 'platform/lang-impl/src/com/intellij/profile/codeInspection')
23 files changed, 2031 insertions, 697 deletions
diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/AddScopeUtil.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/AddScopeUtil.java new file mode 100644 index 000000000000..d92445254f28 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/AddScopeUtil.java @@ -0,0 +1,117 @@ +/* + * Copyright 2000-2012 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. + */ + +/* + * User: anna + * Date: 14-May-2009 + */ +package com.intellij.profile.codeInspection.ui; + +import com.intellij.codeHighlighting.HighlightDisplayLevel; +import com.intellij.codeInspection.ex.Descriptor; +import com.intellij.codeInspection.ex.InspectionProfileImpl; +import com.intellij.codeInspection.ex.InspectionToolWrapper; +import com.intellij.codeInspection.ex.ScopeToolState; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionConfigTreeNode; +import com.intellij.psi.search.scope.packageSet.CustomScopesProviderEx; +import com.intellij.psi.search.scope.packageSet.NamedScope; +import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; +import com.intellij.ui.treeStructure.Tree; +import com.intellij.ui.treeStructure.treetable.TreeTable; +import com.intellij.util.ArrayUtil; + +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; +import java.util.*; + +public class AddScopeUtil { + public static ScopeToolState performAddScope(final TreeTable treeTable, + final Project project, + final InspectionProfileImpl inspectionProfile, + final Collection<InspectionConfigTreeNode> selectedNodes) { + final List<InspectionConfigTreeNode> nodes = new ArrayList<InspectionConfigTreeNode>(); + final List<Descriptor> descriptors = new ArrayList<Descriptor>(); + for (final InspectionConfigTreeNode node : selectedNodes) { + collect(descriptors, nodes, node); + } + + final List<String> availableScopes = getAvailableScopes(descriptors, project, inspectionProfile); + final int idx = Messages.showChooseDialog(treeTable, "Scope:", "Choose Scope", ArrayUtil.toStringArray(availableScopes), availableScopes.get(0), Messages.getQuestionIcon()); + if (idx == -1) return null; + final NamedScope chosenScope = NamedScopesHolder.getScope(project, availableScopes.get(idx)); + + ScopeToolState scopeToolState = null; + final Tree tree = treeTable.getTree(); + + for (final InspectionConfigTreeNode node : nodes) { + final Descriptor descriptor = node.getDefaultDescriptor(); + final InspectionToolWrapper toolWrapper = descriptor.getToolWrapper().createCopy(); //copy + final HighlightDisplayLevel level = inspectionProfile.getErrorLevel(descriptor.getKey(), chosenScope, project); + final boolean enabled = inspectionProfile.isToolEnabled(descriptor.getKey()); + scopeToolState = inspectionProfile.addScope(toolWrapper, chosenScope, level, enabled, project); + node.dropCache(); + ((DefaultTreeModel)tree.getModel()).reload(node); + tree.expandPath(new TreePath(node.getPath())); + } + tree.revalidate(); + return scopeToolState; + } + + private static void collect(final List<Descriptor> descriptors, + final List<InspectionConfigTreeNode> nodes, + final InspectionConfigTreeNode node) { + final ToolDescriptors currentDescriptors = node.getDescriptors(); + if (currentDescriptors != null) { + nodes.add(node); + descriptors.add(currentDescriptors.getDefaultDescriptor()); + descriptors.addAll(currentDescriptors.getNonDefaultDescriptors()); + } else if (node.getUserObject() instanceof String) { + for(int i = 0; i < node.getChildCount(); i++) { + final InspectionConfigTreeNode childNode = (InspectionConfigTreeNode)node.getChildAt(i); + collect(descriptors, nodes, childNode); + } + } + } + + private static List<String> getAvailableScopes(final List<Descriptor> descriptors, final Project project, final InspectionProfileImpl inspectionProfile) { + final ArrayList<NamedScope> scopes = new ArrayList<NamedScope>(); + for (final NamedScopesHolder holder : NamedScopesHolder.getAllNamedScopeHolders(project)) { + Collections.addAll(scopes, holder.getScopes()); + } + scopes.remove(CustomScopesProviderEx.getAllScope()); + + CustomScopesProviderEx.filterNoSettingsScopes(project, scopes); + + final Set<NamedScope> used = new HashSet<NamedScope>(); + for (final Descriptor descriptor : descriptors) { + final List<ScopeToolState> nonDefaultTools = inspectionProfile.getNonDefaultTools(descriptor.getKey().toString(), project); + if (nonDefaultTools != null) { + for (final ScopeToolState state : nonDefaultTools) { + used.add(state.getScope(project)); + } + } + } + scopes.removeAll(used); + + final List<String> availableScopes = new ArrayList<String>(); + for (final NamedScope scope : scopes) { + availableScopes.add(scope.getName()); + } + return availableScopes; + } +}
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.java index ad2b44494044..794945268d19 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.java @@ -151,7 +151,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable imple final Set<String> levels = new HashSet<String>(); for (Object o : rootElement.getChildren("inspection_tool")) { final Element inspectElement = (Element)o; - levels.add(inspectElement.getAttributeValue("level")); + levels.add(inspectElement.getAttributeValue("l")); for (Object s : inspectElement.getChildren("scope")) { levels.add(((Element)s).getAttributeValue("level")); } diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionsAggregationUtil.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionsAggregationUtil.java new file mode 100644 index 000000000000..3707c034ec04 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionsAggregationUtil.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui; + +import com.intellij.codeInsight.daemon.HighlightDisplayKey; +import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionConfigTreeNode; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Queue; +import gnu.trove.THashSet; + +import javax.swing.tree.TreePath; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +public class InspectionsAggregationUtil { + public static List<HighlightDisplayKey> getInspectionsKeys(final InspectionConfigTreeNode node) { + return ContainerUtil.map(getInspectionsNodes(node), new Function<InspectionConfigTreeNode, HighlightDisplayKey>() { + @Override + public HighlightDisplayKey fun(final InspectionConfigTreeNode node) { + return node.getKey(); + } + }); + } + + public static List<InspectionConfigTreeNode> getInspectionsNodes(final InspectionConfigTreeNode node) { + final Queue<InspectionConfigTreeNode> q = new Queue<InspectionConfigTreeNode>(1); + q.addLast(node); + return getInspectionsNodes(q); + } + + public static List<InspectionConfigTreeNode> getInspectionsNodes(final TreePath[] paths) { + final Queue<InspectionConfigTreeNode> q = new Queue<InspectionConfigTreeNode>(paths.length); + for (final TreePath path : paths) { + if (path != null) { + q.addLast((InspectionConfigTreeNode)path.getLastPathComponent()); + } + } + return getInspectionsNodes(q); + } + + private static List<InspectionConfigTreeNode> getInspectionsNodes(final Queue<InspectionConfigTreeNode> queue) { + final Set<InspectionConfigTreeNode> nodes = new THashSet<InspectionConfigTreeNode>(); + while (!queue.isEmpty()) { + final InspectionConfigTreeNode node = queue.pullFirst(); + if (node.getDescriptors() == null) { + for (int i = 0; i < node.getChildCount(); i++) { + final InspectionConfigTreeNode childNode = (InspectionConfigTreeNode) node.getChildAt(i); + queue.addLast(childNode); + } + } else { + nodes.add(node); + } + } + return new ArrayList<InspectionConfigTreeNode>(nodes); + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooser.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooser.java index 2229550d192f..5bc792545c96 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooser.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooser.java @@ -56,7 +56,8 @@ public class LevelChooser extends ComboboxWithBrowseButton { addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - final SeverityEditorDialog dlg = new SeverityEditorDialog(LevelChooser.this, (HighlightSeverity)getComboBox().getSelectedItem(), severityRegistrar); + final SeverityEditorDialog dlg = + new SeverityEditorDialog(LevelChooser.this, (HighlightSeverity)getComboBox().getSelectedItem(), severityRegistrar); dlg.show(); if (dlg.isOK()) { final Object item = getComboBox().getSelectedItem(); @@ -64,7 +65,8 @@ public class LevelChooser extends ComboboxWithBrowseButton { final HighlightInfoType type = dlg.getSelectedType(); if (type != null) { getComboBox().setSelectedItem(type.getSeverity(null)); - } else { + } + else { getComboBox().setSelectedItem(item); } } diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java index ec2fbce96cc5..1067a60ed358 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java @@ -19,6 +19,7 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; import com.intellij.codeInsight.daemon.impl.SeverityUtil; +import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.codeInspection.ex.SeverityEditorDialog; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.actionSystem.AnAction; @@ -26,6 +27,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.actionSystem.ex.ComboBoxAction; +import com.intellij.profile.codeInspection.SeverityProvider; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -40,24 +42,15 @@ public abstract class LevelChooserAction extends ComboBoxAction { private final SeverityRegistrar mySeverityRegistrar; private HighlightSeverity myChosen = null; - public LevelChooserAction(final SeverityRegistrar severityRegistrar) { - mySeverityRegistrar = severityRegistrar; + public LevelChooserAction(final InspectionProfileImpl profile) { + mySeverityRegistrar = ((SeverityProvider)profile.getProfileManager()).getOwnSeverityRegistrar(); } @NotNull @Override - protected DefaultActionGroup createPopupActionGroup(final JComponent button) { + public DefaultActionGroup createPopupActionGroup(final JComponent anchor) { final DefaultActionGroup group = new DefaultActionGroup(); - - final SortedSet<HighlightSeverity> severities = new TreeSet<HighlightSeverity>(mySeverityRegistrar); - for (final SeverityRegistrar.SeverityBasedTextAttributes type : SeverityUtil.getRegisteredHighlightingInfoTypes(mySeverityRegistrar)) { - severities.add(type.getSeverity()); - } - severities.add(HighlightSeverity.ERROR); - severities.add(HighlightSeverity.WARNING); - severities.add(HighlightSeverity.WEAK_WARNING); - severities.add(HighlightSeverity.GENERIC_SERVER_ERROR_OR_WARNING); - for (final HighlightSeverity severity : severities) { + for (final HighlightSeverity severity : getSeverities(mySeverityRegistrar)) { final HighlightSeverityAction action = new HighlightSeverityAction(severity); if (myChosen == null) { setChosen(action.getSeverity()); @@ -68,7 +61,7 @@ public abstract class LevelChooserAction extends ComboBoxAction { group.add(new AnAction("Edit severities...") { @Override public void actionPerformed(final AnActionEvent e) { - final SeverityEditorDialog dlg = new SeverityEditorDialog(button, myChosen, mySeverityRegistrar); + final SeverityEditorDialog dlg = new SeverityEditorDialog(anchor, myChosen, mySeverityRegistrar); dlg.show(); if (dlg.isOK()) { final HighlightInfoType type = dlg.getSelectedType(); @@ -83,6 +76,18 @@ public abstract class LevelChooserAction extends ComboBoxAction { return group; } + public static SortedSet<HighlightSeverity> getSeverities(final SeverityRegistrar severityRegistrar) { + final SortedSet<HighlightSeverity> severities = new TreeSet<HighlightSeverity>(severityRegistrar); + for (final SeverityRegistrar.SeverityBasedTextAttributes type : SeverityUtil.getRegisteredHighlightingInfoTypes(severityRegistrar)) { + severities.add(type.getSeverity()); + } + severities.add(HighlightSeverity.ERROR); + severities.add(HighlightSeverity.WARNING); + severities.add(HighlightSeverity.WEAK_WARNING); + severities.add(HighlightSeverity.GENERIC_SERVER_ERROR_OR_WARNING); + return severities; + } + protected abstract void onChosen(final HighlightSeverity severity); public void setChosen(final HighlightSeverity severity) { diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/MultiScopeSeverityIcon.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/MultiScopeSeverityIcon.java new file mode 100644 index 000000000000..2bf909666f82 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/MultiScopeSeverityIcon.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class MultiScopeSeverityIcon implements Icon { + private final int mySize; + private final List<Color> myColors; + + public MultiScopeSeverityIcon(final int size, final List<Color> colors) { + mySize = size; + myColors = colors; + } + + @Override + public void paintIcon(final Component c, final Graphics g, final int i, final int j) { + final int iconWidth = getIconWidth(); + final int iconHeightCoordinate = j + getIconHeight(); + + final int partWidth = iconWidth / myColors.size(); + + for (int idx = 0; idx < myColors.size(); idx++) { + final Color color = myColors.get(idx); + g.setColor(color); + final int x = i + partWidth * idx; + g.fillRect(x, j, x + partWidth, iconHeightCoordinate); + } + } + + @Override + public int getIconWidth() { + return mySize; + } + + @Override + public int getIconHeight() { + return mySize; + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ScopesChooser.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ScopesChooser.java new file mode 100644 index 000000000000..4932e7ff5ca9 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ScopesChooser.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui; + +import com.intellij.codeInspection.ex.Descriptor; +import com.intellij.codeInspection.ex.InspectionProfileImpl; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.actionSystem.ex.ComboBoxAction; +import com.intellij.openapi.project.Project; +import com.intellij.psi.search.scope.packageSet.CustomScopesProviderEx; +import com.intellij.psi.search.scope.packageSet.NamedScope; +import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; + +/** + * @author Dmitry Batkovich + */ +public abstract class ScopesChooser extends ComboBoxAction { + + private final List<Descriptor> myDefaultDescriptors; + private final InspectionProfileImpl myInspectionProfile; + private final Project myProject; + + public ScopesChooser(final List<Descriptor> defaultDescriptors, final InspectionProfileImpl inspectionProfile, final Project project) { + myDefaultDescriptors = defaultDescriptors; + myInspectionProfile = inspectionProfile; + myProject = project; + setPopupTitle("Select a scope to change its settings"); + getTemplatePresentation().setText("In All Scopes"); + } + + @NotNull + @Override + protected DefaultActionGroup createPopupActionGroup(final JComponent button) { + final DefaultActionGroup group = new DefaultActionGroup(); + + final List<NamedScope> predefinedScopes = new ArrayList<NamedScope>(); + final List<NamedScope> customScopes = new ArrayList<NamedScope>(); + for (final NamedScopesHolder holder : NamedScopesHolder.getAllNamedScopeHolders(myProject)) { + Collections.addAll(customScopes, holder.getEditableScopes()); + predefinedScopes.addAll(holder.getPredefinedScopes()); + } + predefinedScopes.remove(CustomScopesProviderEx.getAllScope()); + fillActionGroup(group, predefinedScopes, myDefaultDescriptors, myInspectionProfile); + group.addSeparator(); + fillActionGroup(group, customScopes, myDefaultDescriptors, myInspectionProfile); + + //TODO edit scopes order + //group.addSeparator(); + //group.add(new AnAction("Edit Scopes Order...") { + // @Override + // public void actionPerformed(final AnActionEvent e) { + // + // } + //}); + + return group; + } + + protected abstract void onScopeAdded(); + + private void fillActionGroup(final DefaultActionGroup group, + final List<NamedScope> scopes, + final List<Descriptor> defaultDescriptors, + final InspectionProfileImpl inspectionProfile) { + for (final NamedScope scope : scopes) { + group.add(new AnAction(scope.getName()) { + @Override + public void actionPerformed(final AnActionEvent e) { + for (final Descriptor defaultDescriptor : defaultDescriptors) { + inspectionProfile.addScope(defaultDescriptor.getToolWrapper().createCopy(), scope, defaultDescriptor.getLevel(), true, getEventProject(e)); + } + onScopeAdded(); + } + }); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java index 62993f5cf9c8..ce5f308c1305 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java @@ -52,19 +52,25 @@ import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProfileManagerImpl; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.profile.codeInspection.SeverityProvider; -import com.intellij.profile.codeInspection.ui.actions.AddScopeAction; -import com.intellij.profile.codeInspection.ui.actions.DeleteScopeAction; -import com.intellij.profile.codeInspection.ui.actions.MoveScopeAction; +import com.intellij.profile.codeInspection.ui.filter.InspectionFilterAction; +import com.intellij.profile.codeInspection.ui.filter.InspectionsFilter; +import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionConfigTreeNode; +import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionsConfigTreeComparator; +import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionsConfigTreeRenderer; +import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionsConfigTreeTable; +import com.intellij.profile.codeInspection.ui.table.ScopesAndSeveritiesTable; import com.intellij.psi.search.scope.packageSet.NamedScope; import com.intellij.ui.*; +import com.intellij.ui.components.JBLabel; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.Alarm; -import com.intellij.util.IconUtil; +import com.intellij.util.Function; import com.intellij.util.config.StorageAccessors; -import com.intellij.util.containers.Convertor; +import com.intellij.util.containers.*; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import com.intellij.xml.util.XmlStringUtil; +import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -76,7 +82,6 @@ import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.DefaultTreeSelectionModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import java.awt.*; @@ -85,6 +90,7 @@ import java.awt.event.KeyEvent; import java.io.IOException; import java.io.StringReader; import java.util.*; +import java.util.HashSet; import java.util.List; /** @@ -95,17 +101,23 @@ public class SingleInspectionProfilePanel extends JPanel { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.InspectionToolsPanel"); @NonNls private static final String INSPECTION_FILTER_HISTORY = "INSPECTION_FILTER_HISTORY"; private static final String UNDER_CONSTRUCTION = InspectionsBundle.message("inspection.tool.description.under.construction.text"); - private final Map<Descriptor, List<Descriptor>> myDescriptors = new HashMap<Descriptor, List<Descriptor>>(); + private final List<ToolDescriptors> myInitialToolDescriptors = new ArrayList<ToolDescriptors>(); private InspectionProfileImpl mySelectedProfile; private JEditorPane myBrowser; private JPanel myOptionsPanel; private JPanel myInspectionProfilePanel = null; private FilterComponent myProfileFilter; + private final InspectionsFilter myInspectionsFilter = new InspectionsFilter() { + @Override + protected void filterChanged() { + filterTree(myProfileFilter.getFilter()); + } + }; private final InspectionConfigTreeNode myRoot = - new InspectionConfigTreeNode(InspectionsBundle.message("inspection.root.node.title"), null, false, false); + new InspectionConfigTreeNode(InspectionsBundle.message("inspection.root.node.title")); private final Alarm myAlarm = new Alarm(); private boolean myModified = false; - private Tree myTree; + private InspectionsConfigTreeTable myTreeTable; private TreeExpander myTreeExpander; @NotNull private String myInitialProfile; @@ -171,21 +183,21 @@ public class SingleInspectionProfilePanel extends JPanel { } public void updateSelection() { - if (myTree != null) { - final TreePath selectionPath = myTree.getSelectionPath(); + if (myTreeTable != null) { + final TreePath selectionPath = myTreeTable.getTree().getSelectionPath(); if (selectionPath != null) { - TreeUtil.selectNode(myTree, (TreeNode)selectionPath.getLastPathComponent()); - TreeUtil.showRowCentered(myTree, myTree.getRowForPath(selectionPath), false); + TreeUtil.selectNode(myTreeTable.getTree(), (TreeNode)selectionPath.getLastPathComponent()); + TreeUtil.showRowCentered(myTreeTable.getTree(), myTreeTable.getTree().getRowForPath(selectionPath), false); } } } private void wereToolSettingsModified() { - for (Map.Entry<Descriptor, List<Descriptor>> entry : myDescriptors.entrySet()) { - Descriptor desc = entry.getKey(); + for (final ToolDescriptors toolDescriptor : myInitialToolDescriptors) { + Descriptor desc = toolDescriptor.getDefaultDescriptor(); if (wereToolSettingsModified(desc)) return; - List<Descriptor> descriptors = entry.getValue(); + List<Descriptor> descriptors = toolDescriptor.getNonDefaultDescriptors(); for (Descriptor descriptor : descriptors) { if (wereToolSettingsModified(descriptor)) return; } @@ -206,7 +218,7 @@ public class SingleInspectionProfilePanel extends JPanel { myAlarm.addRequest(new Runnable() { @Override public void run() { - myTree.repaint(); + myTreeTable.repaint(); } }, 300); myModified = true; @@ -216,10 +228,10 @@ public class SingleInspectionProfilePanel extends JPanel { } private void updateProperSettingsForSelection() { - final TreePath selectionPath = myTree.getSelectionPath(); + final TreePath selectionPath = myTreeTable.getTree().getSelectionPath(); if (selectionPath != null) { InspectionConfigTreeNode node = (InspectionConfigTreeNode)selectionPath.getLastPathComponent(); - final Descriptor descriptor = node.getDescriptor(); + final Descriptor descriptor = node.getDefaultDescriptor(); if (descriptor != null) { final boolean properSetting = mySelectedProfile.isProperSetting(descriptor.getKey().toString()); if (node.isProperSetting() != properSetting) { @@ -227,7 +239,7 @@ public class SingleInspectionProfilePanel extends JPanel { myAlarm.addRequest(new Runnable() { @Override public void run() { - myTree.repaint(); + myTreeTable.repaint(); } }, 300); node.dropCache(); @@ -237,21 +249,14 @@ public class SingleInspectionProfilePanel extends JPanel { } } - private void initDescriptors() { + private void initToolStates() { final InspectionProfileImpl profile = mySelectedProfile; if (profile == null) return; - myDescriptors.clear(); - List<ScopeToolState> tools = profile.getDefaultStates(myProjectProfileManager.getProject()); - for (ScopeToolState state : tools) { - final ArrayList<Descriptor> descriptors = new ArrayList<Descriptor>(); + myInitialToolDescriptors.clear(); + final Project project = myProjectProfileManager.getProject(); + for (final ScopeToolState state : profile.getDefaultStates(myProjectProfileManager.getProject())) { if (!accept(state.getTool())) continue; - Project project = myProjectProfileManager.getProject(); - myDescriptors.put(new Descriptor(state, profile, project), descriptors); - InspectionToolWrapper toolWrapper = state.getTool(); - final List<ScopeToolState> nonDefaultTools = profile.getNonDefaultTools(toolWrapper.getShortName(), project); - for (ScopeToolState nonDefaultToolState : nonDefaultTools) { - descriptors.add(new Descriptor(nonDefaultToolState, profile, project)); - } + myInitialToolDescriptors.add(ToolDescriptors.fromScopeToolState(state, profile, project)); } } @@ -267,7 +272,7 @@ public class SingleInspectionProfilePanel extends JPanel { } fillTreeData(myProfileFilter.getFilter(), true); repaintTableData(); - updateOptionsAndDescriptionPanel(myTree.getSelectionPath()); + updateOptionsAndDescriptionPanel(myTreeTable.getTree().getSelectionPaths()); } @Nullable @@ -311,22 +316,26 @@ public class SingleInspectionProfilePanel extends JPanel { myProfileFilter.setFilter(filter); } - public void filterTree(String filter) { - if (myTree != null) { - getExpandedNodes(mySelectedProfile).saveVisibleState(myTree); + private void filterTree(@Nullable String filter) { + if (myTreeTable != null) { + getExpandedNodes(mySelectedProfile).saveVisibleState(myTreeTable.getTree()); fillTreeData(filter, true); reloadModel(); restoreTreeState(); - if (myTree.getSelectionPath() == null) { - TreeUtil.selectFirstNode(myTree); + if (myTreeTable.getTree().getSelectionPath() == null) { + TreeUtil.selectFirstNode(myTreeTable.getTree()); } } } + private void filterTree() { + filterTree(myProfileFilter != null ? myProfileFilter.getFilter() : null); + } + private void reloadModel() { try { myIsInRestore = true; - ((DefaultTreeModel)myTree.getModel()).reload(); + ((DefaultTreeModel)myTreeTable.getTree().getModel()).reload(); } finally { myIsInRestore = false; @@ -338,7 +347,7 @@ public class SingleInspectionProfilePanel extends JPanel { try { myIsInRestore = true; - getExpandedNodes(mySelectedProfile).restoreVisibleState(myTree); + getExpandedNodes(mySelectedProfile).restoreVisibleState(myTreeTable.getTree()); } finally { myIsInRestore = false; @@ -349,13 +358,17 @@ public class SingleInspectionProfilePanel extends JPanel { final CommonActionsManager actionManager = CommonActionsManager.getInstance(); DefaultActionGroup actions = new DefaultActionGroup(); - actions.add(actionManager.createExpandAllAction(myTreeExpander, myTree)); - actions.add(actionManager.createCollapseAllAction(myTreeExpander, myTree)); + + actions.add(new InspectionFilterAction(mySelectedProfile, myInspectionsFilter)); + actions.addSeparator(); + + actions.add(actionManager.createExpandAllAction(myTreeExpander, myTreeTable)); + actions.add(actionManager.createCollapseAllAction(myTreeExpander, myTreeTable)); actions.add(new AnAction(CommonBundle.message("button.reset.to.default"), CommonBundle.message("button.reset.to.default"), AllIcons.General.Reset) { { - registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_MASK)), myTree); + registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_MASK)), myTreeTable); } @Override public void update(AnActionEvent e) { @@ -395,41 +408,14 @@ public class SingleInspectionProfilePanel extends JPanel { } }); - actions.addSeparator(); - actions.add(new MyAddScopeAction()); - actions.add(new MyDeleteScopeAction()); - actions.add(new MoveScopeAction(myTree, "Move Scope Up", IconUtil.getMoveUpIcon(), -1) { - @Override - protected boolean isEnabledFor(int idx, InspectionConfigTreeNode parent) { - return idx > 0; - } - - @Override - protected InspectionProfileImpl getSelectedProfile() { - return mySelectedProfile; - } - }); - actions.add(new MoveScopeAction(myTree, "Move Scope Down", IconUtil.getMoveDownIcon(), 1) { - @Override - protected boolean isEnabledFor(int idx, InspectionConfigTreeNode parent) { - return idx < parent.getChildCount() - 2; - } - - @Override - protected InspectionProfileImpl getSelectedProfile() { - return mySelectedProfile; - } - }); - actions.addSeparator(); - final ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, actions, true); actionToolbar.setTargetComponent(this); return actionToolbar; } private void repaintTableData() { - if (myTree != null) { - getExpandedNodes(mySelectedProfile).saveVisibleState(myTree); + if (myTreeTable != null) { + getExpandedNodes(mySelectedProfile).saveVisibleState(myTreeTable.getTree()); reloadModel(); restoreTreeState(); } @@ -438,8 +424,8 @@ public class SingleInspectionProfilePanel extends JPanel { public void selectInspectionTool(String name) { final InspectionConfigTreeNode node = findNodeByKey(name, myRoot); if (node != null) { - TreeUtil.showRowCentered(myTree, myTree.getRowForPath(new TreePath(node.getPath())) - 1, true);//myTree.isRootVisible ? 0 : 1; - TreeUtil.selectNode(myTree, node); + TreeUtil.showRowCentered(myTreeTable.getTree(), myTreeTable.getTree().getRowForPath(new TreePath(node.getPath())) - 1, true);//myTree.isRootVisible ? 0 : 1; + TreeUtil.selectNode(myTreeTable.getTree(), node); } } @@ -447,7 +433,7 @@ public class SingleInspectionProfilePanel extends JPanel { private static InspectionConfigTreeNode findNodeByKey(String name, InspectionConfigTreeNode root) { for (int i = 0; i < root.getChildCount(); i++) { final InspectionConfigTreeNode child = (InspectionConfigTreeNode)root.getChildAt(i); - final Descriptor descriptor = child.getDescriptor(); + final Descriptor descriptor = child.getDefaultDescriptor(); if (descriptor != null) { if (descriptor.getKey().toString().equals(name)) { return child; @@ -462,42 +448,37 @@ public class SingleInspectionProfilePanel extends JPanel { } private JScrollPane initTreeScrollPane() { - fillTreeData(null, true); - final InspectionsConfigTreeRenderer renderer = new InspectionsConfigTreeRenderer(myProjectProfileManager.getProject()){ + final InspectionsConfigTreeRenderer renderer = new InspectionsConfigTreeRenderer(){ @Override protected String getFilter() { return myProfileFilter != null ? myProfileFilter.getFilter() : null; } }; - myTree = new CheckboxTree(renderer, myRoot) { + myTreeTable = new InspectionsConfigTreeTable(new InspectionsConfigTreeTable.InspectionsConfigTreeTableSettings(myRoot, myProjectProfileManager.getProject()) { @Override - public Dimension getPreferredScrollableViewportSize() { - Dimension size = super.getPreferredScrollableViewportSize(); - size = new Dimension(size.width + 10, size.height); - return size; + protected void onChanged(final InspectionConfigTreeNode node) { + updateOptionsAndDescriptionPanel(); + updateUpHierarchy(node, (InspectionConfigTreeNode)node.getParent()); } @Override - protected void onNodeStateChanged(final CheckedTreeNode node) { - toggleToolNode((InspectionConfigTreeNode)node); + public InspectionProfileImpl getInspectionProfile() { + return mySelectedProfile; } - }; - - - myTree.setCellRenderer(renderer); - myTree.setRootVisible(false); - myTree.setShowsRootHandles(true); - UIUtil.setLineStyleAngled(myTree); - TreeUtil.installActions(myTree); + }); + myTreeTable.setTreeCellRenderer(renderer); + myTreeTable.setRootVisible(false); + UIUtil.setLineStyleAngled(myTreeTable.getTree()); + TreeUtil.installActions(myTreeTable.getTree()); - myTree.addTreeSelectionListener(new TreeSelectionListener() { + myTreeTable.getTree().addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(TreeSelectionEvent e) { - if (myTree.getSelectionPaths() != null && myTree.getSelectionPaths().length == 1) { - updateOptionsAndDescriptionPanel(myTree.getSelectionPaths()[0]); + if (myTreeTable.getTree().getSelectionPaths() != null) { + updateOptionsAndDescriptionPanel(myTreeTable.getTree().getSelectionPaths()); } else { initOptionsAndDescriptionPanel(); @@ -508,9 +489,9 @@ public class SingleInspectionProfilePanel extends JPanel { if (selected != null) { InspectionProfileImpl baseProfile = (InspectionProfileImpl)selected.getParentProfile(); if (baseProfile != null) { - getExpandedNodes(baseProfile).setSelectionPaths(myTree.getSelectionPaths()); + getExpandedNodes(baseProfile).setSelectionPaths(myTreeTable.getTree().getSelectionPaths()); } - getExpandedNodes(selected).setSelectionPaths(myTree.getSelectionPaths()); + getExpandedNodes(selected).setSelectionPaths(myTreeTable.getTree().getSelectionPaths()); } } @@ -518,36 +499,35 @@ public class SingleInspectionProfilePanel extends JPanel { }); - myTree.addMouseListener(new PopupHandler() { + myTreeTable.addMouseListener(new PopupHandler() { @Override public void invokePopup(Component comp, int x, int y) { - final int[] selectionRows = myTree.getSelectionRows(); - if (selectionRows != null && myTree.getPathForLocation(x, y) != null && Arrays.binarySearch(selectionRows, myTree.getRowForLocation(x, y)) > -1) - { + final int[] selectionRows = myTreeTable.getTree().getSelectionRows(); + if (selectionRows != null && + myTreeTable.getTree().getPathForLocation(x, y) != null && + Arrays.binarySearch(selectionRows, myTreeTable.getTree().getRowForLocation(x, y)) > -1) { compoundPopup().show(comp, x, y); } } }); - new TreeSpeedSearch(myTree, new Convertor<TreePath, String>() { + new TreeSpeedSearch(myTreeTable.getTree(), new Convertor<TreePath, String>() { @Override public String convert(TreePath o) { final InspectionConfigTreeNode node = (InspectionConfigTreeNode)o.getLastPathComponent(); - final Descriptor descriptor = node.getDescriptor(); + final Descriptor descriptor = node.getDefaultDescriptor(); return descriptor != null ? InspectionsConfigTreeComparator.getDisplayTextToSort(descriptor.getText()) : InspectionsConfigTreeComparator .getDisplayTextToSort(node.getGroupName()); } }); - myTree.setSelectionModel(new DefaultTreeSelectionModel()); - - final JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myTree); + final JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myTreeTable); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); - TreeUtil.collapseAll(myTree, 1); + TreeUtil.collapseAll(myTreeTable.getTree(), 1); - myTree.addTreeExpansionListener(new TreeExpansionListener() { + myTreeTable.getTree().addTreeExpansionListener(new TreeExpansionListener() { @Override @@ -556,9 +536,9 @@ public class SingleInspectionProfilePanel extends JPanel { final InspectionConfigTreeNode node = (InspectionConfigTreeNode)event.getPath().getLastPathComponent(); final InspectionProfileImpl parentProfile = (InspectionProfileImpl)selected.getParentProfile(); if (parentProfile != null) { - getExpandedNodes(parentProfile).saveVisibleState(myTree); + getExpandedNodes(parentProfile).saveVisibleState(myTreeTable.getTree()); } - getExpandedNodes(selected).saveVisibleState(myTree); + getExpandedNodes(selected).saveVisibleState(myTreeTable.getTree()); } @Override @@ -575,7 +555,17 @@ public class SingleInspectionProfilePanel extends JPanel { } }); - myTreeExpander = new DefaultTreeExpander(myTree); + myTreeExpander = new DefaultTreeExpander(myTreeTable.getTree()) { + @Override + public boolean canExpand() { + return myTreeTable.isShowing(); + } + + @Override + public boolean canCollapse() { + return myTreeTable.isShowing(); + } + }; myProfileFilter = new MyFilterComponent(); return scrollPane; @@ -603,54 +593,14 @@ public class SingleInspectionProfilePanel extends JPanel { }); } group.add(Separator.getInstance()); - group.add(new MyAddScopeAction()); - group.add(new MyDeleteScopeAction()); ActionPopupMenu menu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.UNKNOWN, group); return menu.getComponent(); } - static String renderSeverity(HighlightSeverity severity) { + public static String renderSeverity(HighlightSeverity severity) { return StringUtil.capitalizeWords(severity.getName().toLowerCase(), true); } - private void toggleToolNode(final InspectionConfigTreeNode toolNode) { - final Descriptor descriptor = toolNode.getDescriptor(); - Project project = myProjectProfileManager.getProject(); - if (descriptor!= null) { - final HighlightDisplayKey key = descriptor.getKey(); - final String toolShortName = key.toString(); - if (toolNode.isChecked()) { - if (toolNode.getScope(project) != null){ - if (toolNode.isByDefault()) { - mySelectedProfile.enableToolByDefault(toolShortName, project); - } - else { - mySelectedProfile.enableTool(toolShortName, toolNode.getScope(project), project); - } - } else { - mySelectedProfile.enableTool(toolShortName, project); - } - } - else { - if (toolNode.getScope(project) != null) { - if (toolNode.isByDefault()) { - mySelectedProfile.disableToolByDefault(toolShortName, project); - } else { - mySelectedProfile.disableTool(toolShortName, toolNode.getScope(project), project); - } - } else if (toolNode.getChildCount() == 0){ //default node and no scopes configured - mySelectedProfile.disableTool(toolShortName, project); - } - } - toolNode.dropCache(); - updateUpHierarchy(toolNode, (InspectionConfigTreeNode)toolNode.getParent()); - } - final TreePath path = new TreePath(toolNode.getPath()); - if (Comparing.equal(myTree.getSelectionPath(), path)) { - updateOptionsAndDescriptionPanel(path); - } - } - private static void updateUpHierarchy(final InspectionConfigTreeNode node, final InspectionConfigTreeNode parent) { if (parent != null) { parent.dropCache(); @@ -701,10 +651,9 @@ public class SingleInspectionProfilePanel extends JPanel { return forceInclude; } - private void fillTreeData(String filter, boolean forceInclude) { + private void fillTreeData(@Nullable String filter, boolean forceInclude) { if (mySelectedProfile == null) return; myRoot.removeAllChildren(); - myRoot.setChecked(false); myRoot.dropCache(); List<Set<String>> keySetList = new ArrayList<Set<String>>(); final Set<String> quoted = new HashSet<String>(); @@ -712,23 +661,17 @@ public class SingleInspectionProfilePanel extends JPanel { keySetList.addAll(SearchUtil.findKeys(filter, quoted)); } Project project = myProjectProfileManager.getProject(); - for (Descriptor descriptor : myDescriptors.keySet()) { + final boolean emptyFilter = myInspectionsFilter.isEmptyFilter(); + for (ToolDescriptors toolDescriptors : myInitialToolDescriptors) { + final Descriptor descriptor = toolDescriptors.getDefaultDescriptor(); if (filter != null && !filter.isEmpty() && !isDescriptorAccepted(descriptor, filter, forceInclude, keySetList, quoted)) { continue; } - final List<ScopeToolState> nonDefaultTools = mySelectedProfile.getNonDefaultTools(descriptor.getKey().toString(), project); - final HighlightDisplayKey key = descriptor.getKey(); - final boolean enabled = mySelectedProfile.isToolEnabled(key); - boolean hasNonDefaultScope = !nonDefaultTools.isEmpty(); - final InspectionConfigTreeNode node = new InspectionConfigTreeNode(descriptor, null, !hasNonDefaultScope, enabled, !hasNonDefaultScope); - getGroupNode(myRoot, descriptor.getGroup()).add(node); - if (hasNonDefaultScope) { - for (Descriptor desc : myDescriptors.get(descriptor)) { - node.add(new InspectionConfigTreeNode(desc, desc.getState(), false, false)); - } - node.add(new InspectionConfigTreeNode(descriptor, descriptor.getState(), true, false)); + if (!emptyFilter && !myInspectionsFilter.matches(mySelectedProfile.getTools(toolDescriptors.getDefaultDescriptor().getKey().toString(), project))) { + continue; } - myRoot.setEnabled(myRoot.isEnabled() || enabled); + final InspectionConfigTreeNode node = new InspectionConfigTreeNode(toolDescriptors); + getGroupNode(myRoot, toolDescriptors.getDefaultDescriptor().getGroup()).add(node); myRoot.dropCache(); } if (filter != null && forceInclude && myRoot.getChildCount() == 0) { @@ -740,19 +683,24 @@ public class SingleInspectionProfilePanel extends JPanel { TreeUtil.sort(myRoot, new InspectionsConfigTreeComparator()); } - private void updateOptionsAndDescriptionPanel(TreePath path) { + private void updateOptionsAndDescriptionPanel(final TreePath... paths) { + if (paths == null || paths.length == 0) { + return; + } + final TreePath path = paths[0]; if (path == null) return; - final InspectionConfigTreeNode node = (InspectionConfigTreeNode)path.getLastPathComponent(); - final Descriptor descriptor = node.getDescriptor(); - if (descriptor != null) { - final String description = descriptor.loadDescription(); - - if (description != null) { + final List<InspectionConfigTreeNode> nodes = InspectionsAggregationUtil.getInspectionsNodes(paths); + if (!nodes.isEmpty()) { + final InspectionConfigTreeNode singleNode = nodes.size() == 1 ? ContainerUtil.getFirstItem(nodes) : null; + if (singleNode != null && singleNode.getDefaultDescriptor().loadDescription() != null) { // need this in order to correctly load plugin-supplied descriptions + final Descriptor defaultDescriptor = singleNode.getDefaultDescriptor(); + final String description = defaultDescriptor.loadDescription(); try { final HintHint hintHint = new HintHint(myBrowser, new Point(0, 0)); hintHint.setFont(myBrowser.getFont()); - myBrowser.read(new StringReader(SearchUtil.markup(HintUtil.prepareHintText(description, hintHint), myProfileFilter.getFilter())), null); + myBrowser + .read(new StringReader(SearchUtil.markup(HintUtil.prepareHintText(description, hintHint), myProfileFilter.getFilter())), null); } catch (IOException e2) { try { @@ -764,7 +712,10 @@ public class SingleInspectionProfilePanel extends JPanel { } } catch (Throwable t) { - LOG.error("Failed to load description for: " + descriptor.getToolWrapper().getTool().getClass() + "; description: " + description, t); + LOG.error("Failed to load description for: " + + defaultDescriptor.getToolWrapper().getTool().getClass() + + "; description: " + + description, t); } } @@ -778,41 +729,123 @@ public class SingleInspectionProfilePanel extends JPanel { } myOptionsPanel.removeAll(); + final Project project = myProjectProfileManager.getProject(); + final JPanel severityPanel = new JPanel(new GridBagLayout()); + final double severityPanelWeightY; + final JPanel configPanelAnchor = new JPanel(new GridLayout()); + configPanelAnchor.setBorder(IdeBorderFactory.createTitledBorder("Options", false, new Insets(0, 0, 0, 0))); + + final Set<String> scopesNames = new THashSet<String>(); + for (final InspectionConfigTreeNode node : nodes) { + final List<ScopeToolState> nonDefaultTools = mySelectedProfile.getNonDefaultTools(node.getDefaultDescriptor().getKey().toString(), project); + for (final ScopeToolState tool : nonDefaultTools) { + scopesNames.add(tool.getScopeName()); + } + } + + if (scopesNames.isEmpty()) { - final NamedScope scope = node.getScope(myProjectProfileManager.getProject()); - if (scope != null || node.isInspectionNode()) { - final HighlightDisplayKey key = descriptor.getKey(); - final LevelChooserAction chooser = - new LevelChooserAction(((SeverityProvider)mySelectedProfile.getProfileManager()).getOwnSeverityRegistrar()) { + final LevelChooserAction severityLevelChooser = + new LevelChooserAction(mySelectedProfile) { @Override protected void onChosen(final HighlightSeverity severity) { final HighlightDisplayLevel level = HighlightDisplayLevel.find(severity); - final Project project = myProjectProfileManager.getProject(); - final boolean toUpdate = mySelectedProfile.getErrorLevel(key, scope, project) != level; - mySelectedProfile.setErrorLevel(key, level, - node.isInspectionNode() || node.isByDefault() ? -1 : node.getParent().getIndex(node), - project); - if (toUpdate) node.dropCache(); + for (final InspectionConfigTreeNode node : nodes) { + final HighlightDisplayKey key = node.getDefaultDescriptor().getKey(); + final NamedScope scope = node.getDefaultDescriptor().getScope(); + final boolean toUpdate = mySelectedProfile.getErrorLevel(key, scope, project) != level; + mySelectedProfile.setErrorLevel(key, level, -1, project); + if (toUpdate) node.dropCache(); + } + } }; - chooser.setChosen(mySelectedProfile.getErrorLevel(key, scope, myProjectProfileManager.getProject()).getSeverity()); + final HighlightSeverity severity = + ScopesAndSeveritiesTable.getSeverity(ContainerUtil.map(nodes, new Function<InspectionConfigTreeNode, ScopeToolState>() { + @Override + public ScopeToolState fun(InspectionConfigTreeNode node) { + return node.getDefaultDescriptor().getState(); + } + })); + severityLevelChooser.setChosen(severity); - final JPanel withSeverity = new JPanel(new GridBagLayout()); - withSeverity.add(new JLabel(InspectionsBundle.message("inspection.severity")), - new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, - GridBagConstraints.NONE, new Insets(0, 0, 10, 10), 0, 0)); - withSeverity.add(chooser.createCustomComponent(chooser.getTemplatePresentation()), new GridBagConstraints(1, 0, 1, 1, 1.0, 0, GridBagConstraints.WEST, - GridBagConstraints.NONE, new Insets(0, 0, 10, 0), 0, 0)); + final ScopesChooser scopesChooser = new ScopesChooser(ContainerUtil.map(nodes, new Function<InspectionConfigTreeNode, Descriptor>() { + @Override + public Descriptor fun(final InspectionConfigTreeNode node) { + return node.getDefaultDescriptor(); + } + }), mySelectedProfile, project) { + @Override + protected void onScopeAdded() { + updateOptionsAndDescriptionPanel(); + } + }; + + severityPanel.add(new JLabel(InspectionsBundle.message("inspection.severity")), + new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.VERTICAL, + new Insets(10, 0, 10, 10), 0, 0)); + severityPanel.add(severityLevelChooser.createCustomComponent(severityLevelChooser.getTemplatePresentation()), + new GridBagConstraints(1, 0, 1, 1, 1.0, 0, GridBagConstraints.WEST, GridBagConstraints.VERTICAL, + new Insets(10, 0, 10, 0), 0, 0)); + severityPanel.add(scopesChooser.createCustomComponent(scopesChooser.getTemplatePresentation()), + new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.VERTICAL, + new Insets(10, 0, 10, 0), 0, 0)); + severityPanelWeightY = 0.0; + if (singleNode != null) { + setConfigPanel(configPanelAnchor, mySelectedProfile.getToolDefaultState(singleNode.getDefaultDescriptor().getKey().toString(), + project)); + } + } + else { + if (singleNode != null) { + for (final Descriptor descriptor : singleNode.getDescriptors().getNonDefaultDescriptors()) { + descriptor.loadConfig(); + } + } + final JTable scopesAndScopesAndSeveritiesTable = + new ScopesAndSeveritiesTable(new ScopesAndSeveritiesTable.TableSettings(nodes, mySelectedProfile, myTreeTable, project) { + @Override + protected void onScopeChosen(@NotNull final ScopeToolState state) { + setConfigPanel(configPanelAnchor, state); + configPanelAnchor.revalidate(); + configPanelAnchor.repaint(); + } - final JComponent comp = descriptor.getState().getAdditionalConfigPanel(); - withSeverity.add(comp, - new GridBagConstraints(0, 1, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, - GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + @Override + protected void onChange() { + myTreeTable.getTree().updateUI(); + } + + @Override + protected void onScopeAdded() { + } - myOptionsPanel.add(withSeverity, BorderLayout.CENTER); + @Override + protected void onScopeRemoved(final int scopesCount) { + if (scopesCount == 1) { + updateOptionsAndDescriptionPanel(); + } + } + }); + + + final ToolbarDecorator wrappedTable = ToolbarDecorator.createDecorator(scopesAndScopesAndSeveritiesTable); + final JPanel panel = wrappedTable.createPanel(); + severityPanel.add(new JBLabel("Scopes & Severities"), + new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, + new Insets(5, 0, 2, 10), 0, 0)); + severityPanel.add(new JBLabel("Add scope to change its settings", UIUtil.ComponentStyle.SMALL), + new GridBagConstraints(1, 0, 1, 1, 1.0, 0, GridBagConstraints.NORTHEAST, GridBagConstraints.NONE, + new Insets(5, 0, 2, 0), 0, 0)); + severityPanel.add(panel, new GridBagConstraints(0, 1, 2, 1, 0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, + new Insets(0, 0, 0, 0), 0, 0)); + severityPanelWeightY = 0.3; } + myOptionsPanel.add(severityPanel, new GridBagConstraints(0, 0, 1, 1, 1.0, severityPanelWeightY, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + myOptionsPanel.add(configPanelAnchor, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, + new Insets(0, 0, 0, 0), 0, 0)); myOptionsPanel.revalidate(); - GuiUtils.enableChildren(myOptionsPanel, node.isChecked()); + GuiUtils.enableChildren(myOptionsPanel, isThoughOneNodeEnabled(nodes)); } else { initOptionsAndDescriptionPanel(); @@ -820,6 +853,26 @@ public class SingleInspectionProfilePanel extends JPanel { myOptionsPanel.repaint(); } + private boolean isThoughOneNodeEnabled(final List<InspectionConfigTreeNode> nodes) { + final Project project = myProjectProfileManager.getProject(); + for (final InspectionConfigTreeNode node : nodes) { + final String toolId = node.getDefaultDescriptor().getKey().toString(); + if (mySelectedProfile.getTools(toolId, project).isEnabled()) { + return true; + } + } + return false; + } + + private void updateOptionsAndDescriptionPanel() { + final TreePath[] paths = myTreeTable.getTree().getSelectionPaths(); + if (paths != null) { + updateOptionsAndDescriptionPanel(paths); + } else { + initOptionsAndDescriptionPanel(); + } + } + private void initOptionsAndDescriptionPanel() { myOptionsPanel.removeAll(); try { @@ -832,6 +885,11 @@ public class SingleInspectionProfilePanel extends JPanel { myOptionsPanel.repaint(); } + private static void setConfigPanel(final JPanel configPanelAnchor, final ScopeToolState state) { + configPanelAnchor.removeAll(); + configPanelAnchor.add(state.getAdditionalConfigPanel()); + } + private static InspectionConfigTreeNode getGroupNode(InspectionConfigTreeNode root, String[] groupPath) { InspectionConfigTreeNode currentRoot = root; for (final String group : groupPath) { @@ -848,7 +906,7 @@ public class SingleInspectionProfilePanel extends JPanel { return child; } } - InspectionConfigTreeNode child = new InspectionConfigTreeNode(group, null, false, false); + InspectionConfigTreeNode child = new InspectionConfigTreeNode(group); root.add(child); return child; } @@ -868,8 +926,8 @@ public class SingleInspectionProfilePanel extends JPanel { if (mySelectedProfile != null) { myInitialProfile = mySelectedProfile.getName(); } - initDescriptors(); - filterTree(myProfileFilter != null ? myProfileFilter.getFilter() : null); + initToolStates(); + filterTree(); } @Override @@ -900,7 +958,7 @@ public class SingleInspectionProfilePanel extends JPanel { myBrowser.setBorder(IdeBorderFactory.createEmptyBorder(5, 5, 5, 5)); myBrowser.addHyperlinkListener(new BrowserHyperlinkListener()); - initDescriptors(); + initToolStates(); fillTreeData(myProfileFilter != null ? myProfileFilter.getFilter() : null, true); JPanel descriptionPanel = new JPanel(new BorderLayout()); @@ -912,9 +970,7 @@ public class SingleInspectionProfilePanel extends JPanel { myRightSplitter.setFirstComponent(descriptionPanel); myRightSplitter.setProportion(myProperties.getFloat(HORIZONTAL_DIVIDER_PROPORTION, 0.5f)); - myOptionsPanel = new JPanel(new BorderLayout()); - myOptionsPanel.setBorder(IdeBorderFactory.createTitledBorder("Options", false, - new Insets(0, 0, 0, 0))); + myOptionsPanel = new JPanel(new GridBagLayout()); initOptionsAndDescriptionPanel(); myRightSplitter.setSecondComponent(myOptionsPanel); myRightSplitter.setHonorComponentsMinimumSize(true); @@ -925,8 +981,8 @@ public class SingleInspectionProfilePanel extends JPanel { final JPanel northPanel = new JPanel(new GridBagLayout()); northPanel.setBorder(IdeBorderFactory.createEmptyBorder(2, 0, 2, 0)); - northPanel.add(createTreeToolbarPanel().getComponent(), new GridBagConstraints(0, 0, 1, 1, 0.5, 1, GridBagConstraints.BASELINE_LEADING, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); - northPanel.add(myProfileFilter, new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.BASELINE_TRAILING, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); + northPanel.add(myProfileFilter, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.BASELINE_TRAILING, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); + northPanel.add(createTreeToolbarPanel().getComponent(), new GridBagConstraints(1, 0, 1, 1, 0.5, 1, GridBagConstraints.BASELINE_LEADING, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); treePanel.add(northPanel, BorderLayout.NORTH); myMainSplitter = new Splitter(false); @@ -1020,8 +1076,8 @@ public class SingleInspectionProfilePanel extends JPanel { } private boolean descriptorsAreChanged() { - for (Map.Entry<Descriptor, List<Descriptor>> entry : myDescriptors.entrySet()) { - Descriptor desc = entry.getKey(); + for (ToolDescriptors toolDescriptors : myInitialToolDescriptors) { + Descriptor desc = toolDescriptors.getDefaultDescriptor(); Project project = myProjectProfileManager.getProject(); if (mySelectedProfile.isToolEnabled(desc.getKey(), null, project) != desc.isEnabled()){ return true; @@ -1029,7 +1085,7 @@ public class SingleInspectionProfilePanel extends JPanel { if (mySelectedProfile.getErrorLevel(desc.getKey(), desc.getScope(), project) != desc.getLevel()) { return true; } - final List<Descriptor> descriptors = entry.getValue(); + final List<Descriptor> descriptors = toolDescriptors.getNonDefaultDescriptors(); for (Descriptor descriptor : descriptors) { if (mySelectedProfile.isToolEnabled(descriptor.getKey(), descriptor.getScope(), project) != descriptor.isEnabled()) { return true; @@ -1055,8 +1111,8 @@ public class SingleInspectionProfilePanel extends JPanel { return false; } - public Tree getTree() { - return myTree; + public Tree getTreeTable() { + return myTreeTable.getTree(); } public boolean isProfileShared() { @@ -1076,13 +1132,13 @@ public class SingleInspectionProfilePanel extends JPanel { } private void setNewHighlightingLevel(@NotNull HighlightDisplayLevel level) { - final int[] rows = myTree.getSelectionRows(); + final int[] rows = myTreeTable.getTree().getSelectionRows(); final boolean showOptionsAndDescriptorPanels = rows != null && rows.length == 1; for (int i = 0; rows != null && i < rows.length; i++) { - final InspectionConfigTreeNode node = (InspectionConfigTreeNode)myTree.getPathForRow(rows[i]).getLastPathComponent(); + final InspectionConfigTreeNode node = (InspectionConfigTreeNode)myTreeTable.getTree().getPathForRow(rows[i]).getLastPathComponent(); final InspectionConfigTreeNode parent = (InspectionConfigTreeNode)node.getParent(); final Object userObject = node.getUserObject(); - if (userObject instanceof Descriptor && (node.getScopeName() != null || node.isLeaf())) { + if (userObject instanceof ToolDescriptors && (node.getScopeName() != null || node.isLeaf())) { updateErrorLevel(node, showOptionsAndDescriptorPanels, level); updateUpHierarchy(node, parent); } @@ -1091,8 +1147,8 @@ public class SingleInspectionProfilePanel extends JPanel { updateUpHierarchy(node, parent); } } - if (rows != null && rows.length == 1) { - updateOptionsAndDescriptionPanel(myTree.getPathForRow(rows[0])); + if (rows != null) { + updateOptionsAndDescriptionPanel(myTreeTable.getTree().getSelectionPaths()); } else { initOptionsAndDescriptionPanel(); @@ -1107,7 +1163,7 @@ public class SingleInspectionProfilePanel extends JPanel { for (int j = 0; j < node.getChildCount(); j++) { final InspectionConfigTreeNode child = (InspectionConfigTreeNode)node.getChildAt(j); final Object userObject = child.getUserObject(); - if (userObject instanceof Descriptor && (child.getScopeName() != null || child.isLeaf())) { + if (userObject instanceof ToolDescriptors && (child.getScopeName() != null || child.isLeaf())) { updateErrorLevel(child, showOptionsAndDescriptorPanels, level); } else { @@ -1119,15 +1175,18 @@ public class SingleInspectionProfilePanel extends JPanel { private void updateErrorLevel(final InspectionConfigTreeNode child, final boolean showOptionsAndDescriptorPanels, @NotNull HighlightDisplayLevel level) { - final HighlightDisplayKey key = child.getDescriptor().getKey(); - mySelectedProfile.setErrorLevel(key, level, child.isInspectionNode() || child.isByDefault() ? -1 : child.getParent().getIndex(child), - myProjectProfileManager.getProject()); + final HighlightDisplayKey key = child.getDefaultDescriptor().getKey(); + mySelectedProfile.setErrorLevel(key, level, -1, myProjectProfileManager.getProject()); child.dropCache(); if (showOptionsAndDescriptorPanels) { updateOptionsAndDescriptionPanel(new TreePath(child.getPath())); } } + public JComponent getTree() { + return myTreeTable.getTree(); + } + private class MyFilterComponent extends FilterComponent { private MyFilterComponent() { super(INSPECTION_FILTER_HISTORY, 10); @@ -1143,47 +1202,14 @@ public class SingleInspectionProfilePanel extends JPanel { protected void onlineFilter() { if (mySelectedProfile == null) return; final String filter = getFilter(); - getExpandedNodes(mySelectedProfile).saveVisibleState(myTree); + getExpandedNodes(mySelectedProfile).saveVisibleState(myTreeTable.getTree()); fillTreeData(filter, true); reloadModel(); if (filter == null || filter.isEmpty()) { restoreTreeState(); } else { - TreeUtil.expandAll(myTree); - } - } - } - - private class MyAddScopeAction extends AddScopeAction { - public MyAddScopeAction() { - super(SingleInspectionProfilePanel.this.myTree); - } - - @Override - protected InspectionProfileImpl getSelectedProfile() { - return mySelectedProfile; - } - - @Override - public void actionPerformed(AnActionEvent e) { - super.actionPerformed(e); - final TreePath[] paths = myTree.getSelectionPaths(); - if (paths != null && paths.length == 1) { - updateOptionsAndDescriptionPanel(myTree.getSelectionPath()); - } else { - initOptionsAndDescriptionPanel(); + TreeUtil.expandAll(myTreeTable.getTree()); } } } - - private class MyDeleteScopeAction extends DeleteScopeAction { - public MyDeleteScopeAction() { - super(SingleInspectionProfilePanel.this.myTree); - } - - @Override - protected InspectionProfileImpl getSelectedProfile() { - return mySelectedProfile; - } - } } diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ToolDescriptors.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ToolDescriptors.java new file mode 100644 index 000000000000..47826735ec33 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ToolDescriptors.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui; + +import com.intellij.codeInspection.ex.Descriptor; +import com.intellij.codeInspection.ex.InspectionProfileImpl; +import com.intellij.codeInspection.ex.InspectionToolWrapper; +import com.intellij.codeInspection.ex.ScopeToolState; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class ToolDescriptors { + + @NotNull + private final Descriptor myDefaultDescriptor; + @NotNull + private final List<Descriptor> myNonDefaultDescriptors; + + private ToolDescriptors(final @NotNull Descriptor defaultDescriptor, + final @NotNull List<Descriptor> nonDefaultDescriptors) { + myDefaultDescriptor = defaultDescriptor; + myNonDefaultDescriptors = nonDefaultDescriptors; + } + + public static ToolDescriptors fromScopeToolState(final ScopeToolState state, + final InspectionProfileImpl profile, + final Project project) { + final InspectionToolWrapper toolWrapper = state.getTool(); + final List<ScopeToolState> nonDefaultTools = profile.getNonDefaultTools(toolWrapper.getShortName(), project); + final ArrayList<Descriptor> descriptors = new ArrayList<Descriptor>(nonDefaultTools.size()); + for (final ScopeToolState nonDefaultToolState : nonDefaultTools) { + descriptors.add(new Descriptor(nonDefaultToolState, profile, project)); + } + return new ToolDescriptors(new Descriptor(state, profile, project), descriptors); + } + + @NotNull + public Descriptor getDefaultDescriptor() { + return myDefaultDescriptor; + } + + @NotNull + public List<Descriptor> getNonDefaultDescriptors() { + return myNonDefaultDescriptors; + } + + @NotNull + public ScopeToolState getDefaultScopeToolState() { + return myDefaultDescriptor.getState(); + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/AddScopeAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/AddScopeAction.java deleted file mode 100644 index 3a1031946b6b..000000000000 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/AddScopeAction.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2000-2012 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. - */ - -/* - * User: anna - * Date: 14-May-2009 - */ -package com.intellij.profile.codeInspection.ui.actions; - -import com.intellij.codeHighlighting.HighlightDisplayLevel; -import com.intellij.codeInspection.ex.Descriptor; -import com.intellij.codeInspection.ex.InspectionProfileImpl; -import com.intellij.codeInspection.ex.InspectionToolWrapper; -import com.intellij.codeInspection.ex.ScopeToolState; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.ui.Messages; -import com.intellij.packageDependencies.DefaultScopesProvider; -import com.intellij.profile.codeInspection.ui.InspectionConfigTreeNode; -import com.intellij.psi.search.scope.packageSet.CustomScopesProviderEx; -import com.intellij.psi.search.scope.packageSet.NamedScope; -import com.intellij.psi.search.scope.packageSet.NamedScopesHolder; -import com.intellij.ui.treeStructure.Tree; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IconUtil; - -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreePath; -import java.util.*; - -public abstract class AddScopeAction extends AnAction { - private final Tree myTree; - private static final Logger LOG = Logger.getInstance("#" + AddScopeAction.class.getName()); - - public AddScopeAction(Tree tree) { - super("Add Scope", "Add Scope", IconUtil.getAddIcon()); - myTree = tree; - registerCustomShortcutSet(CommonShortcuts.INSERT, myTree); - } - - @Override - public void update(AnActionEvent e) { - final Presentation presentation = e.getPresentation(); - presentation.setEnabled(false); - if (getSelectedProfile() == null) return; - final Project project = getProject(e); - final InspectionConfigTreeNode[] selectedNodes = myTree.getSelectedNodes(InspectionConfigTreeNode.class, null); - if (selectedNodes == null) return; - final List<Descriptor> descriptors = new ArrayList<Descriptor>(); - for (InspectionConfigTreeNode node : selectedNodes) { - collect(descriptors, new ArrayList<InspectionConfigTreeNode>(), node); - } - - presentation.setEnabled(!getAvailableScopes(project, descriptors).isEmpty()); - } - - private static Project getProject(AnActionEvent e) { - Project project = CommonDataKeys.PROJECT.getData(e.getDataContext()); - if (project == null) { - project = ProjectManager.getInstance().getDefaultProject(); - } - return project; - } - - @Override - public void actionPerformed(AnActionEvent e) { - final List<Descriptor> descriptors = new ArrayList<Descriptor>(); - final InspectionConfigTreeNode[] selectedNodes = myTree.getSelectedNodes(InspectionConfigTreeNode.class, null); - LOG.assertTrue(selectedNodes != null); - - final List<InspectionConfigTreeNode> nodes = new ArrayList<InspectionConfigTreeNode>(Arrays.asList(selectedNodes)); - for (InspectionConfigTreeNode node : selectedNodes) { - collect(descriptors, nodes, node); - } - - final Project project = getProject(e); - final List<String> availableScopes = getAvailableScopes(project, descriptors); - final int idx = Messages.showChooseDialog(myTree, "Scope:", "Choose Scope", ArrayUtil.toStringArray(availableScopes), availableScopes.get(0), Messages.getQuestionIcon()); - if (idx == -1) return; - final NamedScope chosenScope = NamedScopesHolder.getScope(project, availableScopes.get(idx)); - - for (InspectionConfigTreeNode node : nodes) { - final Descriptor descriptor = node.getDescriptor(); - if (node.getScopeName() != null || descriptor == null) continue; - final InspectionToolWrapper toolWrapper = descriptor.getToolWrapper(); //copy - InspectionProfileImpl selectedProfile = getSelectedProfile(); - HighlightDisplayLevel level = selectedProfile.getErrorLevel(descriptor.getKey(), chosenScope, project); - boolean enabled = selectedProfile.isToolEnabled(descriptor.getKey()); - final ScopeToolState scopeToolState = selectedProfile.addScope(toolWrapper, chosenScope, level, enabled, project); - final Descriptor addedDescriptor = new Descriptor(scopeToolState, selectedProfile, project); - if (node.getChildCount() == 0) { - node.add(new InspectionConfigTreeNode(descriptor, selectedProfile.getToolDefaultState(descriptor.getKey().toString(), project), true, true, false)); - } - node.insert(new InspectionConfigTreeNode(addedDescriptor, scopeToolState, false, false), 0); - node.setInspectionNode(false); - node.dropCache(); - ((DefaultTreeModel)myTree.getModel()).reload(node); - myTree.expandPath(new TreePath(node.getPath())); - } - myTree.revalidate(); - } - - private static void collect(List<Descriptor> descriptors, - List<InspectionConfigTreeNode> nodes, - InspectionConfigTreeNode node) { - final Descriptor descriptor = node.getDescriptor(); - if (descriptor != null) { - if (node.getScopeName() == null) { - descriptors.add(descriptor); - } - } else if (node.getUserObject() instanceof String) { - for(int i = 0; i < node.getChildCount(); i++) { - final InspectionConfigTreeNode childNode = (InspectionConfigTreeNode)node.getChildAt(i); - nodes.add(childNode); - collect(descriptors, nodes, childNode); - } - } - } - - private List<String> getAvailableScopes(Project project, List<Descriptor> descriptors) { - final ArrayList<NamedScope> scopes = new ArrayList<NamedScope>(); - for (NamedScopesHolder holder : NamedScopesHolder.getAllNamedScopeHolders(project)) { - Collections.addAll(scopes, holder.getScopes()); - } - scopes.remove(CustomScopesProviderEx.getAllScope()); - - CustomScopesProviderEx.filterNoSettingsScopes(project, scopes); - - final Set<NamedScope> used = new HashSet<NamedScope>(); - for (Descriptor descriptor : descriptors) { - final List<ScopeToolState> nonDefaultTools = getSelectedProfile().getNonDefaultTools(descriptor.getKey().toString(), project); - if (nonDefaultTools != null) { - for (ScopeToolState state : nonDefaultTools) { - used.add(state.getScope(project)); - } - } - } - scopes.removeAll(used); - - final List<String> availableScopes = new ArrayList<String>(); - for (NamedScope scope : scopes) { - availableScopes.add(scope.getName()); - } - return availableScopes; - } - - protected abstract InspectionProfileImpl getSelectedProfile(); -}
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/DeleteScopeAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/DeleteScopeAction.java deleted file mode 100644 index 1fc94c2d15b2..000000000000 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/DeleteScopeAction.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2000-2012 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. - */ - -/* - * User: anna - * Date: 14-May-2009 - */ -package com.intellij.profile.codeInspection.ui.actions; - -import com.intellij.codeInsight.daemon.HighlightDisplayKey; -import com.intellij.codeInspection.ex.Descriptor; -import com.intellij.codeInspection.ex.InspectionProfileImpl; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonShortcuts; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.profile.codeInspection.ui.InspectionConfigTreeNode; -import com.intellij.ui.treeStructure.Tree; -import com.intellij.util.PlatformIcons; - -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreePath; - -public abstract class DeleteScopeAction extends AnAction { - private static final Logger LOG = Logger.getInstance("#" + DeleteScopeAction.class.getName()); - private final Tree myTree; - - public DeleteScopeAction(Tree tree) { - super("Delete Scope", "Delete Scope", PlatformIcons.DELETE_ICON); - myTree = tree; - registerCustomShortcutSet(CommonShortcuts.getDelete(), myTree); - } - - @Override - public void update(AnActionEvent e) { - final Presentation presentation = e.getPresentation(); - presentation.setEnabled(false); - if (getSelectedProfile() == null) return; - final InspectionConfigTreeNode[] nodes = myTree.getSelectedNodes(InspectionConfigTreeNode.class, null); - if (nodes.length > 0) { - for (InspectionConfigTreeNode node : nodes) { - if (node.getScopeName() == null || node.isByDefault()) return; - } - presentation.setEnabled(true); - } - } - - @Override - public void actionPerformed(AnActionEvent e) { - InspectionConfigTreeNode parent = null; - final InspectionConfigTreeNode[] nodes = myTree.getSelectedNodes(InspectionConfigTreeNode.class, null); - for (InspectionConfigTreeNode node : nodes) { - final Descriptor descriptor = node.getDescriptor(); - LOG.assertTrue(descriptor != null); - parent = (InspectionConfigTreeNode)node.getParent(); - final HighlightDisplayKey key = descriptor.getKey(); - if (parent.getChildCount() <= 2) { //remove default with last non-default - getSelectedProfile().removeAllScopes(key.toString(), e.getProject()); - parent.removeAllChildren(); - parent.setInspectionNode(true); - parent.setByDefault(true); - } - else { - getSelectedProfile().removeScope(key.toString(), parent.getIndex(node), e.getProject()); - node.removeFromParent(); - } - ((DefaultTreeModel)myTree.getModel()).reload(parent); - } - if (parent != null) { - myTree.setSelectionPath(new TreePath(parent.getPath())); - } - myTree.revalidate(); - } - - protected abstract InspectionProfileImpl getSelectedProfile(); -}
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/MoveScopeAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/MoveScopeAction.java deleted file mode 100644 index 40d4b438f995..000000000000 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/MoveScopeAction.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2000-2012 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. - */ - -/* - * User: anna - * Date: 14-May-2009 - */ -package com.intellij.profile.codeInspection.ui.actions; - -import com.intellij.codeInspection.ex.Descriptor; -import com.intellij.codeInspection.ex.InspectionProfileImpl; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.profile.codeInspection.ui.InspectionConfigTreeNode; -import com.intellij.ui.treeStructure.Tree; - -import javax.swing.*; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; - -public abstract class MoveScopeAction extends AnAction { - private final Tree myTree; - private final int myDir; - - public MoveScopeAction(Tree tree, String text, Icon icon, int dir) { - super(text, text, icon); - myTree = tree; - myDir = dir; - } - - protected abstract boolean isEnabledFor(int idx, InspectionConfigTreeNode parent); - - - @Override - public void update(AnActionEvent e) { - final Presentation presentation = e.getPresentation(); - presentation.setEnabled(false); - if (getSelectedProfile() == null) return; - final InspectionConfigTreeNode[] nodes = myTree.getSelectedNodes(InspectionConfigTreeNode.class, null); - if (nodes.length > 0) { - final InspectionConfigTreeNode treeNode = nodes[0]; - if (treeNode.getScope(getEventProject(e)) != null && !treeNode.isByDefault()) { - final TreeNode parent = treeNode.getParent(); - final int index = parent.getIndex(treeNode); - presentation.setEnabled(isEnabledFor(index, (InspectionConfigTreeNode)parent)); - } - } - } - - @Override - public void actionPerformed(AnActionEvent e) { - final InspectionConfigTreeNode[] nodes = myTree.getSelectedNodes(InspectionConfigTreeNode.class, null); - final InspectionConfigTreeNode node = nodes[0]; - final Descriptor descriptor = node.getDescriptor(); - final TreeNode parent = node.getParent(); - final int index = parent.getIndex(node); - getSelectedProfile().moveScope(descriptor.getKey().toString(), index, myDir, e.getProject()); - node.removeFromParent(); - ((InspectionConfigTreeNode)parent).insert(node, index + myDir); - ((DefaultTreeModel)myTree.getModel()).reload(parent); - myTree.setSelectionPath(new TreePath(node.getPath())); - myTree.revalidate(); - } - - protected abstract InspectionProfileImpl getSelectedProfile(); -}
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java new file mode 100644 index 000000000000..cbd1c2482032 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java @@ -0,0 +1,129 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui.filter; + +import com.intellij.codeHighlighting.HighlightDisplayLevel; +import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; +import com.intellij.codeInspection.ex.InspectionProfileImpl; +import com.intellij.icons.AllIcons; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.actionSystem.ex.CheckboxAction; +import com.intellij.profile.codeInspection.SeverityProvider; +import com.intellij.profile.codeInspection.ui.LevelChooserAction; +import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; +import org.jetbrains.annotations.Nullable; + +import java.util.SortedSet; + +/** + * @author Dmitry Batkovich + */ +public class InspectionFilterAction extends DefaultActionGroup { + + private final SeverityRegistrar mySeverityRegistrar; + private final InspectionsFilter myInspectionsFilter; + + public InspectionFilterAction(final InspectionProfileImpl profile, final InspectionsFilter inspectionsFilter) { + super("Filter Inspections", true); + myInspectionsFilter = inspectionsFilter; + mySeverityRegistrar = ((SeverityProvider)profile.getProfileManager()).getOwnSeverityRegistrar(); + getTemplatePresentation().setIcon(AllIcons.General.Filter); + tune(); + } + + private void tune() { + addAction(new ShowEnabledOrDisabledInspectionsAction(null)); + addAction(new ShowEnabledOrDisabledInspectionsAction(true)); + addAction(new ShowEnabledOrDisabledInspectionsAction(false)); + addSeparator(); + + final SortedSet<HighlightSeverity> severities = LevelChooserAction.getSeverities(mySeverityRegistrar); + for (final HighlightSeverity severity : severities) { + add(new ShowWithSpecifiedSeverityInspectionsAction(severity)); + } + addSeparator(); + + add(new ShowAvailableOnlyOnAnalyzeInspectionsAction()); + } + + private class ShowAvailableOnlyOnAnalyzeInspectionsAction extends CheckboxAction { + + public ShowAvailableOnlyOnAnalyzeInspectionsAction() { + super("Show Only \"Available only for Analyze | Inspect Code\""); + } + + @Override + public boolean isSelected(final AnActionEvent e) { + return myInspectionsFilter.isAvailableOnlyForAnalyze(); + } + + @Override + public void setSelected(final AnActionEvent e, final boolean state) { + myInspectionsFilter.setAvailableOnlyForAnalyze(state); + } + } + + private class ShowWithSpecifiedSeverityInspectionsAction extends CheckboxAction { + + private final HighlightSeverity mySeverity; + + private ShowWithSpecifiedSeverityInspectionsAction(final HighlightSeverity severity) { + super(SingleInspectionProfilePanel.renderSeverity(severity), + null, + HighlightDisplayLevel.find(severity).getIcon()); + mySeverity = severity; + } + + + @Override + public boolean isSelected(final AnActionEvent e) { + return myInspectionsFilter.containsSeverity(mySeverity); + } + + @Override + public void setSelected(final AnActionEvent e, final boolean state) { + if (state) { + myInspectionsFilter.add(mySeverity); + } else { + myInspectionsFilter.remove(mySeverity); + } + } + } + + private class ShowEnabledOrDisabledInspectionsAction extends CheckboxAction { + + private final Boolean myShowEnabledActions; + + public ShowEnabledOrDisabledInspectionsAction(@Nullable final Boolean showEnabledActions) { + super(showEnabledActions == null ? "All Inspections" : (showEnabledActions ? "Enabled" : "Disabled")); + myShowEnabledActions = showEnabledActions; + } + + + @Override + public boolean isSelected(final AnActionEvent e) { + return myInspectionsFilter.getSuitableInspectionsStates() == myShowEnabledActions; + } + + @Override + public void setSelected(final AnActionEvent e, final boolean state) { + myInspectionsFilter.setSuitableInspectionsStates(myShowEnabledActions); + } + } +}
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionsFilter.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionsFilter.java new file mode 100644 index 000000000000..432ef560ba58 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionsFilter.java @@ -0,0 +1,102 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui.filter; + +import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper; +import com.intellij.codeInspection.ex.InspectionToolWrapper; +import com.intellij.codeInspection.ex.ScopeToolState; +import com.intellij.codeInspection.ex.Tools; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.util.containers.HashSet; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +/** + * @author Dmitry Batkovich + */ +public abstract class InspectionsFilter { + + private final Set<HighlightSeverity> mySuitableSeverities = new HashSet<HighlightSeverity>(); + private Boolean mySuitableInspectionsStates; + private boolean myAvailableOnlyForAnalyze; + + public boolean isAvailableOnlyForAnalyze() { + return myAvailableOnlyForAnalyze; + } + + public Boolean getSuitableInspectionsStates() { + return mySuitableInspectionsStates; + } + + public boolean containsSeverity(final HighlightSeverity severity) { + return mySuitableSeverities.contains(severity); + } + + public void setAvailableOnlyForAnalyze(final boolean availableOnlyForAnalyze) { + myAvailableOnlyForAnalyze = availableOnlyForAnalyze; + filterChanged(); + } + + public void setSuitableInspectionsStates(@Nullable final Boolean suitableInspectionsStates) { + mySuitableInspectionsStates = suitableInspectionsStates; + filterChanged(); + } + + public void add(final HighlightSeverity severity) { + mySuitableSeverities.add(severity); + filterChanged(); + } + + public void remove(final HighlightSeverity severity) { + mySuitableSeverities.remove(severity); + filterChanged(); + } + + public boolean isEmptyFilter() { + return mySuitableInspectionsStates == null && !myAvailableOnlyForAnalyze && mySuitableSeverities.isEmpty(); + } + + public boolean matches(final Tools tools) { + if (mySuitableInspectionsStates != null && mySuitableInspectionsStates != tools.isEnabled()) { + return false; + } + + if (myAvailableOnlyForAnalyze != isAvailableOnlyForAnalyze(tools)) { + return false; + } + + if (mySuitableSeverities.isEmpty()) { + return true; + } + for (final ScopeToolState state : tools.getTools()) { + if (mySuitableInspectionsStates != null && mySuitableInspectionsStates != state.isEnabled()) { + continue; + } + if (mySuitableSeverities.contains(tools.getDefaultState().getLevel().getSeverity())) { + return true; + } + } + return false; + } + + protected abstract void filterChanged(); + + private static boolean isAvailableOnlyForAnalyze(final Tools tools) { + final InspectionToolWrapper tool = tools.getTool(); + return tool instanceof GlobalInspectionToolWrapper && ((GlobalInspectionToolWrapper)tool).worksInBatchModeOnly(); + } +}
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionConfigTreeNode.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionConfigTreeNode.java index f8fdc2c3dc5f..1f26308c61b1 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionConfigTreeNode.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionConfigTreeNode.java @@ -13,31 +13,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.profile.codeInspection.ui; +package com.intellij.profile.codeInspection.ui.inspectionsTree; +import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInspection.ex.Descriptor; -import com.intellij.codeInspection.ex.ScopeToolState; -import com.intellij.openapi.project.Project; import com.intellij.openapi.util.ClearableLazyValue; -import com.intellij.psi.search.scope.packageSet.NamedScope; -import com.intellij.ui.CheckedTreeNode; +import com.intellij.profile.codeInspection.ui.ToolDescriptors; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.tree.DefaultMutableTreeNode; + /** * @author anna * @since 14-May-2009 */ -public class InspectionConfigTreeNode extends CheckedTreeNode { - private final ScopeToolState myState; - private boolean myByDefault; - private boolean myInspectionNode; +public class InspectionConfigTreeNode extends DefaultMutableTreeNode { private final ClearableLazyValue<Boolean> myProperSetting = new ClearableLazyValue<Boolean>() { @NotNull @Override protected Boolean compute() { - Descriptor descriptor = getDescriptor(); - if (descriptor != null) return descriptor.getInspectionProfile().isProperSetting(descriptor.getToolWrapper().getShortName()); + ToolDescriptors descriptors = getDescriptors(); + if (descriptors != null) { + final Descriptor defaultDescriptor = descriptors.getDefaultDescriptor(); + return defaultDescriptor.getInspectionProfile().isProperSetting(defaultDescriptor.getToolWrapper().getShortName()); + } for (int i = 0; i < getChildCount(); i++) { InspectionConfigTreeNode node = (InspectionConfigTreeNode)getChildAt(i); if (node.isProperSetting()) { @@ -48,35 +48,24 @@ public class InspectionConfigTreeNode extends CheckedTreeNode { } }; - public InspectionConfigTreeNode(@NotNull Object userObject, ScopeToolState state, boolean byDefault, boolean inspectionNode) { + public InspectionConfigTreeNode(@NotNull Object userObject) { super(userObject); - myState = state; - myByDefault = byDefault; - myInspectionNode = inspectionNode; - if (state != null) { - setChecked(state.isEnabled()); - } } - public InspectionConfigTreeNode(@NotNull Descriptor descriptor, ScopeToolState state, boolean byDefault, boolean isEnabled, - boolean inspectionNode) { - this(descriptor, state, byDefault, inspectionNode); - setChecked(isEnabled); + public HighlightDisplayKey getKey() { + return getDefaultDescriptor().getKey(); } @Nullable - public Descriptor getDescriptor() { - if (userObject instanceof String) return null; - return (Descriptor)userObject; + public Descriptor getDefaultDescriptor() { + final ToolDescriptors descriptors = getDescriptors(); + return descriptors == null ? null : descriptors.getDefaultDescriptor(); } @Nullable - public NamedScope getScope(Project project) { - return myState == null ? null : myState.getScope(project); - } - - public boolean isByDefault() { - return myByDefault; + public ToolDescriptors getDescriptors() { + if (userObject instanceof String) return null; + return (ToolDescriptors)userObject; } @Nullable @@ -84,21 +73,10 @@ public class InspectionConfigTreeNode extends CheckedTreeNode { return userObject instanceof String ? (String)userObject : null; } - public boolean isInspectionNode() { - return myInspectionNode; - } - - public void setInspectionNode(boolean inspectionNode) { - myInspectionNode = inspectionNode; - } - - public void setByDefault(boolean byDefault) { - myByDefault = byDefault; - } - @Nullable public String getScopeName() { - return myState != null ? myState.getScopeName() : null; + final ToolDescriptors descriptors = getDescriptors(); + return descriptors != null ? descriptors.getDefaultScopeToolState().getScopeName() : null; } public boolean isProperSetting() { diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionsConfigTreeComparator.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeComparator.java index fe60c51e49b9..b920b0b741ab 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionsConfigTreeComparator.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeComparator.java @@ -18,9 +18,9 @@ * User: anna * Date: 14-May-2009 */ -package com.intellij.profile.codeInspection.ui; +package com.intellij.profile.codeInspection.ui.inspectionsTree; -import com.intellij.codeInspection.ex.Descriptor; +import com.intellij.profile.codeInspection.ui.ToolDescriptors; import java.util.Comparator; @@ -44,11 +44,11 @@ public class InspectionsConfigTreeComparator implements Comparator<InspectionCon return getDisplayTextToSort(s1).compareToIgnoreCase(getDisplayTextToSort(s2)); } - final Descriptor descriptor1 = o1.getDescriptor(); - final Descriptor descriptor2 = o2.getDescriptor(); - if (descriptor1 != null && descriptor2 != null) { - s1 = descriptor1.getText(); - s2 = descriptor2.getText(); + final ToolDescriptors descriptors1 = o1.getDescriptors(); + final ToolDescriptors descriptors2 = o2.getDescriptors(); + if (descriptors1 != null && descriptors2 != null) { + s1 = descriptors1.getDefaultDescriptor().getText(); + s2 = descriptors2.getDefaultDescriptor().getText(); } if (s1 != null && s2 != null) { diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionsConfigTreeRenderer.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java index 8094a1bfd415..43b791cbe6a2 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionsConfigTreeRenderer.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java @@ -18,7 +18,7 @@ * User: anna * Date: 14-May-2009 */ -package com.intellij.profile.codeInspection.ui; +package com.intellij.profile.codeInspection.ui.inspectionsTree; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ex.Descriptor; @@ -26,29 +26,23 @@ import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper; import com.intellij.codeInspection.ex.InspectionToolWrapper; import com.intellij.codeInspection.ex.LocalInspectionToolWrapper; import com.intellij.ide.ui.search.SearchUtil; -import com.intellij.openapi.project.Project; -import com.intellij.ui.CheckboxTree; -import com.intellij.ui.JBColor; +import com.intellij.profile.codeInspection.ui.ToolDescriptors; +import com.intellij.ui.ColoredTreeCellRenderer; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.ui.PlatformColors; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -abstract class InspectionsConfigTreeRenderer extends CheckboxTree.CheckboxTreeCellRenderer { - private final Project myProject; - - public InspectionsConfigTreeRenderer(Project project) { - myProject = project; - } - +public abstract class InspectionsConfigTreeRenderer extends ColoredTreeCellRenderer { protected abstract String getFilter(); @Override - public void customizeRenderer(final JTree tree, + public void customizeCellRenderer(@NotNull final JTree tree, final Object value, final boolean selected, final boolean expanded, @@ -73,41 +67,25 @@ abstract class InspectionsConfigTreeRenderer extends CheckboxTree.CheckboxTreeCe style = SimpleTextAttributes.STYLE_BOLD; } else { - final Descriptor descriptor = node.getDescriptor(); - final String scopeName = node.getScopeName(); - if (scopeName != null) { - if (node.isByDefault()) { - text = "Everywhere else"; - } - else { - text = "In scope \'" + scopeName + "\'"; - if (node.getScope(myProject) == null) { - foreground = JBColor.RED; - } - } - } else { - text = descriptor.getText(); - } - hint = getHint(descriptor); + final ToolDescriptors descriptors = node.getDescriptors(); + assert descriptors != null; + final Descriptor defaultDescriptor = descriptors.getDefaultDescriptor(); + text = defaultDescriptor.getText(); + hint = getHint(defaultDescriptor); } if (text != null) { - SearchUtil.appendFragments(getFilter(), text, style, foreground, background, - getTextRenderer()); + SearchUtil.appendFragments(getFilter(), text, style, foreground, background, this); } if (hint != null) { - getTextRenderer() - .append(" " + hint, selected ? new SimpleTextAttributes(Font.PLAIN, foreground) : SimpleTextAttributes.GRAYED_ATTRIBUTES); + append(" " + hint, selected ? new SimpleTextAttributes(Font.PLAIN, foreground) : SimpleTextAttributes.GRAYED_ATTRIBUTES); } setForeground(foreground); } @Nullable - private static String getHint(Descriptor descriptor) { + private static String getHint(final Descriptor descriptor) { final InspectionToolWrapper toolWrapper = descriptor.getToolWrapper(); - if (toolWrapper == null) { - return InspectionsBundle.message("inspection.tool.availability.in.tree.node"); - } if (toolWrapper instanceof LocalInspectionToolWrapper || toolWrapper instanceof GlobalInspectionToolWrapper && !((GlobalInspectionToolWrapper)toolWrapper).worksInBatchModeOnly()) { return null; diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java new file mode 100644 index 000000000000..966a456e1d38 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java @@ -0,0 +1,257 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui.inspectionsTree; + +import com.intellij.codeHighlighting.HighlightDisplayLevel; +import com.intellij.codeInsight.daemon.HighlightDisplayKey; +import com.intellij.codeInspection.ex.InspectionProfileImpl; +import com.intellij.codeInspection.ex.ScopeToolState; +import com.intellij.ide.IdeTooltip; +import com.intellij.ide.IdeTooltipManager; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.profile.codeInspection.ui.InspectionsAggregationUtil; +import com.intellij.profile.codeInspection.ui.table.ScopesAndSeveritiesTable; +import com.intellij.profile.codeInspection.ui.table.ThreeStateCheckBoxRenderer; +import com.intellij.ui.treeStructure.treetable.TreeTable; +import com.intellij.ui.treeStructure.treetable.TreeTableModel; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.table.TableColumn; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreeNode; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.*; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class InspectionsConfigTreeTable extends TreeTable { + private final static Logger LOG = Logger.getInstance(InspectionsConfigTreeTable.class); + + private final static int TREE_COLUMN = 0; + private final static int SEVERITIES_COLUMN = 1; + private final static int IS_ENABLED_COLUMN = 2; + + public InspectionsConfigTreeTable(final InspectionsConfigTreeTableSettings settings) { + super(new InspectionsConfigTreeTableModel(settings)); + + final TableColumn severitiesColumn = getColumnModel().getColumn(SEVERITIES_COLUMN); + severitiesColumn.setMaxWidth(20); + + final TableColumn isEnabledColumn = getColumnModel().getColumn(IS_ENABLED_COLUMN); + isEnabledColumn.setMaxWidth(20); + isEnabledColumn.setCellRenderer(new ThreeStateCheckBoxRenderer()); + isEnabledColumn.setCellEditor(new ThreeStateCheckBoxRenderer()); + + addMouseMotionListener(new MouseAdapter() { + @Override + public void mouseMoved(final MouseEvent e) { + final Point point = e.getPoint(); + final int column = columnAtPoint(point); + if (column != SEVERITIES_COLUMN) { + return; + } + final int row = rowAtPoint(point); + final Object maybeIcon = getModel().getValueAt(row, column); + if (maybeIcon instanceof MultiScopeSeverityIcon) { + final LinkedHashMap<String, HighlightSeverity> scopeToAverageSeverityMap = + ((MultiScopeSeverityIcon)maybeIcon).getScopeToAverageSeverityMap(); + IdeTooltipManager.getInstance().show(new IdeTooltip(InspectionsConfigTreeTable.this, point, new ScopesAndSeveritiesHintTable(scopeToAverageSeverityMap)), false); + } + } + }); + } + + public abstract static class InspectionsConfigTreeTableSettings { + private final TreeNode myRoot; + private final Project myProject; + + public InspectionsConfigTreeTableSettings(final TreeNode root, final Project project) { + myRoot = root; + myProject = project; + } + + public TreeNode getRoot() { + return myRoot; + } + + public Project getProject() { + return myProject; + } + + protected abstract InspectionProfileImpl getInspectionProfile(); + + protected abstract void onChanged(InspectionConfigTreeNode node); + } + + private static class InspectionsConfigTreeTableModel extends DefaultTreeModel implements TreeTableModel { + + private final InspectionsConfigTreeTableSettings mySettings; + + public InspectionsConfigTreeTableModel(final InspectionsConfigTreeTableSettings settings) { + super(settings.getRoot()); + mySettings = settings; + } + + @Override + public int getColumnCount() { + return 3; + } + + @Nullable + @Override + public String getColumnName(final int column) { + return null; + } + + @Override + public Class getColumnClass(final int column) { + switch (column) { + case TREE_COLUMN: + return TreeTableModel.class; + case SEVERITIES_COLUMN: + return Icon.class; + case IS_ENABLED_COLUMN: + return Boolean.class; + } + throw new IllegalArgumentException(); + } + + @Nullable + @Override + public Object getValueAt(final Object node, final int column) { + if (column == TREE_COLUMN) { + return null; + } + final InspectionConfigTreeNode treeNode = (InspectionConfigTreeNode)node; + final List<HighlightDisplayKey> inspectionsKeys = InspectionsAggregationUtil.getInspectionsKeys(treeNode); + if (column == SEVERITIES_COLUMN) { + final MultiColoredHighlightSeverityIconSink sink = new MultiColoredHighlightSeverityIconSink(); + for (final HighlightDisplayKey selectedInspectionsNode : inspectionsKeys) { + final String toolId = selectedInspectionsNode.toString(); + if (mySettings.getInspectionProfile().getTools(toolId, mySettings.getProject()).isEnabled()) { + sink.put(mySettings.getInspectionProfile().getToolDefaultState(toolId, mySettings.getProject()), + mySettings.getInspectionProfile().getNonDefaultTools(toolId, mySettings.getProject())); + } + } + return sink.constructIcon(); + } else if (column == IS_ENABLED_COLUMN) { + return isEnabled(inspectionsKeys); + } + throw new IllegalArgumentException(); + } + + @Nullable + private Boolean isEnabled(final List<HighlightDisplayKey> selectedInspectionsNodes) { + Boolean isPreviousEnabled = null; + for (final HighlightDisplayKey key : selectedInspectionsNodes) { + final boolean enabled = mySettings.getInspectionProfile().getTools(key.toString(), mySettings.getProject()).isEnabled(); + if (isPreviousEnabled == null) { + isPreviousEnabled = enabled; + } else if (!isPreviousEnabled.equals(enabled)) { + return null; + } + } + return isPreviousEnabled; + } + + @Override + public boolean isCellEditable(final Object node, final int column) { + return column == IS_ENABLED_COLUMN; + } + + @Override + public void setValueAt(final Object aValue, final Object node, final int column) { + LOG.assertTrue(column == IS_ENABLED_COLUMN); + LOG.assertTrue(aValue != null); + final boolean doEnable = (Boolean) aValue; + for (final InspectionConfigTreeNode aNode : InspectionsAggregationUtil.getInspectionsNodes((InspectionConfigTreeNode) node)) { + final String toolId = aNode.getKey().toString(); + if (doEnable) { + mySettings.getInspectionProfile().enableTool(toolId, mySettings.getProject()); + } else { + mySettings.getInspectionProfile().disableTool(toolId, mySettings.getProject()); + } + aNode.dropCache(); + mySettings.onChanged(aNode); + } + } + + @Override + public void setTree(final JTree tree) { + } + } + + private static class MultiColoredHighlightSeverityIconSink { + + private final LinkedHashMap<String, HighlightSeverity> myScopeToAverageSeverityMap = new LinkedHashMap<String, HighlightSeverity>(); + + private boolean myIsFirst = true; + + public Icon constructIcon() { + if (myScopeToAverageSeverityMap.isEmpty()) { + return null; + } + //TODO order scopes + return !allScopesHasMixedSeverity() + ? new MultiScopeSeverityIcon(myScopeToAverageSeverityMap) + : ScopesAndSeveritiesTable.MIXED_FAKE_LEVEL.getIcon(); + } + + private boolean allScopesHasMixedSeverity() { + for (final Map.Entry<String, HighlightSeverity> e : myScopeToAverageSeverityMap.entrySet()) { + if (!ScopesAndSeveritiesTable.MIXED_FAKE_SEVERITY.equals(e.getValue())) { + return false; + } + } + return true; + } + + public void put(final ScopeToolState defaultState, final Collection<ScopeToolState> nonDefault) { + putOne(defaultState); + for (final ScopeToolState scopeToolState : nonDefault) { + putOne(scopeToolState); + } + if (myIsFirst) { + myIsFirst = false; + } + } + + public void putOne(final ScopeToolState state) { + final Icon icon = state.getLevel().getIcon(); + final String scopeName = state.getScopeName(); + if (icon instanceof HighlightDisplayLevel.SingleColorIconWithMask) { + if (myIsFirst) { + myScopeToAverageSeverityMap.put(scopeName, state.getLevel().getSeverity()); + } else { + final HighlightSeverity severity = myScopeToAverageSeverityMap.get(scopeName); + if (!ScopesAndSeveritiesTable.MIXED_FAKE_SEVERITY.equals(severity) && !Comparing.equal(severity, state.getLevel().getSeverity())) { + myScopeToAverageSeverityMap.put(scopeName, ScopesAndSeveritiesTable.MIXED_FAKE_SEVERITY); + } + } + } else if (!ScopesAndSeveritiesTable.MIXED_FAKE_SEVERITY.equals(myScopeToAverageSeverityMap.get(scopeName))) { + myScopeToAverageSeverityMap.put(scopeName, ScopesAndSeveritiesTable.MIXED_FAKE_SEVERITY); + } + } + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/MultiScopeSeverityIcon.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/MultiScopeSeverityIcon.java new file mode 100644 index 000000000000..6f093ca66349 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/MultiScopeSeverityIcon.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui.inspectionsTree; + + +import com.intellij.codeHighlighting.HighlightDisplayLevel; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.ui.JBColor; + +import javax.swing.*; +import java.awt.*; +import java.util.Collection; +import java.util.LinkedHashMap; + +/** + * @author Dmitry Batkovich + */ +public class MultiScopeSeverityIcon implements Icon { + private final static JBColor MIXED_SEVERITY_COLOR = JBColor.DARK_GRAY; + + private final static int SIZE = 12; + + private final LinkedHashMap<String, HighlightSeverity> myScopeToAverageSeverityMap; + + public MultiScopeSeverityIcon(final LinkedHashMap<String, HighlightSeverity> scopeToAverageSeverityMap) { + myScopeToAverageSeverityMap = scopeToAverageSeverityMap; + } + + public LinkedHashMap<String, HighlightSeverity> getScopeToAverageSeverityMap() { + return myScopeToAverageSeverityMap; + } + + @Override + public void paintIcon(final Component c, final Graphics g, final int i, final int j) { + final int iconWidth = getIconWidth(); + + final int partWidth = iconWidth / myScopeToAverageSeverityMap.size(); + + final Collection<HighlightSeverity> values = myScopeToAverageSeverityMap.values(); + int idx = 0; + for (final HighlightSeverity severity : values) { + final Icon icon = HighlightDisplayLevel.find(severity).getIcon(); + g.setColor(icon instanceof HighlightDisplayLevel.SingleColorIconWithMask ? + ((HighlightDisplayLevel.SingleColorIconWithMask)icon).getColor() : MIXED_SEVERITY_COLOR); + final int x = i + partWidth * idx; + g.fillRect(x, j, partWidth, getIconHeight()); + idx++; + } + g.drawImage(HighlightDisplayLevel.ImageHolder.ourErrorMaskImage, i, j, null); + } + + @Override + public int getIconWidth() { + return SIZE; + } + + @Override + public int getIconHeight() { + return SIZE; + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/ScopesAndSeveritiesHintTable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/ScopesAndSeveritiesHintTable.java new file mode 100644 index 000000000000..05cb7ab193f5 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/ScopesAndSeveritiesHintTable.java @@ -0,0 +1,106 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui.inspectionsTree; + +import com.intellij.codeHighlighting.HighlightDisplayLevel; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; +import com.intellij.ui.table.JBTable; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import java.awt.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class ScopesAndSeveritiesHintTable extends JBTable { + private final static int SCOPE_COLUMN = 0; + private final static int SEVERITY_COLUMN = 1; + + public ScopesAndSeveritiesHintTable(final LinkedHashMap<String, HighlightSeverity> scopeToAverageSeverityMap) { + super(new MyModel(scopeToAverageSeverityMap)); + + final DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer(); + cellRenderer.setOpaque(false); + getColumnModel().getColumn(SCOPE_COLUMN).setCellRenderer(cellRenderer); + + getColumnModel().getColumn(SEVERITY_COLUMN).setCellRenderer(new DefaultTableCellRenderer() { + @Override + public Component getTableCellRendererComponent(final JTable table, + final Object value, + final boolean isSelected, + final boolean hasFocus, + final int row, + final int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + final HighlightSeverity severity = (HighlightSeverity)value; + setIcon(HighlightDisplayLevel.find(severity).getIcon()); + setText(SingleInspectionProfilePanel.renderSeverity(severity)); + setOpaque(false); + return this; + } + }); + setShowGrid(false); + setRowSelectionAllowed(false); + setColumnSelectionAllowed(false); + setOpaque(false); + } + + private final static class MyModel extends AbstractTableModel { + + private final LinkedHashMap<String, HighlightSeverity> myScopeToAverageSeverityMap; + private final List<String> myScopes; + + public MyModel(final LinkedHashMap<String, HighlightSeverity> scopeToAverageSeverityMap) { + myScopeToAverageSeverityMap = scopeToAverageSeverityMap; + myScopes = new ArrayList<String>(myScopeToAverageSeverityMap.keySet()); + } + + @Override + public Class<?> getColumnClass(final int columnIndex) { + switch (columnIndex) { + case SCOPE_COLUMN: return String.class; + case SEVERITY_COLUMN: return HighlightSeverity.class; + default: throw new IllegalArgumentException(); + } + } + + @Override + public int getRowCount() { + return myScopes.size(); + } + + @Override + public int getColumnCount() { + return 2; + } + + @Override + public Object getValueAt(final int rowIndex, final int columnIndex) { + switch (columnIndex) { + case SCOPE_COLUMN: return myScopes.get(rowIndex); + case SEVERITY_COLUMN: return myScopeToAverageSeverityMap.get(myScopes.get(rowIndex)); + default: throw new IllegalArgumentException(); + } + + } + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java new file mode 100644 index 000000000000..ad7dc946fff8 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java @@ -0,0 +1,404 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui.table; + +import com.intellij.codeHighlighting.HighlightDisplayLevel; +import com.intellij.codeInsight.daemon.HighlightDisplayKey; +import com.intellij.codeInspection.ex.InspectionProfileImpl; +import com.intellij.codeInspection.ex.ScopeToolState; +import com.intellij.icons.AllIcons; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Comparing; +import com.intellij.profile.codeInspection.ui.AddScopeUtil; +import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionConfigTreeNode; +import com.intellij.psi.search.scope.packageSet.NamedScope; +import com.intellij.ui.table.JBTable; +import com.intellij.ui.treeStructure.treetable.TreeTable; +import com.intellij.util.ArrayUtil; +import com.intellij.util.SmartList; +import com.intellij.util.ui.EditableModel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class ScopesAndSeveritiesTable extends JBTable { + private final static Logger LOG = Logger.getInstance(ScopesAndSeveritiesTable.class); + + public static final HighlightSeverity MIXED_FAKE_SEVERITY = new HighlightSeverity("Mixed", -1); + @SuppressWarnings("UnusedDeclaration") + public static final HighlightDisplayLevel MIXED_FAKE_LEVEL = new HighlightDisplayLevel(MIXED_FAKE_SEVERITY, AllIcons.Actions.Help); + + private final static int SCOPE_ENABLED_COLUMN = 0; + private final static int SCOPE_NAME_COLUMN = 1; + private final static int SEVERITY_COLUMN = 2; + + public ScopesAndSeveritiesTable(final TableSettings tableSettings) { + super(new MyTableModel(tableSettings)); + + final TableColumnModel columnModel = getColumnModel(); + + final TableColumn scopeEnabledColumn = columnModel.getColumn(SCOPE_ENABLED_COLUMN); + scopeEnabledColumn.setMaxWidth(30); + scopeEnabledColumn.setCellRenderer(new ThreeStateCheckBoxRenderer()); + scopeEnabledColumn.setCellEditor(new ThreeStateCheckBoxRenderer()); + + final TableColumn severityColumn = columnModel.getColumn(SEVERITY_COLUMN); + severityColumn.setCellRenderer(SeverityRenderer.create(tableSettings.getInspectionProfile())); + severityColumn.setCellEditor(SeverityRenderer.create(tableSettings.getInspectionProfile())); + + setColumnSelectionAllowed(false); + setRowSelectionAllowed(true); + setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(final ListSelectionEvent e) { + final int idx = getSelectionModel().getMinSelectionIndex(); + if (idx >= 0) { + final ExistedScopesStatesAndNonExistNames scopeToolState = ((MyTableModel)getModel()).getScopeToolState(idx); + final List<ScopeToolState> existedStates = scopeToolState.getExistedStates(); + if (existedStates.size() == 1) { + tableSettings.onScopeChosen(existedStates.get(0)); + } + } + } + }); + setRowSelectionInterval(0, 0); + + setStriped(true); + setShowGrid(false); + } + + public abstract static class TableSettings { + private final List<InspectionConfigTreeNode> myNodes; + private final List<String> myKeyNames; + private final List<HighlightDisplayKey> myKeys; + private final InspectionProfileImpl myInspectionProfile; + private final TreeTable myTreeTable; + private final Project myProject; + + protected TableSettings(final List<InspectionConfigTreeNode> nodes, + final InspectionProfileImpl inspectionProfile, + final TreeTable treeTable, + final Project project) { + myNodes = nodes; + myKeys = new ArrayList<HighlightDisplayKey>(myNodes.size()); + myKeyNames = new ArrayList<String>(myNodes.size()); + for(final InspectionConfigTreeNode node : nodes) { + final HighlightDisplayKey key = node.getDefaultDescriptor().getKey(); + myKeys.add(key); + myKeyNames.add(key.toString()); + } + + myInspectionProfile = inspectionProfile; + myTreeTable = treeTable; + myProject = project; + } + + public List<HighlightDisplayKey> getKeys() { + return myKeys; + } + + public List<String> getKeyNames() { + return myKeyNames; + } + + public List<InspectionConfigTreeNode> getNodes() { + return myNodes; + } + + public InspectionProfileImpl getInspectionProfile() { + return myInspectionProfile; + } + + public TreeTable getTreeTable() { + return myTreeTable; + } + + public Project getProject() { + return myProject; + } + + protected abstract void onScopeAdded(); + + protected abstract void onScopeRemoved(final int scopesCount); + + protected abstract void onScopeChosen(final @NotNull ScopeToolState scopeToolState); + + protected abstract void onChange(); + } + + @NotNull + public static HighlightSeverity getSeverity(final List<ScopeToolState> scopeToolStates) { + HighlightSeverity previousValue = null; + for (final ScopeToolState scopeToolState : scopeToolStates) { + final HighlightSeverity currentValue = scopeToolState.getLevel().getSeverity(); + if (previousValue == null) { + previousValue = currentValue; + } else if (!previousValue.equals(currentValue)){ + return MIXED_FAKE_SEVERITY; + } + } + return previousValue; + } + + private static class MyTableModel extends AbstractTableModel implements EditableModel { + private final InspectionProfileImpl myInspectionProfile; + private final List<String> myKeyNames; + private final List<InspectionConfigTreeNode> myNodes; + private final TreeTable myTreeTable; + private final Project myProject; + private final TableSettings myTableSettings; + private final List<HighlightDisplayKey> myKeys; + + private String[] myScopeNames; + + public MyTableModel(final TableSettings tableSettings) { + myTableSettings = tableSettings; + myProject = tableSettings.getProject(); + myInspectionProfile = tableSettings.getInspectionProfile(); + myKeys = tableSettings.getKeys(); + myKeyNames = tableSettings.getKeyNames(); + myNodes = tableSettings.getNodes(); + myTreeTable = tableSettings.getTreeTable(); + refreshAggregatedScopes(); + } + + @Override + public boolean isCellEditable(final int rowIndex, final int columnIndex) { + return columnIndex != SCOPE_NAME_COLUMN; + } + + @Override + public int getRowCount() { + return lastRowIndex() + 1; + } + + @Nullable + @Override + public String getColumnName(final int column) { + return null; + } + + @Override + public int getColumnCount() { + return 3; + } + + @Override + public Class<?> getColumnClass(final int columnIndex) { + if (SCOPE_ENABLED_COLUMN == columnIndex) { + return Boolean.class; + } + if (SCOPE_NAME_COLUMN == columnIndex) { + return String.class; + } + if (SEVERITY_COLUMN == columnIndex) { + return HighlightSeverity.class; + } + throw new IllegalArgumentException(); + } + + @Override + public Object getValueAt(final int rowIndex, final int columnIndex) { + if (rowIndex < 0) { + return null; + } + switch (columnIndex) { + case SCOPE_ENABLED_COLUMN: + return isEnabled(rowIndex); + case SCOPE_NAME_COLUMN: + return getScope(rowIndex).getName(); + case SEVERITY_COLUMN: + return getSeverity(rowIndex); + default: + throw new IllegalArgumentException("Invalid column index " + columnIndex); + } + } + + private NamedScope getScope(final int rowIndex) { + return getScopeToolState(rowIndex).getExistedStates().get(0).getScope(myProject); + } + + @NotNull + private HighlightSeverity getSeverity(final int rowIndex) { + final ExistedScopesStatesAndNonExistNames existedScopesStatesAndNonExistNames = getScopeToolState(rowIndex); + if (!existedScopesStatesAndNonExistNames.getNonExistNames().isEmpty()) { + return MIXED_FAKE_SEVERITY; + } + return ScopesAndSeveritiesTable.getSeverity(existedScopesStatesAndNonExistNames.getExistedStates()); + } + + @Nullable + private Boolean isEnabled(final int rowIndex) { + Boolean previousValue = null; + final ExistedScopesStatesAndNonExistNames existedScopesStatesAndNonExistNames = getScopeToolState(rowIndex); + for (final ScopeToolState scopeToolState : existedScopesStatesAndNonExistNames.getExistedStates()) { + final boolean currentValue = scopeToolState.isEnabled(); + if (previousValue == null) { + previousValue = currentValue; + } else if (!previousValue.equals(currentValue)){ + return null; + } + } + if (!existedScopesStatesAndNonExistNames.getNonExistNames().isEmpty() && !Boolean.FALSE.equals(previousValue)) { + return null; + } + return previousValue; + } + + private ExistedScopesStatesAndNonExistNames getScopeToolState(final int rowIndex) { + final List<String> nonExistNames = new SmartList<String>(); + final List<ScopeToolState> existedStates = new SmartList<ScopeToolState>(); + for (final String keyName : myKeyNames) { + final ScopeToolState scopeToolState = getScopeToolState(keyName, rowIndex); + if (scopeToolState != null) { + existedStates.add(scopeToolState); + } else { + nonExistNames.add(keyName); + } + } + return new ExistedScopesStatesAndNonExistNames(existedStates, nonExistNames); + } + + @Nullable + private ScopeToolState getScopeToolState(final String keyName, final int rowIndex) { + if (rowIndex == lastRowIndex()) { + return myInspectionProfile.getToolDefaultState(keyName, myProject); + } + else { + final String scopeName = myScopeNames[rowIndex]; + final List<ScopeToolState> nonDefaultTools = myInspectionProfile.getNonDefaultTools(keyName, myProject); + for (final ScopeToolState nonDefaultTool : nonDefaultTools) { + if (Comparing.equal(scopeName, nonDefaultTool.getScopeName())) { + return nonDefaultTool; + } + } + } + return null; + } + + private void refreshAggregatedScopes() { + final LinkedHashSet<String> scopesNames = new LinkedHashSet<String>(); + for (final String keyName : myKeyNames) { + final List<ScopeToolState> nonDefaultTools = myInspectionProfile.getNonDefaultTools(keyName, myProject); + for (final ScopeToolState tool : nonDefaultTools) { + scopesNames.add(tool.getScopeName()); + } + } + myScopeNames = ArrayUtil.toStringArray(scopesNames); + } + + private int lastRowIndex() { + return myScopeNames.length; + } + + @Override + public void setValueAt(final Object value, final int rowIndex, final int columnIndex) { + if (value == null) { + return; + } + if (columnIndex == SEVERITY_COLUMN) { + final HighlightDisplayLevel level = HighlightDisplayLevel.find(((HighlightSeverity)value).getName()); + if (level == null) { + LOG.error("no display level found for name " + ((HighlightSeverity)value).getName()); + return; + } + final int idx = rowIndex == lastRowIndex() ? -1 : rowIndex; + myInspectionProfile.setErrorLevel(myKeys, level, idx, myProject); + } + else if (columnIndex == SCOPE_ENABLED_COLUMN) { + final NamedScope scope = getScope(rowIndex); + if ((Boolean)value) { + if (rowIndex == lastRowIndex()) { + myInspectionProfile.enableToolsByDefault(myKeyNames, myProject); + } + else { + //TODO create scopes states if not exist (need scope sorting) + myInspectionProfile.enableTools(myKeyNames, scope, myProject); + } + } + else { + if (rowIndex == lastRowIndex()) { + myInspectionProfile.disableToolByDefault(myKeyNames, myProject); + } + else { + myInspectionProfile.disableTools(myKeyNames, scope, myProject); + } + } + } + myTableSettings.onChange(); + } + + @Override + public void removeRow(final int idx) { + if (idx != lastRowIndex()) { + myInspectionProfile.removeScopes(myKeyNames, getScope(idx), myProject); + refreshAggregatedScopes(); + myTableSettings.onScopeRemoved(getRowCount()); + } + } + + @Override + public void addRow() { + AddScopeUtil.performAddScope(myTreeTable, myProject, myInspectionProfile, myNodes); + myTableSettings.onScopeAdded(); + refreshAggregatedScopes(); + } + + @Override + public void exchangeRows(final int oldIndex, final int newIndex) { + } + + @Override + public boolean canExchangeRows(final int oldIndex, final int newIndex) { + return false; + } + } + + private static class ExistedScopesStatesAndNonExistNames { + + private final List<ScopeToolState> myExistedStates; + private final List<String> myNonExistNames; + + public ExistedScopesStatesAndNonExistNames(final List<ScopeToolState> existedStates, final List<String> nonExistNames) { + myExistedStates = existedStates; + myNonExistNames = nonExistNames; + } + + public List<ScopeToolState> getExistedStates() { + return myExistedStates; + } + + public List<String> getNonExistNames() { + return myNonExistNames; + } + } +}
\ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java new file mode 100644 index 000000000000..2fe95e6d7224 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui.table; + +import com.intellij.codeHighlighting.HighlightDisplayLevel; +import com.intellij.codeInspection.ex.InspectionProfileImpl; +import com.intellij.lang.annotation.HighlightSeverity; +import com.intellij.openapi.ui.ComboBoxTableRenderer; +import com.intellij.profile.codeInspection.SeverityProvider; +import com.intellij.profile.codeInspection.ui.LevelChooserAction; +import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.event.MouseEvent; +import java.util.EventObject; +import java.util.SortedSet; + +/** + * @author Dmitry Batkovich + */ +public class SeverityRenderer extends ComboBoxTableRenderer<HighlightSeverity> { + public SeverityRenderer(final HighlightSeverity[] values) { + super(values); + } + + public static SeverityRenderer create(final InspectionProfileImpl inspectionProfile) { + final SortedSet<HighlightSeverity> severities = + LevelChooserAction.getSeverities(((SeverityProvider)inspectionProfile.getProfileManager()).getOwnSeverityRegistrar()); + return new SeverityRenderer(severities.toArray(new HighlightSeverity[severities.size()])); + } + + + @Override + protected String getTextFor(@NotNull final HighlightSeverity value) { + return SingleInspectionProfilePanel.renderSeverity(value); + } + + @Override + protected Icon getIconFor(@NotNull final HighlightSeverity value) { + return HighlightDisplayLevel.find(value).getIcon(); + } + + @Override + public boolean isCellEditable(final EventObject event) { + if (event instanceof MouseEvent) { + return ((MouseEvent)event).getClickCount() >= 1; + } + return true; + } +} diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ThreeStateCheckBoxRenderer.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ThreeStateCheckBoxRenderer.java new file mode 100644 index 000000000000..7d8cfdfc9db5 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ThreeStateCheckBoxRenderer.java @@ -0,0 +1,127 @@ +/* + * Copyright 2000-2014 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.profile.codeInspection.ui.table; + +import com.intellij.ui.ClickListener; +import com.intellij.util.SmartList; +import com.intellij.util.ui.ThreeStateCheckBox; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import java.awt.*; +import java.awt.event.MouseEvent; +import java.util.EventObject; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class ThreeStateCheckBoxRenderer extends ThreeStateCheckBox implements TableCellRenderer, TableCellEditor { + + private final List<CellEditorListener> myListeners = new SmartList<CellEditorListener>(); + + public ThreeStateCheckBoxRenderer() { + setThirdStateEnabled(false); + setHorizontalAlignment(CENTER); + setVerticalAlignment(CENTER); + } + + @Override + public Component getTableCellEditorComponent(final JTable table, final Object value, final boolean isSelected, final int row, final int column) { + return tune(value, isSelected, row, table); + } + + @Override + public Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) { + return tune(value, isSelected, row, table); + } + + private JCheckBox tune(final Object value, final boolean isSelected, final int row, final JTable table) { + final Color bg = UIUtil.isUnderNimbusLookAndFeel() && row % 2 == 1 ? UIUtil.TRANSPARENT_COLOR : table.getBackground(); + final Color fg = table.getForeground(); + final Color selBg = table.getSelectionBackground(); + final Color selFg = table.getSelectionForeground(); + + setForeground(isSelected ? selFg : fg); + setBackground(isSelected ? selBg : bg); + + if (value == null) { + setState(State.DONT_CARE); + } else { + setSelected((Boolean) value); + } + new ClickListener() { + @Override + public boolean onClick(@NotNull final MouseEvent event, final int clickCount) { + if (clickCount == 1) { + stopCellEditing(); + return true; + } + return false; + } + }.installOn(this); + return this; + } + + @Nullable + @Override + public Object getCellEditorValue() { + return getState() != State.DONT_CARE ? isSelected() : null; + } + + @Override + public boolean isCellEditable(final EventObject anEvent) { + return true; + } + + @Override + public boolean shouldSelectCell(final EventObject anEvent) { + return true; + } + + @Override + public boolean stopCellEditing() { + final ChangeEvent e = new ChangeEvent(this); + for (final CellEditorListener listener : myListeners) { + listener.editingStopped(e); + } + return true; + } + + @Override + public void cancelCellEditing() { + final ChangeEvent e = new ChangeEvent(this); + for (final CellEditorListener listener : myListeners) { + listener.editingCanceled(e); + } + } + + @Override + public void addCellEditorListener(final CellEditorListener l) { + myListeners.add(l); + } + + @Override + public void removeCellEditorListener(final CellEditorListener l) { + myListeners.remove(l); + } +} |