summaryrefslogtreecommitdiff
path: root/platform/lang-impl/src
diff options
context:
space:
mode:
Diffstat (limited to 'platform/lang-impl/src')
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/CodeCompletionPanel.java22
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java6
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/CodeStyleSettingsUtilImpl.java4
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/ModuleAwareProjectConfigurable.java4
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java142
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java2
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/editor/EditorSmartKeysConfigurable.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java5
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/actions/MultiCaretCodeInsightAction.java153
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/actions/MultiCaretCodeInsightActionHandler.java39
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java5
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java7
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java5
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/completion/FilePathCompletionContributor.java68
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java3
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/EncodingReferenceInjector.java46
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java25
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java7
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java2
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java127
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java30
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/editorActions/fillParagraph/ParagraphFillHandler.java2
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java95
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java623
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/actions/CommentByBlockCommentAction.java13
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/generation/actions/CommentByLineCommentAction.java13
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupOffsets.java88
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java9
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/settings/PostfixDescriptionPanel.java1
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/settings/PostfixTemplatesConfigurable.form2
-rw-r--r--platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java2
-rw-r--r--platform/lang-impl/src/com/intellij/codeInspection/ex/Descriptor.java15
-rw-r--r--platform/lang-impl/src/com/intellij/codeInspection/ex/SeverityEditorDialog.java3
-rw-r--r--platform/lang-impl/src/com/intellij/codeInspection/ex/VisibleTreeState.java4
-rw-r--r--platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java2
-rw-r--r--platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java2
-rw-r--r--platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleViewImpl.java2
-rw-r--r--platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java34
-rw-r--r--platform/lang-impl/src/com/intellij/find/FindUtil.java102
-rw-r--r--platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java46
-rw-r--r--platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java21
-rw-r--r--platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java17
-rw-r--r--platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java17
-rw-r--r--platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java49
-rw-r--r--platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java5
-rw-r--r--platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java53
-rw-r--r--platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java11
-rw-r--r--platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java47
-rw-r--r--platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java19
-rw-r--r--platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java147
-rw-r--r--platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java90
-rw-r--r--platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java23
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java28
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java46
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedSymbolAction.java37
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java237
-rw-r--r--platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java6
-rw-r--r--platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkExcludeRootAction.java13
-rw-r--r--platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java74
-rw-r--r--platform/lang-impl/src/com/intellij/ide/projectView/actions/UnmarkRootAction.java24
-rw-r--r--platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java29
-rw-r--r--platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java13
-rw-r--r--platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java2
-rw-r--r--platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java169
-rw-r--r--platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java285
-rw-r--r--platform/lang-impl/src/com/intellij/injected/editor/InjectedCaret.java17
-rw-r--r--platform/lang-impl/src/com/intellij/internal/DumpDirectoryInfoAction.java7
-rw-r--r--platform/lang-impl/src/com/intellij/internal/DumpVfsInfoForExcludedFilesAction.java114
-rw-r--r--platform/lang-impl/src/com/intellij/lang/LanguagePerFileMappings.java281
-rw-r--r--platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java25
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewProvider.java2
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java53
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java30
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java47
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectPreviousOccurrenceAction.java10
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java27
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java (renamed from platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java)33
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java4
-rw-r--r--platform/lang-impl/src/com/intellij/packageDependencies/ui/ProjectPatternProvider.java8
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/AddScopeUtil.java117
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionToolsConfigurable.java2
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionsAggregationUtil.java74
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooser.java6
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooserAction.java33
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/MultiScopeSeverityIcon.java58
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ScopesChooser.java98
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java542
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/ToolDescriptors.java70
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/AddScopeAction.java164
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/DeleteScopeAction.java90
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/actions/MoveScopeAction.java81
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionFilterAction.java129
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/filter/InspectionsFilter.java102
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionConfigTreeNode.java (renamed from platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionConfigTreeNode.java)66
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeComparator.java (renamed from platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionsConfigTreeComparator.java)14
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeRenderer.java (renamed from platform/lang-impl/src/com/intellij/profile/codeInspection/ui/InspectionsConfigTreeRenderer.java)50
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java257
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/MultiScopeSeverityIcon.java74
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/ScopesAndSeveritiesHintTable.java106
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java404
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/SeverityRenderer.java64
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ThreeStateCheckBoxRenderer.java127
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/file/DirectoryIconProvider.java13
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java2
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java2
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java16
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java5
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java6
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java17
-rw-r--r--platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java25
-rw-r--r--platform/lang-impl/src/com/intellij/refactoring/actions/RefactoringQuickListPopupAction.java5
-rw-r--r--platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java20
-rw-r--r--platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java19
-rw-r--r--platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java5
-rw-r--r--platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java23
-rw-r--r--platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceOnErrorAction.java26
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/ContentHashesSupport.java11
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/DebugAssertions.java14
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java55
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java2
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java153
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java5
123 files changed, 4630 insertions, 2414 deletions
diff --git a/platform/lang-impl/src/com/intellij/application/options/CodeCompletionPanel.java b/platform/lang-impl/src/com/intellij/application/options/CodeCompletionPanel.java
index 8e8eba54cbf9..6c65209d1122 100644
--- a/platform/lang-impl/src/com/intellij/application/options/CodeCompletionPanel.java
+++ b/platform/lang-impl/src/com/intellij/application/options/CodeCompletionPanel.java
@@ -28,8 +28,10 @@ import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.ui.components.JBCheckBox;
import org.intellij.lang.annotations.MagicConstant;
+import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.event.ActionEvent;
@@ -56,7 +58,7 @@ public class CodeCompletionPanel {
private static final String CASE_SENSITIVE_FIRST_LETTER = ApplicationBundle.message("combobox.autocomplete.case.sensitive.first.letter");
private static final String[] CASE_VARIANTS = {CASE_SENSITIVE_ALL, CASE_SENSITIVE_NONE, CASE_SENSITIVE_FIRST_LETTER};
- public CodeCompletionPanel(){
+ public CodeCompletionPanel() {
//noinspection unchecked
myCaseSensitiveCombo.setModel(new DefaultComboBoxModel(CASE_VARIANTS));
@@ -73,7 +75,7 @@ public class CodeCompletionPanel {
myCbAutocompletion.addActionListener(
new ActionListener() {
@Override
- public void actionPerformed(ActionEvent event) {
+ public void actionPerformed(@NotNull ActionEvent event) {
boolean selected = myCbAutocompletion.isSelected();
myCbSelectByChars.setEnabled(selected);
}
@@ -83,7 +85,7 @@ public class CodeCompletionPanel {
myCbAutopopupJavaDoc.addActionListener(
new ActionListener() {
@Override
- public void actionPerformed(ActionEvent event) {
+ public void actionPerformed(@NotNull ActionEvent event) {
myAutopopupJavaDocField.setEnabled(myCbAutopopupJavaDoc.isSelected());
}
}
@@ -92,7 +94,7 @@ public class CodeCompletionPanel {
myCbParameterInfoPopup.addActionListener(
new ActionListener() {
@Override
- public void actionPerformed(ActionEvent event) {
+ public void actionPerformed(@NotNull ActionEvent event) {
myParameterInfoDelayField.setEnabled(myCbParameterInfoPopup.isSelected());
}
}
@@ -205,16 +207,8 @@ public class CodeCompletionPanel {
}
private static int getIntegerValue(String s, int defaultValue) {
- int value = defaultValue;
- try {
- value = Integer.parseInt(s);
- if(value < 0) {
- return defaultValue;
- }
- }
- catch (NumberFormatException ignored) {
- }
- return value;
+ int value = StringUtilRt.parseInt(s, defaultValue);
+ return value < 0 ? defaultValue : value;
}
@MagicConstant(intValues = {CodeInsightSettings.ALL, CodeInsightSettings.NONE, CodeInsightSettings.FIRST_LETTER})
diff --git a/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java b/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java
index f7c1fd4c7e2d..2b142a4bffb2 100644
--- a/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java
+++ b/platform/lang-impl/src/com/intellij/application/options/CodeStyleAbstractPanel.java
@@ -201,7 +201,7 @@ public abstract class CodeStyleAbstractPanel implements Disposable {
private int getAdjustedRightMargin() {
int result = getRightMargin();
- return result > 0 ? result : CodeStyleFacade.getInstance(ProjectUtil.guessCurrentProject(getPanel())).getRightMargin();
+ return result > 0 ? result : CodeStyleFacade.getInstance(ProjectUtil.guessCurrentProject(getPanel())).getRightMargin(getDefaultLanguage());
}
protected abstract int getRightMargin();
@@ -226,7 +226,7 @@ public abstract class CodeStyleAbstractPanel implements Disposable {
catch (ConfigurationException ignore) {
}
CodeStyleSettings clone = mySettings.clone();
- clone.RIGHT_MARGIN = getAdjustedRightMargin();
+ clone.setRightMargin(getDefaultLanguage(), getAdjustedRightMargin());
CodeStyleSettingsManager.getInstance(project).setTemporarySettings(clone);
PsiFile formatted;
try {
@@ -267,7 +267,7 @@ public abstract class CodeStyleAbstractPanel implements Disposable {
Document document = documentManager.getDocument(psiFile);
if (document != null) {
CodeStyleSettings clone = mySettings.clone();
- clone.RIGHT_MARGIN = getAdjustedRightMargin();
+ clone.setRightMargin(getDefaultLanguage(), getAdjustedRightMargin());
CodeStyleSettingsManager.getInstance(project).setTemporarySettings(clone);
try {
CodeStyleManager.getInstance(project).reformat(psiFile);
diff --git a/platform/lang-impl/src/com/intellij/application/options/CodeStyleSettingsUtilImpl.java b/platform/lang-impl/src/com/intellij/application/options/CodeStyleSettingsUtilImpl.java
index 640fcac38652..418cc3ccef6d 100644
--- a/platform/lang-impl/src/com/intellij/application/options/CodeStyleSettingsUtilImpl.java
+++ b/platform/lang-impl/src/com/intellij/application/options/CodeStyleSettingsUtilImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * 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.
@@ -23,7 +23,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
public class CodeStyleSettingsUtilImpl extends CodeStyleSettingsUtil {
/**
- * Shows code style settings sutable for the project passed. I.e. it shows project code style page if one
+ * Shows code style settings suitable for the project passed. I.e. it shows project code style page if one
* is configured to use own code style scheme or global one in other case.
* @param project
* @return Returns true if settings were modified during editing session.
diff --git a/platform/lang-impl/src/com/intellij/application/options/ModuleAwareProjectConfigurable.java b/platform/lang-impl/src/com/intellij/application/options/ModuleAwareProjectConfigurable.java
index f7d8ab8e7df1..b005b5e158fd 100644
--- a/platform/lang-impl/src/com/intellij/application/options/ModuleAwareProjectConfigurable.java
+++ b/platform/lang-impl/src/com/intellij/application/options/ModuleAwareProjectConfigurable.java
@@ -35,7 +35,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
@@ -116,8 +115,7 @@ public abstract class ModuleAwareProjectConfigurable<T extends UnnamedConfigurab
for (Module module : modules) {
final T configurable = createModuleConfigurable(module);
myModuleConfigurables.put(module, configurable);
- final JComponent component = new JBScrollPane(configurable.createComponent());
- component.setBorder(new EmptyBorder(0, 0, 0, 0));
+ final JComponent component = configurable.createComponent();
cardPanel.add(component, module.getName());
}
moduleList.addListSelectionListener(new ListSelectionListener() {
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java
index 099830e15902..f978d5f6dcdb 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/OptionTableWithPreviewPanel.java
@@ -340,6 +340,16 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
addOption(fieldName, title, null, options, values);
}
+ protected void addOption(@NotNull String fieldName,
+ @NotNull String title,
+ @Nullable String groupName,
+ int minValue,
+ int maxValue,
+ int defaultValue,
+ String defaultValueText) {
+ myOptions.add(new IntOption(null, fieldName, title, groupName, null, null, minValue, maxValue, defaultValue, defaultValueText));
+ }
+
protected void addOption(@NotNull String fieldName, @NotNull String title, @Nullable String groupName) {
myOptions.add(new BooleanOption(null, fieldName, title, groupName, null, null));
}
@@ -469,6 +479,78 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
}
}
+ private class IntOption extends Option {
+
+ private final int myMinValue;
+ private final int myMaxValue;
+ private final int myDefaultValue;
+ @Nullable private String myDefaultValueText;
+
+ public IntOption(Class<? extends CustomCodeStyleSettings> clazz,
+ @NotNull String fieldName,
+ @NotNull String title,
+ @Nullable String groupName,
+ @Nullable OptionAnchor anchor,
+ @Nullable String anchorFiledName,
+ int minValue,
+ int maxValue,
+ int defaultValue,
+ @Nullable String defaultValueText) {
+ super(clazz, fieldName, title, groupName, anchor, anchorFiledName);
+ myMinValue = minValue;
+ myMaxValue = maxValue;
+ myDefaultValue = defaultValue;
+ myDefaultValueText = defaultValueText;
+ }
+
+ @Override
+ public Object getValue(CodeStyleSettings settings) {
+ try {
+ int value = field.getInt(getSettings(settings));
+ return value == myDefaultValue && myDefaultValueText != null ? myDefaultValueText : value;
+ }
+ catch (IllegalAccessException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public void setValue(Object value, CodeStyleSettings settings) {
+ //noinspection EmptyCatchBlock
+ try {
+ if (myDefaultValueText != null && !myDefaultValueText.equals(value)) {
+ field.setInt(getSettings(settings), ((Integer)value).intValue());
+ }
+ else {
+ field.setInt(getSettings(settings), -1);
+ }
+ }
+ catch (IllegalAccessException e) {
+ }
+ }
+
+ public int getMinValue() {
+ return myMinValue;
+ }
+
+ public int getMaxValue() {
+ return myMaxValue;
+ }
+
+ public int getDefaultValue() {
+ return myDefaultValue;
+ }
+
+ public boolean isDefaultText(Object value) {
+ return myDefaultValueText != null && myDefaultValueText.equals(value);
+ }
+
+ @Nullable
+ public String getDefaultValueText() {
+ return myDefaultValueText;
+ }
+ }
+
@SuppressWarnings({"HardCodedStringLiteral"})
public final ColumnInfo TITLE = new ColumnInfo("TITLE") {
@Override
@@ -604,6 +686,7 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
private final JLabel myComboBox = new JLabel();
private final JCheckBox myCheckBox = new JCheckBox();
private final JPanel myEmptyLabel = new JPanel();
+ private final JLabel myIntLabel = new JLabel();
@Override
public Component getTableCellRendererComponent(JTable table,
@@ -636,6 +719,10 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
myComboBox.setEnabled(isEnabled);
return myComboBox;
}
+ else if (value instanceof Integer) {
+ myIntLabel.setText(value.toString());
+ return myIntLabel;
+ }
myCheckBox.putClientProperty("JComponent.sizeVariant", "small");
myComboBox.putClientProperty("JComponent.sizeVariant", "small");
@@ -645,12 +732,55 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
}
}
+ private static class MyIntOptionEditor extends JTextField {
+ private int myMinValue;
+ private int myMaxValue;
+ private int myDefaultValue;
+ private String myDefaultValueText;
+
+ private MyIntOptionEditor() {
+ super();
+ }
+
+ public Object getPresentableValue() {
+ int value = validateAndGetIntOption();
+ return value == myDefaultValue && myDefaultValueText != null ? myDefaultValueText : value;
+ }
+
+ private int validateAndGetIntOption() {
+ try {
+ int value = Integer.parseInt(getText());
+ return value >= myMinValue && value <= myMaxValue ? value : myDefaultValue;
+ }
+ catch (NumberFormatException nfe) {
+ return myDefaultValue;
+ }
+ }
+
+ public void setMinValue(int minValue) {
+ myMinValue = minValue;
+ }
+
+ public void setMaxValue(int maxValue) {
+ myMaxValue = maxValue;
+ }
+
+ public void setDefaultValue(int defaultValue) {
+ myDefaultValue = defaultValue;
+ }
+
+ public void setDefaultValueText(String defaultValueText) {
+ myDefaultValueText = defaultValueText;
+ }
+ }
+
/**
* @author Konstantin Bulenkov
*/
private class MyValueEditor extends AbstractTableCellEditor {
private final JCheckBox myBooleanEditor = new JCheckBox();
private JBComboBoxTableCellEditorComponent myOptionsEditor = new JBComboBoxTableCellEditorComponent();
+ private MyIntOptionEditor myIntOptionsEditor = new MyIntOptionEditor();
private Component myCurrentEditor = null;
private MyTreeNode myCurrentNode = null;
@@ -684,6 +814,9 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
else if (myCurrentEditor == myBooleanEditor) {
return myBooleanEditor.isSelected() ? Boolean.TRUE : Boolean.FALSE;
}
+ else if (myCurrentEditor == myIntOptionsEditor) {
+ return myIntOptionsEditor.getPresentableValue();
+ }
return null;
}
@@ -702,6 +835,15 @@ public abstract class OptionTableWithPreviewPanel extends MultilanguageCodeStyle
myBooleanEditor.setSelected(node.getValue() == Boolean.TRUE);
myBooleanEditor.setEnabled(node.isEnabled());
}
+ else if (node.getKey() instanceof IntOption) {
+ IntOption intOption = (IntOption)node.getKey();
+ myCurrentEditor = myIntOptionsEditor;
+ myIntOptionsEditor.setText(intOption.isDefaultText(node.getValue()) ? "" : node.getValue().toString());
+ myIntOptionsEditor.setMinValue(intOption.getMinValue());
+ myIntOptionsEditor.setMaxValue(intOption.getMaxValue());
+ myIntOptionsEditor.setDefaultValue(intOption.getDefaultValue());
+ myIntOptionsEditor.setDefaultValueText(intOption.getDefaultValueText());
+ }
else {
myCurrentEditor = myOptionsEditor;
myOptionsEditor.setCell(table, row, column);
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java
index 1b270874101e..c192d0e2893a 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java
@@ -32,6 +32,8 @@ public class WrappingAndBracesPanel extends OptionTableWithPreviewPanel {
@Override
protected void initTables() {
+ addOption("RIGHT_MARGIN", ApplicationBundle.message("editbox.right.margin.columns"), null, 0, 999, -1, ApplicationBundle.message("settings.code.style.default.general"));
+
addOption("KEEP_LINE_BREAKS", ApplicationBundle.message("wrapping.keep.line.breaks"), WRAPPING_KEEP);
addOption("KEEP_FIRST_COLUMN_COMMENT", ApplicationBundle.message("wrapping.keep.comment.at.first.column"), WRAPPING_KEEP);
addOption("KEEP_CONTROL_STATEMENT_IN_ONE_LINE", ApplicationBundle.message("checkbox.keep.when.reformatting.control.statement.in.one.line"), WRAPPING_KEEP);
diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorSmartKeysConfigurable.java b/platform/lang-impl/src/com/intellij/application/options/editor/EditorSmartKeysConfigurable.java
index 2cabcabf74ad..a5551086daaf 100644
--- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorSmartKeysConfigurable.java
+++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorSmartKeysConfigurable.java
@@ -161,7 +161,7 @@ public class EditorSmartKeysConfigurable extends CompositeConfigurable<UnnamedCo
myCbSurroundSelectionOnTyping.setSelected(codeInsightSettings.SURROUND_SELECTION_ON_QUOTE_TYPED);
- myCbIndentingBackspace.setSelected(codeInsightSettings.INDENTING_BACKSPACE);
+ myCbIndentingBackspace.setSelected(codeInsightSettings.SMART_BACKSPACE == CodeInsightSettings.AUTOINDENT);
super.reset();
}
@@ -182,7 +182,7 @@ public class EditorSmartKeysConfigurable extends CompositeConfigurable<UnnamedCo
codeInsightSettings.SURROUND_SELECTION_ON_QUOTE_TYPED = myCbSurroundSelectionOnTyping.isSelected();
editorSettings.setCamelWords(myCbCamelWords.isSelected());
codeInsightSettings.REFORMAT_ON_PASTE = getReformatPastedBlockValue();
- codeInsightSettings.INDENTING_BACKSPACE = myCbIndentingBackspace.isSelected();
+ codeInsightSettings.SMART_BACKSPACE = myCbIndentingBackspace.isSelected() ? CodeInsightSettings.AUTOINDENT : CodeInsightSettings.OFF;
super.apply();
}
@@ -208,7 +208,7 @@ public class EditorSmartKeysConfigurable extends CompositeConfigurable<UnnamedCo
isModified |= isModified(myCbSurroundSelectionOnTyping, codeInsightSettings.SURROUND_SELECTION_ON_QUOTE_TYPED);
- isModified |= isModified(myCbIndentingBackspace, codeInsightSettings.INDENTING_BACKSPACE);
+ isModified |= isModified(myCbIndentingBackspace, codeInsightSettings.SMART_BACKSPACE == CodeInsightSettings.AUTOINDENT);
return isModified;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java b/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java
index 013b0808faca..942cbfa17f1e 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/CodeInsightSettings.java
@@ -100,7 +100,10 @@ public class CodeInsightSettings implements PersistentStateComponent<Element>, C
public boolean SHOW_FULL_SIGNATURES_IN_PARAMETER_INFO = false;
- public boolean INDENTING_BACKSPACE = true;
+ @MagicConstant(intValues = {OFF, AUTOINDENT})
+ public int SMART_BACKSPACE = AUTOINDENT;
+ public static final int OFF = 0;
+ public static final int AUTOINDENT = 1;
public boolean SMART_INDENT_ON_ENTER = true;
public boolean INSERT_BRACE_ON_ENTER = true;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/MultiCaretCodeInsightAction.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/MultiCaretCodeInsightAction.java
new file mode 100644
index 000000000000..568e17b58bd6
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/MultiCaretCodeInsightAction.java
@@ -0,0 +1,153 @@
+/*
+ * 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.codeInsight.actions;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.editor.Caret;
+import com.intellij.openapi.editor.CaretAction;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.ScrollType;
+import com.intellij.openapi.editor.actionSystem.DocCommandGroupId;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
+import com.intellij.psi.util.PsiUtilBase;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Base class for PSI-aware editor actions that need to support multiple carets.
+ * Recognizes multi-root PSI and injected fragments, so different carets might be processed in context of different
+ * {@link com.intellij.openapi.editor.Editor} and {@link com.intellij.psi.PsiFile} instances.
+ * <p>
+ * Implementations should implement {@link #getHandler()} method, and might override {@link
+ * #isValidFor(com.intellij.openapi.project.Project, com.intellij.openapi.editor.Editor, com.intellij.openapi.editor.Caret, com.intellij.psi.PsiFile)} method.
+ *
+ * @see com.intellij.codeInsight.actions.MultiCaretCodeInsightActionHandler
+ */
+public abstract class MultiCaretCodeInsightAction extends AnAction {
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ final Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ final Editor hostEditor = CommonDataKeys.EDITOR.getData(e.getDataContext());
+ if (hostEditor == null) {
+ return;
+ }
+
+ actionPerformedImpl(project, hostEditor);
+ }
+
+ public void actionPerformedImpl(final Project project, final Editor hostEditor) {
+ CommandProcessor.getInstance().executeCommand(project, new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ MultiCaretCodeInsightActionHandler handler = getHandler();
+ try {
+ iterateOverCarets(project, hostEditor, handler);
+ }
+ finally {
+ handler.postInvoke();
+ }
+ }
+ });
+ }
+ }, getCommandName(), DocCommandGroupId.noneGroupId(hostEditor.getDocument()));
+
+ hostEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ final Presentation presentation = e.getPresentation();
+
+ Project project = e.getProject();
+ if (project == null) {
+ presentation.setEnabled(false);
+ return;
+ }
+
+ Editor hostEditor = CommonDataKeys.EDITOR.getData(e.getDataContext());
+ if (hostEditor == null) {
+ presentation.setEnabled(false);
+ return;
+ }
+
+ final Ref<Boolean> enabled = new Ref<Boolean>(Boolean.FALSE);
+ iterateOverCarets(project, hostEditor, new MultiCaretCodeInsightActionHandler() {
+ @Override
+ public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull Caret caret, @NotNull PsiFile file) {
+ if (isValidFor(project, editor, caret, file)) {
+ enabled.set(Boolean.TRUE);
+ }
+ }
+ });
+ presentation.setEnabled(enabled.get());
+ }
+
+ private static void iterateOverCarets(@NotNull final Project project,
+ @NotNull final Editor hostEditor,
+ @NotNull final MultiCaretCodeInsightActionHandler handler) {
+ PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
+ final PsiFile psiFile = documentManager.getCachedPsiFile(hostEditor.getDocument());
+ documentManager.commitAllDocuments();
+
+ hostEditor.getCaretModel().runForEachCaret(new CaretAction() {
+ @Override
+ public void perform(Caret caret) {
+ Editor editor = hostEditor;
+ if (psiFile != null) {
+ Caret injectedCaret = InjectedLanguageUtil.getCaretForInjectedLanguageNoCommit(caret, psiFile);
+ if (injectedCaret != null) {
+ caret = injectedCaret;
+ editor = caret.getEditor();
+ }
+ }
+ final PsiFile file = PsiUtilBase.getPsiFileInEditor(caret, project);
+ if (file != null) {
+ handler.invoke(project, editor, caret, file);
+ }
+ }
+ }, true);
+ }
+
+ /**
+ * During action status update this method is invoked for each caret in editor. If at least for a single caret it returns
+ * <code>true</code>, action is considered enabled.
+ */
+ protected boolean isValidFor(@NotNull Project project, @NotNull Editor editor, @NotNull Caret caret, @NotNull PsiFile file) {
+ return true;
+ }
+
+ @NotNull
+ protected abstract MultiCaretCodeInsightActionHandler getHandler();
+
+ protected String getCommandName() {
+ String text = getTemplatePresentation().getText();
+ return text == null ? "" : text;
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/MultiCaretCodeInsightActionHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/MultiCaretCodeInsightActionHandler.java
new file mode 100644
index 000000000000..bfe7e325b8eb
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/MultiCaretCodeInsightActionHandler.java
@@ -0,0 +1,39 @@
+/*
+ * 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.codeInsight.actions;
+
+import com.intellij.openapi.editor.Caret;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Delegate class that performs actual work for {@link com.intellij.codeInsight.actions.MultiCaretCodeInsightAction}
+ */
+public abstract class MultiCaretCodeInsightActionHandler {
+ /**
+ * Invoked for each caret in editor (in bottom-to-top order). <code>project</code> value is the same for all carets, <code>editor</code>
+ * and <code>file</code> values can be different in presence of multi-root PSI and injected fragments. For injected fragments
+ * caret instance will belong to corresponding injected editor.
+ */
+ public abstract void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull Caret caret, @NotNull PsiFile file);
+
+ /**
+ * Invoked after processing all carets.
+ */
+ public void postInvoke() {}
+} \ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java
index 50942cb06c6b..4966a9466a26 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeAction.java
@@ -174,7 +174,8 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
}
final TextRange range;
- if (!processWholeFile && editor != null && editor.getSelectionModel().hasSelection()){
+ final boolean processSelectedText = !processWholeFile && hasSelection;
+ if (processSelectedText) {
range = TextRange.create(editor.getSelectionModel().getSelectionStart(), editor.getSelectionModel().getSelectionEnd());
}
else{
@@ -185,7 +186,7 @@ public class ReformatCodeAction extends AnAction implements DumbAware {
new OptimizeImportsProcessor(new ReformatCodeProcessor(project, file, null, processChangedTextOnly)).run();
}
else {
- new ReformatCodeProcessor(project, file, range, processChangedTextOnly).run();
+ new ReformatCodeProcessor(project, file, range, !processSelectedText && processChangedTextOnly).run();
}
if (rearrangeEntries && file != null && editor != null) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
index e039cec3a424..e0a3be5f423d 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
@@ -772,11 +772,8 @@ public class CodeCompletionHandlerBase {
if (context.getCompletionChar() == Lookup.COMPLETE_STATEMENT_SELECT_CHAR) {
final Language language = PsiUtilBase.getLanguageInEditor(editor, project);
if (language != null) {
- final List<SmartEnterProcessor> processors = SmartEnterProcessors.INSTANCE.forKey(language);
- if (processors.size() > 0) {
- for (SmartEnterProcessor processor : processors) {
- processor.process(project, editor, indicator.getParameters().getOriginalFile());
- }
+ for (SmartEnterProcessor processor : SmartEnterProcessors.INSTANCE.forKey(language)) {
+ if (processor.processAfterCompletion(editor, indicator.getParameters().getOriginalFile())) break;
}
}
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java
index 0143e55a4e98..e25f050c8d7b 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java
@@ -17,6 +17,7 @@
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.CodeInsightSettings;
+import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl;
import com.intellij.codeInsight.completion.impl.CompletionSorterImpl;
import com.intellij.codeInsight.editorActions.CompletionAutoPopupHandler;
@@ -216,7 +217,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
if (!initContext.getOffsetMap().wasModified(CompletionInitializationContext.IDENTIFIER_END_OFFSET)) {
try {
final int selectionEndOffset = initContext.getSelectionEndOffset();
- final PsiReference reference = initContext.getFile().findReferenceAt(selectionEndOffset);
+ final PsiReference reference = TargetElementUtilBase.findReference(myEditor, selectionEndOffset);
if (reference != null) {
initContext.setReplacementOffset(findReplacementOffset(selectionEndOffset, reference));
}
@@ -252,7 +253,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
}
}
- return reference.getElement().getTextRange().getStartOffset() + reference.getRangeInElement().getEndOffset();
+ return selectionEndOffset;
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/FilePathCompletionContributor.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/FilePathCompletionContributor.java
index f23a7a6f6cca..4a34e9460718 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/completion/FilePathCompletionContributor.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/FilePathCompletionContributor.java
@@ -48,6 +48,7 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ProcessingContext;
+import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -71,9 +72,7 @@ public class FilePathCompletionContributor extends CompletionContributor {
final PsiReference psiReference = parameters.getPosition().getContainingFile().findReferenceAt(parameters.getOffset());
if (getReference(psiReference) != null && parameters.getInvocationCount() == 1) {
final String shortcut = getActionShortcut(IdeActions.ACTION_CODE_COMPLETION);
- if (shortcut != null) {
- result.addLookupAdvertisement(CodeInsightBundle.message("class.completion.file.path", shortcut));
- }
+ result.addLookupAdvertisement(CodeInsightBundle.message("class.completion.file.path", shortcut));
}
}
});
@@ -134,24 +133,30 @@ public class FilePathCompletionContributor extends CompletionContributor {
final PsiFile[] files = FilenameIndex.getFilesByName(project, name, scope);
- if (files.length > 0) {
- for (final PsiFile file : files) {
+ if (files.length <= 0) {
+ continue;
+ }
+ for (final PsiFile file : files) {
+ ProgressManager.checkCanceled();
+
+ final VirtualFile virtualFile = file.getVirtualFile();
+ if (virtualFile == null || !virtualFile.isValid() || Comparing.equal(virtualFile, contextFile)) {
+ continue;
+ }
+ List<FileReferenceHelper> helperList = new ArrayList<FileReferenceHelper>();
+ for (FileReferenceHelper contextHelper : helpers) {
ProgressManager.checkCanceled();
- final VirtualFile virtualFile = file.getVirtualFile();
- if (virtualFile != null && virtualFile.isValid() && !Comparing.equal(virtualFile, contextFile)) {
- for (FileReferenceHelper contextHelper : helpers) {
- ProgressManager.checkCanceled();
-
- if (contextHelper.isMine(project, virtualFile)) {
- if (pathPrefixParts == null ||
- fileMatchesPathPrefix(contextHelper.getPsiFileSystemItem(project, virtualFile), pathPrefixParts)) {
- __result.addElement(new FilePathLookupItem(file, contextHelper));
- }
- }
+ if (contextHelper.isMine(project, virtualFile)) {
+ if (pathPrefixParts == null ||
+ fileMatchesPathPrefix(contextHelper.getPsiFileSystemItem(project, virtualFile), pathPrefixParts)) {
+ helperList.add(contextHelper);
}
}
}
+ if (!helperList.isEmpty()) {
+ __result.addElement(new FilePathLookupItem(file, helperList));
+ }
}
}
}
@@ -159,9 +164,7 @@ public class FilePathCompletionContributor extends CompletionContributor {
if (set.getSuitableFileTypes().length > 0 && parameters.getInvocationCount() == 1) {
final String shortcut = getActionShortcut(IdeActions.ACTION_CODE_COMPLETION);
- if (shortcut != null) {
- result.addLookupAdvertisement(CodeInsightBundle.message("class.completion.file.path.all.variants", shortcut));
- }
+ result.addLookupAdvertisement(CodeInsightBundle.message("class.completion.file.path.all.variants", shortcut));
}
if (fileReferencePair.getSecond()) result.stopHere();
@@ -203,7 +206,7 @@ public class FilePathCompletionContributor extends CompletionContributor {
final String path = StringUtil.join(contextParts, "/");
int nextIndex = 0;
- for (final String s : pathPrefix) {
+ for (@NonNls final String s : pathPrefix) {
if ((nextIndex = path.indexOf(s.toLowerCase(), nextIndex)) == -1) return false;
}
@@ -252,19 +255,19 @@ public class FilePathCompletionContributor extends CompletionContributor {
return null;
}
- public class FilePathLookupItem extends LookupElement {
+ public static class FilePathLookupItem extends LookupElement {
private final String myName;
private final String myPath;
private final String myInfo;
private final Icon myIcon;
private final PsiFile myFile;
- private final FileReferenceHelper myReferenceHelper;
+ private final List<FileReferenceHelper> myHelpers;
- public FilePathLookupItem(@NotNull final PsiFile file, @NotNull final FileReferenceHelper referenceHelper) {
+ public FilePathLookupItem(@NotNull final PsiFile file, @NotNull final List<FileReferenceHelper> helpers) {
myName = file.getName();
myPath = file.getVirtualFile().getPath();
- myReferenceHelper = referenceHelper;
+ myHelpers = helpers;
myInfo = FileInfoManager.getFileAdditionalInfo(file);
myIcon = file.getFileType().getIcon();
@@ -306,10 +309,7 @@ public class FilePathCompletionContributor extends CompletionContributor {
@Override
public void renderElement(LookupElementPresentation presentation) {
- final VirtualFile virtualFile = myFile.getVirtualFile();
- LOG.assertTrue(virtualFile != null);
- final PsiFileSystemItem root = myReferenceHelper.findRoot(myFile.getProject(), virtualFile);
- final String relativePath = PsiFileSystemItemUtil.getRelativePath(root, myReferenceHelper.getPsiFileSystemItem(myFile.getProject(), virtualFile));
+ final String relativePath = getRelativePath();
final StringBuilder sb = new StringBuilder();
if (myInfo != null) {
@@ -340,6 +340,18 @@ public class FilePathCompletionContributor extends CompletionContributor {
presentation.setIcon(myIcon);
}
+ @Nullable
+ private String getRelativePath() {
+ final VirtualFile virtualFile = myFile.getVirtualFile();
+ LOG.assertTrue(virtualFile != null);
+ for (FileReferenceHelper helper : myHelpers) {
+ final PsiFileSystemItem root = helper.findRoot(myFile.getProject(), virtualFile);
+ String path = PsiFileSystemItemUtil.getRelativePath(root, helper.getPsiFileSystemItem(myFile.getProject(), virtualFile));
+ if (path != null) return path;
+ }
+ return null;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java
index 1984230809c5..8ceca4c94a31 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java
@@ -25,7 +25,6 @@ import com.intellij.codeInsight.intention.IntentionManager;
import com.intellij.codeInsight.intention.impl.IntentionHintComponent;
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
import com.intellij.codeInsight.intention.impl.config.IntentionManagerSettings;
-import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateState;
import com.intellij.codeInspection.actions.CleanupAllIntention;
@@ -208,8 +207,6 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass {
}
private void getIntentionActionsToShow() {
- if (LookupManager.getInstance(myProject).getActiveLookup() != null) return;
-
getActionsToShow(myEditor, myFile, myIntentionsInfo, myPassIdToShowIntentionsFor);
if (myFile instanceof IntentionFilterOwner) {
final IntentionFilterOwner.IntentionActionsFilter actionsFilter = ((IntentionFilterOwner)myFile).getIntentionActionsFilter();
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/EncodingReferenceInjector.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/EncodingReferenceInjector.java
new file mode 100644
index 000000000000..6594a5a0866d
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/analysis/encoding/EncodingReferenceInjector.java
@@ -0,0 +1,46 @@
+/*
+ * 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.codeInsight.daemon.impl.analysis.encoding;
+
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.injection.ReferenceInjector;
+import com.intellij.util.ProcessingContext;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author peter
+ */
+public class EncodingReferenceInjector extends ReferenceInjector {
+ @NotNull
+ @Override
+ public PsiReference[] getReferences(@NotNull PsiElement element, @NotNull ProcessingContext context, @NotNull TextRange range) {
+ return new PsiReference[]{new EncodingReference(element, range.substring(element.getText()), range)};
+ }
+
+ @NotNull
+ @Override
+ public String getId() {
+ return "encoding-reference";
+ }
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return "Encoding Name";
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
index df55cbad9346..c27ce400049e 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
@@ -54,13 +54,17 @@ import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.psi.*;
import com.intellij.psi.presentation.java.SymbolPresentationUtil;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.ListScrollingUtil;
import com.intellij.ui.content.Content;
import com.intellij.ui.popup.AbstractPopup;
import com.intellij.ui.popup.NotLookupOrSearchCondition;
import com.intellij.ui.popup.PopupPositionManager;
import com.intellij.ui.popup.PopupUpdateProcessor;
-import com.intellij.util.*;
+import com.intellij.util.Alarm;
+import com.intellij.util.BooleanFunction;
+import com.intellij.util.Consumer;
+import com.intellij.util.Processor;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -572,7 +576,7 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
final PsiReference ref = TargetElementUtilBase.findReference(editor, offset);
if (ref != null) {
element = assertSameProject(util.adjustReference(ref));
- if (element == null && ref instanceof PsiPolyVariantReference) {
+ if (ref instanceof PsiPolyVariantReference) {
element = assertSameProject(ref.getElement());
}
}
@@ -595,16 +599,17 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
int offset = editor.getCaretModel().getOffset();
if (offset > 0 && offset == editor.getDocument().getTextLength()) offset--;
- final PsiElement contextElement = file == null? null : file.findElementAt(offset);
- final PsiReference ref = TargetElementUtilBase.findReference(editor, offset);
+ PsiReference ref = TargetElementUtilBase.findReference(editor, offset);
+ PsiElement contextElement = file == null? null : file.findElementAt(offset);
+ PsiElement targetElement = ref != null ? ref.getElement() : contextElement;
+ if (targetElement != null) {
+ PsiUtilCore.ensureValid(targetElement);
+ }
- final DocumentationProvider documentationProvider = getProviderFromElement(file);
+ DocumentationProvider documentationProvider = getProviderFromElement(file);
- return documentationProvider.getDocumentationElementForLookupItem(
- PsiManager.getInstance(myProject),
- item.getObject(),
- ref != null ? ref.getElement():contextElement
- );
+ PsiManager psiManager = PsiManager.getInstance(myProject);
+ return documentationProvider.getDocumentationElementForLookupItem(psiManager, item.getObject(), targetElement);
}
}
return null;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java
index a68a1fdeee5a..2a46c08fc2dd 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java
@@ -37,8 +37,6 @@ import java.util.ArrayList;
import java.util.List;
public class CopyHandler extends EditorActionHandler {
- private static final Logger LOG = Logger.getInstance(CopyHandler.class);
-
private final EditorActionHandler myOriginalAction;
public CopyHandler(final EditorActionHandler originalHandler) {
@@ -93,7 +91,10 @@ public class CopyHandler extends EditorActionHandler {
transferableDatas.addAll(processor.collectTransferableData(file, editor, startOffsets, endOffsets));
}
- String rawText = TextBlockTransferable.convertLineSeparators(selectionModel.getSelectedText(true), "\n", transferableDatas);
+ String text = editor.getCaretModel().supportsMultipleCarets()
+ ? CopyPasteSupport.getSelectedTextForClipboard(editor, transferableDatas)
+ : selectionModel.getSelectedText();
+ String rawText = TextBlockTransferable.convertLineSeparators(text, "\n", transferableDatas);
String escapedText = null;
for (CopyPastePreProcessor processor : Extensions.getExtensions(CopyPastePreProcessor.EP_NAME)) {
escapedText = processor.preprocessOnCopy(file, startOffsets, endOffsets, rawText);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java
index 634b8f5570a3..345cb80bae69 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java
@@ -45,7 +45,7 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate {
@Override
public boolean charDeleted(char c, PsiFile file, Editor editor) {
- if (!CodeInsightSettings.getInstance().INDENTING_BACKSPACE || !StringUtil.isWhiteSpace(c)) {
+ if (CodeInsightSettings.getInstance().SMART_BACKSPACE != CodeInsightSettings.AUTOINDENT || !StringUtil.isWhiteSpace(c)) {
return false;
}
LanguageCodeStyleSettingsProvider codeStyleSettingsProvider = LanguageCodeStyleSettingsProvider.forLanguage(file.getLanguage());
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java
deleted file mode 100644
index 075f7618eddd..000000000000
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.codeInsight.editorActions;
-
-import com.intellij.openapi.editor.RawText;
-import com.intellij.openapi.util.Comparing;
-import com.intellij.openapi.util.text.StringUtil;
-
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.Transferable;
-import java.awt.datatransfer.UnsupportedFlavorException;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-class TextBlockTransferable implements Transferable {
- private final Collection<TextBlockTransferableData> myExtraData;
- private final RawText myRawText;
- private final String myText;
- private final DataFlavor[] myTransferDataFlavors;
-
- public TextBlockTransferable(String text, Collection<TextBlockTransferableData> extraData, RawText rawText) {
- myText = text;
- myExtraData = extraData;
- myRawText = rawText;
-
- List<DataFlavor> dataFlavors = new ArrayList<DataFlavor>();
- Collections.addAll(dataFlavors, DataFlavor.stringFlavor, DataFlavor.plainTextFlavor);
- final DataFlavor flavor = RawText.getDataFlavor();
- if (myRawText != null && flavor != null) {
- dataFlavors.add(flavor);
- }
- for(TextBlockTransferableData data: extraData) {
- final DataFlavor blockFlavor = data.getFlavor();
- if (blockFlavor != null) {
- dataFlavors.add(blockFlavor);
- }
- }
- myTransferDataFlavors = dataFlavors.toArray(new DataFlavor[dataFlavors.size()]);
- }
-
- @Override
- public DataFlavor[] getTransferDataFlavors() {
- return myTransferDataFlavors;
- }
-
- @Override
- public boolean isDataFlavorSupported(DataFlavor flavor) {
- DataFlavor[] flavors = getTransferDataFlavors();
- for (DataFlavor flavor1 : flavors) {
- if (flavor.equals(flavor1)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
- try {
- for(TextBlockTransferableData data: myExtraData) {
- if (Comparing.equal(data.getFlavor(), flavor)) {
- return data;
- }
- }
- if (myRawText != null && Comparing.equal(RawText.getDataFlavor(), flavor)) {
- return myRawText;
- }
- else if (DataFlavor.stringFlavor.equals(flavor)) {
- return myText;
- }
- else if (DataFlavor.plainTextFlavor.equals(flavor)) {
- return new StringReader(myText);
- }
- }
- catch(NoClassDefFoundError e) {
- // ignore
- }
- throw new UnsupportedFlavorException(flavor);
- }
-
- public static String convertLineSeparators(String text,
- String newSeparator,
- Collection<TextBlockTransferableData> transferableDatas) {
- if (transferableDatas.size() > 0){
- int size = 0;
- for(TextBlockTransferableData data: transferableDatas) {
- size += data.getOffsetCount();
- }
-
- int[] offsets = new int[size];
- int index = 0;
- for(TextBlockTransferableData data: transferableDatas) {
- index = data.getOffsets(offsets, index);
- }
-
- text = StringUtil.convertLineSeparators(text, newSeparator, offsets);
-
- index = 0;
- for(TextBlockTransferableData data: transferableDatas) {
- index = data.setOffsets(offsets, index);
- }
-
- return text;
- }
- else{
- return StringUtil.convertLineSeparators(text, newSeparator);
- }
- }
-} \ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java
deleted file mode 100644
index c15a50e3019a..000000000000
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2000-2009 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.codeInsight.editorActions;
-
-import java.awt.datatransfer.DataFlavor;
-
-/**
- * @author yole
- */
-public interface TextBlockTransferableData {
- DataFlavor getFlavor();
-
- int getOffsetCount();
- int getOffsets(final int[] offsets, final int index);
- int setOffsets(final int[] offsets, final int index);
-}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/fillParagraph/ParagraphFillHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/fillParagraph/ParagraphFillHandler.java
index 03a72378838c..3aeefefd55ec 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/fillParagraph/ParagraphFillHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/fillParagraph/ParagraphFillHandler.java
@@ -54,7 +54,7 @@ public class ParagraphFillHandler {
document.replaceString(textRange.getStartOffset(), textRange.getEndOffset(),
replacementText);
final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(
- CodeStyleSettingsManager.getSettings(element.getProject()));
+ CodeStyleSettingsManager.getSettings(element.getProject()), element.getLanguage());
codeFormatter.doWrapLongLinesIfNecessary(editor, element.getProject(), document,
textRange.getStartOffset(),
textRange.getStartOffset() + replacementText.length() + 1);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java
index ca915119388b..3704425eb54d 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByBlockCommentHandler.java
@@ -16,9 +16,9 @@
package com.intellij.codeInsight.generation;
-import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.CommentUtil;
+import com.intellij.codeInsight.actions.MultiCaretCodeInsightActionHandler;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.highlighter.custom.CustomFileTypeLexer;
import com.intellij.lang.Commenter;
@@ -52,18 +52,20 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
-public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
+public class CommentByBlockCommentHandler extends MultiCaretCodeInsightActionHandler {
private Project myProject;
private Editor myEditor;
+ private Caret myCaret;
private @NotNull PsiFile myFile;
private Document myDocument;
private CommenterDataHolder mySelfManagedCommenterData;
@Override
- public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
+ public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull Caret caret, @NotNull PsiFile file) {
if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return;
myProject = project;
myEditor = editor;
+ myCaret = caret;
myFile = file;
myDocument = editor.getDocument();
@@ -72,19 +74,17 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
return;
}
FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.comment.block");
- final Commenter commenter = findCommenter(myFile, myEditor);
+ final Commenter commenter = findCommenter(myFile, myEditor, caret);
if (commenter == null) return;
- final SelectionModel selectionModel = myEditor.getSelectionModel();
-
final String prefix;
final String suffix;
if (commenter instanceof SelfManagingCommenter) {
final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter;
mySelfManagedCommenterData = selfManagingCommenter.createBlockCommentingState(
- selectionModel.getSelectionStart(),
- selectionModel.getSelectionEnd(),
+ caret.getSelectionStart(),
+ caret.getSelectionEnd(),
myDocument,
myFile
);
@@ -94,12 +94,12 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
}
prefix = selfManagingCommenter.getBlockCommentPrefix(
- selectionModel.getSelectionStart(),
+ caret.getSelectionStart(),
myDocument,
mySelfManagedCommenterData
);
suffix = selfManagingCommenter.getBlockCommentSuffix(
- selectionModel.getSelectionEnd(),
+ caret.getSelectionEnd(),
myDocument,
mySelfManagedCommenterData
);
@@ -117,9 +117,9 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
final int commentEnd = commentedRange.getEndOffset();
int selectionStart = commentStart;
int selectionEnd = commentEnd;
- if (selectionModel.hasSelection()) {
- selectionStart = selectionModel.getSelectionStart();
- selectionEnd = selectionModel.getSelectionEnd();
+ if (myCaret.hasSelection()) {
+ selectionStart = myCaret.getSelectionStart();
+ selectionEnd = myCaret.getSelectionEnd();
}
if ((commentStart < selectionStart || commentStart >= selectionEnd) && (commentEnd <= selectionStart || commentEnd > selectionEnd)) {
commentRange(selectionStart, selectionEnd, prefix, suffix, commenter);
@@ -129,9 +129,9 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
}
}
else {
- if (selectionModel.hasBlockSelection()) {
- final LogicalPosition start = selectionModel.getBlockStart();
- final LogicalPosition end = selectionModel.getBlockEnd();
+ if (myEditor.getSelectionModel().hasBlockSelection()) {
+ final LogicalPosition start = myEditor.getSelectionModel().getBlockStart();
+ final LogicalPosition end = myEditor.getSelectionModel().getBlockEnd();
assert start != null;
assert end != null;
@@ -151,9 +151,9 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
EditorModificationUtil.insertStringAtCaret(editor, prefix, true, true);
}
}
- else if (selectionModel.hasSelection()) {
- int selectionStart = selectionModel.getSelectionStart();
- int selectionEnd = selectionModel.getSelectionEnd();
+ else if (myCaret.hasSelection()) {
+ int selectionStart = myCaret.getSelectionStart();
+ int selectionEnd = myCaret.getSelectionEnd();
if (commenter instanceof IndentedCommenter) {
final Boolean value = ((IndentedCommenter)commenter).forceIndentedLineComment();
if (value != null && value == Boolean.TRUE) {
@@ -165,7 +165,7 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
}
else {
EditorUtil.fillVirtualSpaceUntilCaret(editor);
- int caretOffset = myEditor.getCaretModel().getOffset();
+ int caretOffset = myCaret.getOffset();
if (commenter instanceof IndentedCommenter) {
final Boolean value = ((IndentedCommenter)commenter).forceIndentedLineComment();
if (value != null && value == Boolean.TRUE) {
@@ -177,7 +177,7 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
}
}
myDocument.insertString(caretOffset, prefix + suffix);
- myEditor.getCaretModel().moveToOffset(caretOffset + prefix.length());
+ myCaret.moveToOffset(caretOffset + prefix.length());
}
}
}
@@ -188,12 +188,11 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
}
private boolean testSelectionForNonComments() {
- SelectionModel model = myEditor.getSelectionModel();
- if (!model.hasSelection()) {
+ if (!myCaret.hasSelection()) {
return true;
}
TextRange range
- = new TextRange(model.getSelectionStart(), model.getSelectionEnd() - 1);
+ = new TextRange(myCaret.getSelectionStart(), myCaret.getSelectionEnd() - 1);
for (PsiElement element = myFile.findElementAt(range.getStartOffset()); element != null && range.intersects(element.getTextRange());
element = element.getNextSibling()) {
if (element instanceof OuterLanguageElement) {
@@ -247,7 +246,7 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
final FileType fileType = myFile.getFileType();
if (fileType instanceof CustomSyntaxTableFileType) {
Lexer lexer = new CustomFileTypeLexer(((CustomSyntaxTableFileType)fileType).getSyntaxTable());
- final int caretOffset = myEditor.getCaretModel().getOffset();
+ final int caretOffset = myCaret.getOffset();
int commentStart = CharArrayUtil.lastIndexOf(text, commenter.getBlockCommentPrefix(), caretOffset);
if (commentStart == -1) return null;
@@ -261,17 +260,16 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
final String prefix;
final String suffix;
- final SelectionModel selectionModel = myEditor.getSelectionModel();
if (commenter instanceof SelfManagingCommenter) {
SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter;
prefix = selfManagingCommenter.getBlockCommentPrefix(
- selectionModel.getSelectionStart(),
+ myCaret.getSelectionStart(),
myDocument,
mySelfManagedCommenterData
);
suffix = selfManagingCommenter.getBlockCommentSuffix(
- selectionModel.getSelectionEnd(),
+ myCaret.getSelectionEnd(),
myDocument,
mySelfManagedCommenterData
);
@@ -286,8 +284,8 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
if (commenter instanceof SelfManagingCommenter) {
commentedRange = ((SelfManagingCommenter)commenter).getBlockCommentRange(
- selectionModel.getSelectionStart(),
- selectionModel.getSelectionEnd(),
+ myCaret.getSelectionStart(),
+ myCaret.getSelectionEnd(),
myDocument,
mySelfManagedCommenterData
);
@@ -316,11 +314,10 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
@Nullable
private TextRange getSelectedComments(CharSequence text, String prefix, String suffix) {
TextRange commentedRange = null;
- final SelectionModel selectionModel = myEditor.getSelectionModel();
- if (selectionModel.hasSelection()) {
- int selectionStart = selectionModel.getSelectionStart();
+ if (myCaret.hasSelection()) {
+ int selectionStart = myCaret.getSelectionStart();
selectionStart = CharArrayUtil.shiftForward(text, selectionStart, " \t\n");
- int selectionEnd = selectionModel.getSelectionEnd() - 1;
+ int selectionEnd = myCaret.getSelectionEnd() - 1;
selectionEnd = CharArrayUtil.shiftBackward(text, selectionEnd, " \t\n") + 1;
if (selectionEnd - selectionStart >= prefix.length() + suffix.length() &&
CharArrayUtil.regionMatches(text, selectionStart, prefix) &&
@@ -332,13 +329,13 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
}
@Nullable
- private static Commenter findCommenter(PsiFile file, Editor editor) {
+ private static Commenter findCommenter(PsiFile file, Editor editor, Caret caret) {
final FileType fileType = file.getFileType();
if (fileType instanceof AbstractFileType) {
return ((AbstractFileType)fileType).getCommenter();
}
- Language lang = PsiUtilBase.getLanguageInEditor(editor, file.getProject());
+ Language lang = PsiUtilBase.getLanguageInEditor(caret, file.getProject());
return getCommenter(file, editor, lang, lang);
}
@@ -371,9 +368,8 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
@Nullable
private PsiElement findCommentAtCaret() {
- int offset = myEditor.getCaretModel().getOffset();
- SelectionModel selectionModel = myEditor.getSelectionModel();
- TextRange range = new TextRange(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
+ int offset = myCaret.getOffset();
+ TextRange range = new TextRange(myCaret.getSelectionStart(), myCaret.getSelectionEnd());
if (offset == range.getEndOffset()) {
offset--;
}
@@ -383,21 +379,16 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
PsiElement elt = myFile.getViewProvider().findElementAt(offset);
if (elt == null) return null;
PsiElement comment = PsiTreeUtil.getParentOfType(elt, PsiComment.class, false);
- if (comment == null || selectionModel.hasSelection() && !range.contains(comment.getTextRange())) {
+ if (comment == null || myCaret.hasSelection() && !range.contains(comment.getTextRange())) {
return null;
}
return comment;
}
- @Override
- public boolean startInWriteAction() {
- return true;
- }
-
public void commentRange(int startOffset, int endOffset, String commentPrefix, String commentSuffix, Commenter commenter) {
CharSequence chars = myDocument.getCharsSequence();
- LogicalPosition caretPosition = myEditor.getCaretModel().getLogicalPosition();
+ LogicalPosition caretPosition = myCaret.getLogicalPosition();
if (startOffset == 0 || chars.charAt(startOffset - 1) == '\n') {
if (endOffset == myDocument.getTextLength() || endOffset > 0 && chars.charAt(endOffset - 1) == '\n') {
@@ -426,21 +417,17 @@ public class CommentByBlockCommentHandler implements CodeInsightActionHandler {
nestingSuffix.append("\n");
TextRange range =
insertNestedComments(chars, startOffset, endOffset, nestingPrefix.toString(), nestingSuffix.toString(), commenter);
- myEditor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset());
- //myEditor.getSelectionModel().removeSelection();
+ myCaret.setSelection(range.getStartOffset(), range.getEndOffset());
LogicalPosition pos = new LogicalPosition(caretPosition.line + 1, caretPosition.column);
- myEditor.getCaretModel().moveToLogicalPosition(pos);
- myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+ myCaret.moveToLogicalPosition(pos);
return;
}
}
TextRange range = insertNestedComments(chars, startOffset, endOffset, commentPrefix, commentSuffix, commenter);
- myEditor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset());
- //myEditor.getSelectionModel().removeSelection();
+ myCaret.setSelection(range.getStartOffset(), range.getEndOffset());
LogicalPosition pos = new LogicalPosition(caretPosition.line, caretPosition.column + commentPrefix.length());
- myEditor.getCaretModel().moveToLogicalPosition(pos);
- myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+ myCaret.moveToLogicalPosition(pos);
}
private int doBoundCommentingAndGetShift(int offset,
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java
index ba73ac14d715..d62f51bb2e02 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/CommentByLineCommentHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * 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.
@@ -16,12 +16,13 @@
package com.intellij.codeInsight.generation;
-import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.CommentUtil;
+import com.intellij.codeInsight.actions.MultiCaretCodeInsightActionHandler;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.highlighter.custom.SyntaxTable;
import com.intellij.injected.editor.EditorWindow;
+import com.intellij.injected.editor.InjectedCaret;
import com.intellij.lang.Commenter;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageCommenters;
@@ -38,7 +39,6 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
@@ -53,181 +53,245 @@ import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
-public class CommentByLineCommentHandler implements CodeInsightActionHandler {
-
+public class CommentByLineCommentHandler extends MultiCaretCodeInsightActionHandler {
private Project myProject;
- private PsiFile myFile;
- private Document myDocument;
- private Editor myEditor;
- private int myStartOffset;
- private int myEndOffset;
- private int myStartLine;
- private int myEndLine;
- private int[] myStartOffsets;
- private int[] myEndOffsets;
- private Commenter[] myCommenters;
- private Map<SelfManagingCommenter, CommenterDataHolder> myCommenterStateMap;
private CodeStyleManager myCodeStyleManager;
+ private final List<Block> myBlocks = new ArrayList<Block>();
+
@Override
- public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull PsiFile file) {
+ // first pass - adjacent carets are grouped into blocks
+ public void invoke(@NotNull Project project, @NotNull Editor editor, @NotNull Caret caret, @NotNull PsiFile file) {
if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return;
myProject = project;
- myFile = file.getViewProvider().getPsi(file.getViewProvider().getBaseLanguage());
- myEditor = editor;
+ file = file.getViewProvider().getPsi(file.getViewProvider().getBaseLanguage());
- PsiElement context = InjectedLanguageManager.getInstance(myFile.getProject()).getInjectionHost(myFile);
+ PsiElement context = InjectedLanguageManager.getInstance(file.getProject()).getInjectionHost(file);
if (context != null && (context.textContains('\'') || context.textContains('\"'))) {
String s = context.getText();
if (StringUtil.startsWith(s, "\"") || StringUtil.startsWith(s, "\'")) {
- myFile = context.getContainingFile();
- myEditor = editor instanceof EditorWindow ? ((EditorWindow)editor).getDelegate() : editor;
+ file = context.getContainingFile();
+ editor = editor instanceof EditorWindow ? ((EditorWindow)editor).getDelegate() : editor;
+ caret = caret instanceof InjectedCaret ? ((InjectedCaret)caret).getDelegate() : caret;
}
}
- myDocument = myEditor.getDocument();
- if (!FileDocumentManager.getInstance().requestWriting(myDocument, project)) {
+ Document document = editor.getDocument();
+ if (!FileDocumentManager.getInstance().requestWriting(document, project)) {
return;
}
- PsiDocumentManager.getInstance(project).commitDocument(myDocument);
-
- FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.comment.line");
-
- myCodeStyleManager = CodeStyleManager.getInstance(myProject);
-
- final SelectionModel selectionModel = myEditor.getSelectionModel();
-
- boolean hasSelection = selectionModel.hasSelection();
- myStartOffset = selectionModel.getSelectionStart();
- myEndOffset = selectionModel.getSelectionEnd();
+ boolean hasSelection = caret.hasSelection();
+ int startOffset = caret.getSelectionStart();
+ int endOffset = caret.getSelectionEnd();
- FoldRegion fold = myEditor.getFoldingModel().getCollapsedRegionAtOffset(myStartOffset);
- if (fold != null && fold.shouldNeverExpand() && fold.getStartOffset() == myStartOffset && fold.getEndOffset() == myEndOffset) {
- // Foldings that never expand are automatically selected, so the fact it is selected must not interfer with commenter's logic
+ FoldRegion fold = editor.getFoldingModel().getCollapsedRegionAtOffset(startOffset);
+ if (fold != null && fold.shouldNeverExpand() && fold.getStartOffset() == startOffset && fold.getEndOffset() == endOffset) {
+ // Foldings that never expand are automatically selected, so the fact it is selected must not interfere with commenter's logic
hasSelection = false;
}
- if (myDocument.getTextLength() == 0) return;
+ if (document.getTextLength() == 0) return;
while (true) {
- int lastLineEnd = myDocument.getLineEndOffset(myDocument.getLineNumber(myEndOffset));
- FoldRegion collapsedAt = myEditor.getFoldingModel().getCollapsedRegionAtOffset(lastLineEnd);
+ int lastLineEnd = document.getLineEndOffset(document.getLineNumber(endOffset));
+ FoldRegion collapsedAt = editor.getFoldingModel().getCollapsedRegionAtOffset(lastLineEnd);
if (collapsedAt != null) {
- final int endOffset = collapsedAt.getEndOffset();
- if (endOffset <= myEndOffset) {
+ final int regionEndOffset = collapsedAt.getEndOffset();
+ if (regionEndOffset <= endOffset) {
break;
}
- myEndOffset = endOffset;
+ endOffset = regionEndOffset;
}
else {
break;
}
}
- boolean wholeLinesSelected = !hasSelection ||
- myStartOffset == myDocument.getLineStartOffset(myDocument.getLineNumber(myStartOffset)) &&
- myEndOffset == myDocument.getLineEndOffset(myDocument.getLineNumber(myEndOffset - 1)) + 1;
-
- boolean startingNewLineComment = !hasSelection && isLineEmpty(myDocument.getLineNumber(myStartOffset)) && !Comparing
- .equal(IdeActions.ACTION_COMMENT_LINE, ActionManagerEx.getInstanceEx().getPrevPreformedActionId());
- doComment();
-
- if (startingNewLineComment) {
- final Commenter commenter = myCommenters[0];
- if (commenter != null) {
- String prefix;
- if (commenter instanceof SelfManagingCommenter) {
- prefix = ((SelfManagingCommenter)commenter).getCommentPrefix(
- myStartLine,
- myDocument,
- myCommenterStateMap.get((SelfManagingCommenter)commenter)
- );
- if (prefix == null) prefix = ""; // TODO
- }
- else {
- prefix = commenter.getLineCommentPrefix();
- if (prefix == null) prefix = commenter.getBlockCommentPrefix();
- }
+ int startLine = document.getLineNumber(startOffset);
+ int endLine = document.getLineNumber(endOffset);
- int lineStart = myDocument.getLineStartOffset(myStartLine);
- lineStart = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), lineStart, " \t");
- lineStart += prefix.length();
- lineStart = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), lineStart, " \t");
- if (lineStart > myDocument.getTextLength()) lineStart = myDocument.getTextLength();
- myEditor.getCaretModel().moveToOffset(lineStart);
- myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
- }
+ if (endLine > startLine && document.getLineStartOffset(endLine) == endOffset) {
+ endLine--;
+ }
+
+ Block lastBlock = myBlocks.isEmpty() ? null : myBlocks.get(myBlocks.size() - 1);
+ Block currentBlock;
+ if (lastBlock == null || lastBlock.editor != editor || lastBlock.psiFile != file || endLine < (lastBlock.startLine - 1)) {
+ currentBlock = new Block();
+ currentBlock.editor = editor;
+ currentBlock.psiFile = file;
+ currentBlock.endLine = endLine;
+ myBlocks.add(currentBlock);
}
else {
- if (!hasSelection) {
- // Don't tweak caret position if we're already located on the last document line.
- LogicalPosition position = myEditor.getCaretModel().getLogicalPosition();
- if (position.line < myDocument.getLineCount() - 1) {
- int verticalShift = 1 + myEditor.getSoftWrapModel().getSoftWrapsForLine(position.line).size()
- - position.softWrapLinesOnCurrentLogicalLine;
- myEditor.getCaretModel().moveCaretRelatively(0, verticalShift, false, false, true);
- }
- }
- else {
- if (wholeLinesSelected) {
- selectionModel.setSelection(myStartOffset, selectionModel.getSelectionEnd());
- }
- }
+ currentBlock = lastBlock;
}
- }
+ currentBlock.carets.add(caret);
+ currentBlock.startLine = startLine;
- private boolean isLineEmpty(final int line) {
- final CharSequence chars = myDocument.getCharsSequence();
- int start = myDocument.getLineStartOffset(line);
- int end = Math.min(myDocument.getLineEndOffset(line), myDocument.getTextLength() - 1);
- for (int i = start; i <= end; i++) {
- if (!Character.isWhitespace(chars.charAt(i))) return false;
+ boolean wholeLinesSelected = !hasSelection ||
+ startOffset == document.getLineStartOffset(document.getLineNumber(startOffset)) &&
+ endOffset == document.getLineEndOffset(document.getLineNumber(endOffset - 1)) + 1;
+ boolean startingNewLineComment = !hasSelection
+ && isLineEmpty(document, document.getLineNumber(startOffset))
+ && !Comparing.equal(IdeActions.ACTION_COMMENT_LINE,
+ ActionManagerEx.getInstanceEx().getPrevPreformedActionId());
+ currentBlock.caretUpdate = startingNewLineComment ? CaretUpdate.PUT_AT_COMMENT_START :
+ !hasSelection ? CaretUpdate.SHIFT_DOWN :
+ wholeLinesSelected ? CaretUpdate.RESTORE_SELECTION : null;
}
- return true;
- }
@Override
- public boolean startInWriteAction() {
- return true;
- }
+ public void postInvoke() {
+ FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.comment.line");
+
+ myCodeStyleManager = CodeStyleManager.getInstance(myProject);
- private void doComment() {
- myStartLine = myDocument.getLineNumber(myStartOffset);
- myEndLine = myDocument.getLineNumber(myEndOffset);
+ // second pass - determining whether we need to comment or to uncomment
+ boolean allLinesCommented = true;
+ for (Block block : myBlocks) {
+ int startLine = block.startLine;
+ int endLine = block.endLine;
+ Document document = block.editor.getDocument();
+ PsiFile psiFile = block.psiFile;
+
+ block.startOffsets = new int[endLine - startLine + 1];
+ block.endOffsets = new int[endLine - startLine + 1];
+ block.commenters = new Commenter[endLine - startLine + 1];
+ block.commenterStateMap = new THashMap<SelfManagingCommenter, CommenterDataHolder>();
+ CharSequence chars = document.getCharsSequence();
+
+ boolean singleline = startLine == endLine;
+ int offset = document.getLineStartOffset(startLine);
+ offset = CharArrayUtil.shiftForward(chars, offset, " \t");
- if (myEndLine > myStartLine && myDocument.getLineStartOffset(myEndLine) == myEndOffset) {
- myEndLine--;
- }
+ int endOffset = CharArrayUtil.shiftBackward(chars, document.getLineEndOffset(endLine), " \t\n");
- myStartOffsets = new int[myEndLine - myStartLine + 1];
- myEndOffsets = new int[myEndLine - myStartLine + 1];
- myCommenters = new Commenter[myEndLine - myStartLine + 1];
- myCommenterStateMap = new THashMap<SelfManagingCommenter, CommenterDataHolder>();
- CharSequence chars = myDocument.getCharsSequence();
+ block.blockSuitableCommenter = getBlockSuitableCommenter(psiFile, offset, endOffset);
+ block.commentWithIndent =
+ !CodeStyleSettingsManager.getSettings(myProject).getCommonSettings(psiFile.getLanguage()).LINE_COMMENT_AT_FIRST_COLUMN;
+
+ for (int line = startLine; line <= endLine; line++) {
+ Commenter commenter = block.blockSuitableCommenter != null ? block.blockSuitableCommenter : findCommenter(block.editor, psiFile, line);
+ if (commenter == null || commenter.getLineCommentPrefix() == null
+ && (commenter.getBlockCommentPrefix() == null || commenter.getBlockCommentSuffix() == null)) {
+ block.skip = true;
+ break;
+ }
- boolean singleline = myStartLine == myEndLine;
- int offset = myDocument.getLineStartOffset(myStartLine);
- offset = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), offset, " \t");
+ if (commenter instanceof SelfManagingCommenter && block.commenterStateMap.get(commenter) == null) {
+ final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter;
+ CommenterDataHolder state = selfManagingCommenter.createLineCommentingState(startLine, endLine, document, psiFile);
+ if (state == null) state = SelfManagingCommenter.EMPTY_STATE;
+ block.commenterStateMap.put(selfManagingCommenter, state);
+ }
- int endOffset = CharArrayUtil.shiftBackward(myDocument.getCharsSequence(), myDocument.getLineEndOffset(myEndLine), " \t\n");
+ block.commenters[line - startLine] = commenter;
+ if (!isLineCommented(block, line, commenter) && (singleline || !isLineEmpty(document, line))) {
+ allLinesCommented = false;
+ if (commenter instanceof IndentedCommenter) {
+ final Boolean value = ((IndentedCommenter)commenter).forceIndentedLineComment();
+ if (value != null) {
+ block.commentWithIndent = value;
+ }
+ }
+ break;
+ }
+ }
+ }
+ boolean moveCarets = true;
+ for (Block block : myBlocks) {
+ if (block.carets.size() > 1 && block.startLine != block.endLine) {
+ moveCarets = false;
+ break;
+ }
+ }
+ // third pass - actual change
+ for (Block block : myBlocks) {
+ if (!block.skip) {
+ if (!allLinesCommented) {
+ if (!block.commentWithIndent) {
+ doDefaultCommenting(block);
+ }
+ else {
+ doIndentCommenting(block);
+ }
+ }
+ else {
+ for (int line = block.endLine; line >= block.startLine; line--) {
+ uncommentLine(block, line);
+ }
+ }
+ }
+
+ if (!moveCarets || block.caretUpdate == null) {
+ continue;
+ }
+ Document document = block.editor.getDocument();
+ for (Caret caret : block.carets) {
+ switch (block.caretUpdate) {
+ case PUT_AT_COMMENT_START:
+ final Commenter commenter = block.commenters[0];
+ if (commenter != null) {
+ String prefix;
+ if (commenter instanceof SelfManagingCommenter) {
+ prefix = ((SelfManagingCommenter)commenter).getCommentPrefix(block.startLine,
+ document,
+ block.commenterStateMap.get((SelfManagingCommenter)commenter));
+ if (prefix == null) prefix = ""; // TODO
+ }
+ else {
+ prefix = commenter.getLineCommentPrefix();
+ if (prefix == null) prefix = commenter.getBlockCommentPrefix();
+ }
+
+ int lineStart = document.getLineStartOffset(block.startLine);
+ lineStart = CharArrayUtil.shiftForward(document.getCharsSequence(), lineStart, " \t");
+ lineStart += prefix.length();
+ lineStart = CharArrayUtil.shiftForward(document.getCharsSequence(), lineStart, " \t");
+ if (lineStart > document.getTextLength()) lineStart = document.getTextLength();
+ caret.moveToOffset(lineStart);
+ }
+ break;
+ case SHIFT_DOWN:
+ // Don't tweak caret position if we're already located on the last document line.
+ LogicalPosition position = caret.getLogicalPosition();
+ if (position.line < document.getLineCount() - 1) {
+ int verticalShift = 1 + block.editor.getSoftWrapModel().getSoftWrapsForLine(position.line).size()
+ - position.softWrapLinesOnCurrentLogicalLine;
+ caret.moveCaretRelatively(0, verticalShift, false, true);
+ }
+ break;
+ case RESTORE_SELECTION:
+ caret.setSelection(document.getLineStartOffset(document.getLineNumber(caret.getSelectionStart())), caret.getSelectionEnd());
+ }
+ }
+ }
+ }
+
+ private static Commenter getBlockSuitableCommenter(final PsiFile file, int offset, int endOffset) {
final Language languageSuitableForCompleteFragment;
if (offset >= endOffset) { // we are on empty line
- PsiElement element = myFile.findElementAt(offset);
+ PsiElement element = file.findElementAt(offset);
if (element != null) languageSuitableForCompleteFragment = element.getParent().getLanguage();
else languageSuitableForCompleteFragment = null;
- } else {
- languageSuitableForCompleteFragment = PsiUtilBase.reallyEvaluateLanguageInRange(offset, endOffset, myFile);
}
+ else {
+ languageSuitableForCompleteFragment = PsiUtilBase.reallyEvaluateLanguageInRange(offset, endOffset, file);
+ }
+
Commenter blockSuitableCommenter =
- languageSuitableForCompleteFragment == null ? LanguageCommenters.INSTANCE.forLanguage(myFile.getLanguage()) : null;
- if (blockSuitableCommenter == null && myFile.getFileType() instanceof CustomSyntaxTableFileType) {
+ languageSuitableForCompleteFragment == null ? LanguageCommenters.INSTANCE.forLanguage(file.getLanguage()) : null;
+ if (blockSuitableCommenter == null && file.getFileType() instanceof CustomSyntaxTableFileType) {
blockSuitableCommenter = new Commenter() {
- final SyntaxTable mySyntaxTable = ((CustomSyntaxTableFileType)myFile.getFileType()).getSyntaxTable();
+ final SyntaxTable mySyntaxTable = ((CustomSyntaxTableFileType)file.getFileType()).getSyntaxTable();
@Override
@Nullable
@@ -259,96 +323,30 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
};
}
- boolean allLineCommented = true;
- boolean commentWithIndent =
- !CodeStyleSettingsManager.getSettings(myProject).getCommonSettings(myFile.getLanguage()).LINE_COMMENT_AT_FIRST_COLUMN;
-
- for (int line = myStartLine; line <= myEndLine; line++) {
- Commenter commenter = blockSuitableCommenter != null ? blockSuitableCommenter : findCommenter(line);
- if (commenter == null) return;
- if (commenter.getLineCommentPrefix() == null &&
- (commenter.getBlockCommentPrefix() == null || commenter.getBlockCommentSuffix() == null)) {
- return;
- }
-
- if (commenter instanceof SelfManagingCommenter &&
- myCommenterStateMap.get(commenter) == null) {
- final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter;
- CommenterDataHolder state =
- selfManagingCommenter.createLineCommentingState(myStartLine, myEndLine, myDocument, myFile);
- if (state == null) state = SelfManagingCommenter.EMPTY_STATE;
- myCommenterStateMap.put(selfManagingCommenter, state);
- }
-
- myCommenters[line - myStartLine] = commenter;
- if (!isLineCommented(line, chars, commenter) && (singleline || !isLineEmpty(line))) {
- allLineCommented = false;
- if (commenter instanceof IndentedCommenter) {
- final Boolean value = ((IndentedCommenter)commenter).forceIndentedLineComment();
- if (value != null) {
- commentWithIndent = value;
- }
- }
- break;
- }
- }
+ return blockSuitableCommenter;
+ }
- if (!allLineCommented) {
- if (!commentWithIndent) {
- doDefaultCommenting(blockSuitableCommenter);
- }
- else {
- doIndentCommenting(blockSuitableCommenter);
- }
- }
- else {
- for (int line = myEndLine; line >= myStartLine; line--) {
- uncommentLine(line);
- //int offset1 = myStartOffsets[line - myStartLine];
- //int offset2 = myEndOffsets[line - myStartLine];
- //if (offset1 == offset2) continue;
- //Commenter commenter = myCommenters[line - myStartLine];
- //String prefix = commenter.getBlockCommentPrefix();
- //if (prefix == null || !myDocument.getText().substring(offset1, myDocument.getTextLength()).startsWith(prefix)) {
- // prefix = commenter.getLineCommentPrefix();
- //}
- //
- //String suffix = commenter.getBlockCommentSuffix();
- //if (suffix == null && prefix != null) suffix = "";
- //
- //if (prefix != null && suffix != null) {
- // final int suffixLen = suffix.length();
- // final int prefixLen = prefix.length();
- // if (offset2 >= 0) {
- // if (!CharArrayUtil.regionMatches(chars, offset1 + prefixLen, prefix)) {
- // myDocument.deleteString(offset2 - suffixLen, offset2);
- // }
- // }
- // if (offset1 >= 0) {
- // for (int i = offset2 - suffixLen - 1; i > offset1 + prefixLen; --i) {
- // if (CharArrayUtil.regionMatches(chars, i, suffix)) {
- // myDocument.deleteString(i, i + suffixLen);
- // }
- // else if (CharArrayUtil.regionMatches(chars, i, prefix)) {
- // myDocument.deleteString(i, i + prefixLen);
- // }
- // }
- // myDocument.deleteString(offset1, offset1 + prefixLen);
- // }
- //}
- }
+ private static boolean isLineEmpty(Document document, final int line) {
+ final CharSequence chars = document.getCharsSequence();
+ int start = document.getLineStartOffset(line);
+ int end = Math.min(document.getLineEndOffset(line), document.getTextLength() - 1);
+ for (int i = start; i <= end; i++) {
+ if (!Character.isWhitespace(chars.charAt(i))) return false;
}
+ return true;
}
- private boolean isLineCommented(final int line, final CharSequence chars, final Commenter commenter) {
+ private static boolean isLineCommented(Block block, final int line, final Commenter commenter) {
boolean commented;
int lineEndForBlockCommenting = -1;
- int lineStart = myDocument.getLineStartOffset(line);
+ Document document = block.editor.getDocument();
+ int lineStart = document.getLineStartOffset(line);
+ CharSequence chars = document.getCharsSequence();
lineStart = CharArrayUtil.shiftForward(chars, lineStart, " \t");
if (commenter instanceof SelfManagingCommenter) {
final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter;
- commented = selfManagingCommenter.isLineCommented(line, lineStart, myDocument, myCommenterStateMap.get(selfManagingCommenter));
+ commented = selfManagingCommenter.isLineCommented(line, lineStart, document, block.commenterStateMap.get(selfManagingCommenter));
}
else {
String prefix = commenter.getLineCommentPrefix();
@@ -359,8 +357,8 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
else {
prefix = commenter.getBlockCommentPrefix();
String suffix = commenter.getBlockCommentSuffix();
- final int textLength = myDocument.getTextLength();
- lineEndForBlockCommenting = myDocument.getLineEndOffset(line);
+ final int textLength = document.getTextLength();
+ lineEndForBlockCommenting = document.getLineEndOffset(line);
if (lineEndForBlockCommenting == textLength) {
final int shifted = CharArrayUtil.shiftBackward(chars, textLength - 1, " \t");
if (shifted < textLength - 1) lineEndForBlockCommenting = shifted;
@@ -368,59 +366,61 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
else {
lineEndForBlockCommenting = CharArrayUtil.shiftBackward(chars, lineEndForBlockCommenting, " \t");
}
- commented = lineStart == lineEndForBlockCommenting && myStartLine != myEndLine ||
+ commented = lineStart == lineEndForBlockCommenting && block.startLine != block.endLine ||
CharArrayUtil.regionMatches(chars, lineStart, prefix)
&& CharArrayUtil.regionMatches(chars, lineEndForBlockCommenting - suffix.length(), suffix);
}
}
if (commented) {
- myStartOffsets[line - myStartLine] = lineStart;
- myEndOffsets[line - myStartLine] = lineEndForBlockCommenting;
+ block.startOffsets[line - block.startLine] = lineStart;
+ block.endOffsets[line - block.startLine] = lineEndForBlockCommenting;
}
return commented;
}
@Nullable
- private Commenter findCommenter(final int line) {
- final FileType fileType = myFile.getFileType();
+ private static Commenter findCommenter(Editor editor, PsiFile file, final int line) {
+ final FileType fileType = file.getFileType();
if (fileType instanceof AbstractFileType) {
return ((AbstractFileType)fileType).getCommenter();
}
- int lineStartOffset = myDocument.getLineStartOffset(line);
- int lineEndOffset = myDocument.getLineEndOffset(line) - 1;
- final CharSequence charSequence = myDocument.getCharsSequence();
+ Document document = editor.getDocument();
+ int lineStartOffset = document.getLineStartOffset(line);
+ int lineEndOffset = document.getLineEndOffset(line) - 1;
+ final CharSequence charSequence = document.getCharsSequence();
lineStartOffset = CharArrayUtil.shiftForward(charSequence, lineStartOffset, " \t");
lineEndOffset = CharArrayUtil.shiftBackward(charSequence, lineEndOffset < 0 ? 0 : lineEndOffset, " \t");
- final Language lineStartLanguage = PsiUtilCore.getLanguageAtOffset(myFile, lineStartOffset);
- final Language lineEndLanguage = PsiUtilCore.getLanguageAtOffset(myFile, lineEndOffset);
- return CommentByBlockCommentHandler.getCommenter(myFile, myEditor, lineStartLanguage, lineEndLanguage);
+ final Language lineStartLanguage = PsiUtilCore.getLanguageAtOffset(file, lineStartOffset);
+ final Language lineEndLanguage = PsiUtilCore.getLanguageAtOffset(file, lineEndOffset);
+ return CommentByBlockCommentHandler.getCommenter(file, editor, lineStartLanguage, lineEndLanguage);
}
- private Indent computeMinIndent(int line1, int line2, CharSequence chars, CodeStyleManager codeStyleManager, FileType fileType) {
- Indent minIndent = CommentUtil.getMinLineIndent(myProject, myDocument, line1, line2, fileType);
+ private Indent computeMinIndent(Editor editor, PsiFile psiFile, int line1, int line2, FileType fileType) {
+ Document document = editor.getDocument();
+ Indent minIndent = CommentUtil.getMinLineIndent(myProject, document, line1, line2, fileType);
if (line1 > 0) {
- int commentOffset = getCommentStart(line1 - 1);
+ int commentOffset = getCommentStart(editor, psiFile, line1 - 1);
if (commentOffset >= 0) {
- int lineStart = myDocument.getLineStartOffset(line1 - 1);
- String space = chars.subSequence(lineStart, commentOffset).toString();
- Indent indent = codeStyleManager.getIndent(space, fileType);
+ int lineStart = document.getLineStartOffset(line1 - 1);
+ String space = document.getCharsSequence().subSequence(lineStart, commentOffset).toString();
+ Indent indent = myCodeStyleManager.getIndent(space, fileType);
minIndent = minIndent != null ? indent.min(minIndent) : indent;
}
}
if (minIndent == null) {
- minIndent = codeStyleManager.zeroIndent();
+ minIndent = myCodeStyleManager.zeroIndent();
}
return minIndent;
}
- private int getCommentStart(int line) {
- int offset = myDocument.getLineStartOffset(line);
- CharSequence chars = myDocument.getCharsSequence();
+ private static int getCommentStart(Editor editor, PsiFile psiFile, int line) {
+ int offset = editor.getDocument().getLineStartOffset(line);
+ CharSequence chars = editor.getDocument().getCharsSequence();
offset = CharArrayUtil.shiftForward(chars, offset, " \t");
- final Commenter commenter = findCommenter(line);
+ final Commenter commenter = findCommenter(editor, psiFile, line);
if (commenter == null) return -1;
String prefix = commenter.getLineCommentPrefix();
if (prefix == null) prefix = commenter.getBlockCommentPrefix();
@@ -428,53 +428,55 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
return CharArrayUtil.regionMatches(chars, offset, prefix) ? offset : -1;
}
- public void doDefaultCommenting(final Commenter commenter) {
+ public void doDefaultCommenting(final Block block) {
+ final Document document = block.editor.getDocument();
DocumentUtil.executeInBulk(
- myDocument, myEndLine - myStartLine >= Registry.intValue("comment.by.line.bulk.lines.trigger"), new Runnable() {
+ document, block.endLine - block.startLine >= Registry.intValue("comment.by.line.bulk.lines.trigger"), new Runnable() {
@Override
public void run() {
- for (int line = myEndLine; line >= myStartLine; line--) {
- int offset = myDocument.getLineStartOffset(line);
- commentLine(line, offset, commenter);
+ for (int line = block.endLine; line >= block.startLine; line--) {
+ int offset = document.getLineStartOffset(line);
+ commentLine(block, line, offset);
}
}
});
}
- private void doIndentCommenting(final Commenter commenter) {
- final CharSequence chars = myDocument.getCharsSequence();
- final FileType fileType = myFile.getFileType();
- final Indent minIndent = computeMinIndent(myStartLine, myEndLine, chars, myCodeStyleManager, fileType);
+ private void doIndentCommenting(final Block block) {
+ final Document document = block.editor.getDocument();
+ final CharSequence chars = document.getCharsSequence();
+ final FileType fileType = block.psiFile.getFileType();
+ final Indent minIndent = computeMinIndent(block.editor, block.psiFile, block.startLine, block.endLine, fileType);
DocumentUtil.executeInBulk(
- myDocument, myEndLine - myStartLine > Registry.intValue("comment.by.line.bulk.lines.trigger"), new Runnable() {
- @Override
- public void run() {
- for (int line = myEndLine; line >= myStartLine; line--) {
- int lineStart = myDocument.getLineStartOffset(line);
- int offset = lineStart;
- final StringBuilder buffer = new StringBuilder();
- while (true) {
- String space = buffer.toString();
- Indent indent = myCodeStyleManager.getIndent(space, fileType);
- if (indent.isGreaterThan(minIndent) || indent.equals(minIndent)) break;
- char c = chars.charAt(offset);
- if (c != ' ' && c != '\t') {
- String newSpace = myCodeStyleManager.fillIndent(minIndent, fileType);
- myDocument.replaceString(lineStart, offset, newSpace);
- offset = lineStart + newSpace.length();
- break;
+ document, block.endLine - block.startLine > Registry.intValue("comment.by.line.bulk.lines.trigger"), new Runnable() {
+ @Override
+ public void run() {
+ for (int line = block.endLine; line >= block.startLine; line--) {
+ int lineStart = document.getLineStartOffset(line);
+ int offset = lineStart;
+ final StringBuilder buffer = new StringBuilder();
+ while (true) {
+ String space = buffer.toString();
+ Indent indent = myCodeStyleManager.getIndent(space, fileType);
+ if (indent.isGreaterThan(minIndent) || indent.equals(minIndent)) break;
+ char c = chars.charAt(offset);
+ if (c != ' ' && c != '\t') {
+ String newSpace = myCodeStyleManager.fillIndent(minIndent, fileType);
+ document.replaceString(lineStart, offset, newSpace);
+ offset = lineStart + newSpace.length();
+ break;
+ }
+ buffer.append(c);
+ offset++;
}
- buffer.append(c);
- offset++;
+ commentLine(block, line, offset);
}
- commentLine(line, offset, commenter);
}
- }
- });
+ });
}
- private void uncommentRange(int startOffset, int endOffset, @NotNull Commenter commenter) {
+ private static void uncommentRange(Document document, int startOffset, int endOffset, @NotNull Commenter commenter) {
final String commentedSuffix = commenter.getCommentedBlockCommentSuffix();
final String commentedPrefix = commenter.getCommentedBlockCommentPrefix();
final String prefix = commenter.getBlockCommentPrefix();
@@ -482,52 +484,53 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
if (prefix == null || suffix == null) {
return;
}
- if (endOffset >= suffix.length() && CharArrayUtil.regionMatches(myDocument.getCharsSequence(), endOffset - suffix.length(), suffix)) {
- myDocument.deleteString(endOffset - suffix.length(), endOffset);
- endOffset = myDocument.getTextLength();
+ if (endOffset >= suffix.length() && CharArrayUtil.regionMatches(document.getCharsSequence(), endOffset - suffix.length(), suffix)) {
+ document.deleteString(endOffset - suffix.length(), endOffset);
+ endOffset = document.getTextLength();
}
if (commentedPrefix != null && commentedSuffix != null) {
- CommentByBlockCommentHandler.commentNestedComments(myDocument, new TextRange(startOffset, endOffset), commenter);
+ CommentByBlockCommentHandler.commentNestedComments(document, new TextRange(startOffset, endOffset), commenter);
}
- myDocument.deleteString(startOffset, startOffset + prefix.length());
+ document.deleteString(startOffset, startOffset + prefix.length());
}
- private void uncommentLine(int line) {
- Commenter commenter = myCommenters[line - myStartLine];
- if (commenter == null) commenter = findCommenter(line);
+ private static void uncommentLine(Block block, int line) {
+ Document document = block.editor.getDocument();
+ Commenter commenter = block.commenters[line - block.startLine];
+ if (commenter == null) commenter = findCommenter(block.editor, block.psiFile, line);
if (commenter == null) return;
- final int startOffset = myStartOffsets[line - myStartLine];
+ final int startOffset = block.startOffsets[line - block.startLine];
if (commenter instanceof SelfManagingCommenter) {
final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter;
- selfManagingCommenter.uncommentLine(line, startOffset, myDocument, myCommenterStateMap.get(selfManagingCommenter));
+ selfManagingCommenter.uncommentLine(line, startOffset, document, block.commenterStateMap.get(selfManagingCommenter));
return;
}
- final int endOffset = myEndOffsets[line - myStartLine];
+ final int endOffset = block.endOffsets[line - block.startLine];
if (startOffset == endOffset) {
return;
}
String prefix = commenter.getLineCommentPrefix();
if (prefix != null) {
- CharSequence chars = myDocument.getCharsSequence();
+ CharSequence chars = document.getCharsSequence();
if (commenter instanceof CommenterWithLineSuffix) {
CommenterWithLineSuffix commenterWithLineSuffix = (CommenterWithLineSuffix)commenter;
String suffix = commenterWithLineSuffix.getLineCommentSuffix();
- int theEnd = endOffset > 0 ? endOffset : myDocument.getLineEndOffset(line);
+ int theEnd = endOffset > 0 ? endOffset : document.getLineEndOffset(line);
while (theEnd > startOffset && Character.isWhitespace(chars.charAt(theEnd - 1))) {
theEnd--;
}
- String lineText = myDocument.getText(new TextRange(startOffset, theEnd));
+ String lineText = document.getText(new TextRange(startOffset, theEnd));
if (lineText.indexOf(suffix) != -1) {
int start = startOffset + lineText.indexOf(suffix);
- myDocument.deleteString(start, start + suffix.length());
+ document.deleteString(start, start + suffix.length());
}
}
@@ -544,10 +547,10 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
charsToDelete++;
}
}
- myDocument.deleteString(startOffset, startOffset + charsToDelete);
+ document.deleteString(startOffset, startOffset + charsToDelete);
return;
}
- String text = myDocument.getCharsSequence().subSequence(startOffset, endOffset).toString();
+ String text = document.getCharsSequence().subSequence(startOffset, endOffset).toString();
prefix = commenter.getBlockCommentPrefix();
final String suffix = commenter.getBlockCommentSuffix();
@@ -575,45 +578,47 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
assert prefixes.size() == suffixes.size();
for (int i = prefixes.size() - 1; i >= 0; i--) {
- uncommentRange(startOffset + prefixes.get(i), Math.min(startOffset + suffixes.get(i) + suffix.length(), endOffset), commenter);
+ uncommentRange(document, startOffset + prefixes.get(i), Math.min(startOffset + suffixes.get(i) + suffix.length(), endOffset), commenter);
}
}
- private void commentLine(int line, int offset, @Nullable Commenter commenter) {
- if (commenter == null) commenter = findCommenter(line);
+ private static void commentLine(Block block, int line, int offset) {
+ Commenter commenter = block.blockSuitableCommenter;
+ Document document = block.editor.getDocument();
+ if (commenter == null) commenter = findCommenter(block.editor, block.psiFile, line);
if (commenter == null) return;
if (commenter instanceof SelfManagingCommenter) {
final SelfManagingCommenter selfManagingCommenter = (SelfManagingCommenter)commenter;
- selfManagingCommenter.commentLine(line, offset, myDocument, myCommenterStateMap.get(selfManagingCommenter));
+ selfManagingCommenter.commentLine(line, offset, document, block.commenterStateMap.get(selfManagingCommenter));
return;
}
String prefix = commenter.getLineCommentPrefix();
if (prefix != null) {
if (commenter instanceof CommenterWithLineSuffix) {
- int endOffset = myDocument.getLineEndOffset(line);
- endOffset = CharArrayUtil.shiftBackward(myDocument.getCharsSequence(), endOffset, " \t");
- int shiftedStartOffset = CharArrayUtil.shiftForward(myDocument.getCharsSequence(), offset, " \t");
+ int endOffset = document.getLineEndOffset(line);
+ endOffset = CharArrayUtil.shiftBackward(document.getCharsSequence(), endOffset, " \t");
+ int shiftedStartOffset = CharArrayUtil.shiftForward(document.getCharsSequence(), offset, " \t");
String lineSuffix = ((CommenterWithLineSuffix)commenter).getLineCommentSuffix();
- if (!CharArrayUtil.regionMatches(myDocument.getCharsSequence(), shiftedStartOffset, prefix)) {
- if (!CharArrayUtil.regionMatches(myDocument.getCharsSequence(), endOffset - lineSuffix.length(), lineSuffix)) {
- myDocument.insertString(endOffset, lineSuffix);
+ if (!CharArrayUtil.regionMatches(document.getCharsSequence(), shiftedStartOffset, prefix)) {
+ if (!CharArrayUtil.regionMatches(document.getCharsSequence(), endOffset - lineSuffix.length(), lineSuffix)) {
+ document.insertString(endOffset, lineSuffix);
}
- myDocument.insertString(offset, prefix);
+ document.insertString(offset, prefix);
}
}
else {
- myDocument.insertString(offset, prefix);
+ document.insertString(offset, prefix);
}
}
else {
prefix = commenter.getBlockCommentPrefix();
String suffix = commenter.getBlockCommentSuffix();
if (prefix == null || suffix == null) return;
- int endOffset = myDocument.getLineEndOffset(line);
- if (endOffset == offset && myStartLine != myEndLine) return;
- final int textLength = myDocument.getTextLength();
- final CharSequence chars = myDocument.getCharsSequence();
+ int endOffset = document.getLineEndOffset(line);
+ if (endOffset == offset && block.startLine != block.endLine) return;
+ final int textLength = document.getTextLength();
+ final CharSequence chars = document.getCharsSequence();
offset = CharArrayUtil.shiftForward(chars, offset, " \t");
if (endOffset == textLength) {
final int shifted = CharArrayUtil.shiftBackward(chars, textLength - 1, " \t");
@@ -623,7 +628,7 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
endOffset = CharArrayUtil.shiftBackward(chars, endOffset, " \t");
}
if (endOffset < offset ||
- offset == textLength - 1 && line != myDocument.getLineCount() - 1) {
+ offset == textLength - 1 && line != document.getLineCount() - 1) {
return;
}
final String text = chars.subSequence(offset, endOffset).toString();
@@ -653,7 +658,7 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
}
}
if (!(commentedSuffix == null && !suffixes.isEmpty() && offset + suffixes.get(suffixes.size() - 1) + suffix.length() >= endOffset)) {
- myDocument.insertString(endOffset, suffix);
+ document.insertString(endOffset, suffix);
}
int nearestPrefix = prefixes.size() - 1;
int nearestSuffix = suffixes.size() - 1;
@@ -662,26 +667,46 @@ public class CommentByLineCommentHandler implements CodeInsightActionHandler {
final int position = prefixes.get(nearestPrefix);
nearestPrefix--;
if (commentedPrefix != null) {
- myDocument.replaceString(offset + position, offset + position + prefix.length(), commentedPrefix);
+ document.replaceString(offset + position, offset + position + prefix.length(), commentedPrefix);
}
else if (position != 0) {
- myDocument.insertString(offset + position, suffix);
+ document.insertString(offset + position, suffix);
}
}
else {
final int position = suffixes.get(nearestSuffix);
nearestSuffix--;
if (commentedSuffix != null) {
- myDocument.replaceString(offset + position, offset + position + suffix.length(), commentedSuffix);
+ document.replaceString(offset + position, offset + position + suffix.length(), commentedSuffix);
}
else if (offset + position + suffix.length() < endOffset) {
- myDocument.insertString(offset + position + suffix.length(), prefix);
+ document.insertString(offset + position + suffix.length(), prefix);
}
}
}
if (!(commentedPrefix == null && !prefixes.isEmpty() && prefixes.get(0) == 0)) {
- myDocument.insertString(offset, prefix);
+ document.insertString(offset, prefix);
}
}
}
+
+ private static class Block {
+ private Editor editor;
+ private PsiFile psiFile;
+ private List<Caret> carets = new ArrayList<Caret>();
+ private int startLine;
+ private int endLine;
+ private int[] startOffsets;
+ private int[] endOffsets;
+ private Commenter blockSuitableCommenter;
+ private Commenter[] commenters;
+ private Map<SelfManagingCommenter, CommenterDataHolder> commenterStateMap;
+ private boolean commentWithIndent;
+ private CaretUpdate caretUpdate;
+ private boolean skip;
+ }
+
+ private enum CaretUpdate {
+ PUT_AT_COMMENT_START, SHIFT_DOWN, RESTORE_SELECTION
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/CommentByBlockCommentAction.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/CommentByBlockCommentAction.java
index ce0d3b63e6e0..bd24557744f5 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/CommentByBlockCommentAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/CommentByBlockCommentAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * 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.
@@ -16,11 +16,12 @@
package com.intellij.codeInsight.generation.actions;
-import com.intellij.codeInsight.CodeInsightActionHandler;
-import com.intellij.codeInsight.actions.BaseCodeInsightAction;
+import com.intellij.codeInsight.actions.MultiCaretCodeInsightAction;
+import com.intellij.codeInsight.actions.MultiCaretCodeInsightActionHandler;
import com.intellij.codeInsight.generation.CommentByBlockCommentHandler;
import com.intellij.lang.Commenter;
import com.intellij.lang.LanguageCommenters;
+import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.impl.AbstractFileType;
@@ -29,19 +30,19 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
-public class CommentByBlockCommentAction extends BaseCodeInsightAction implements DumbAware {
+public class CommentByBlockCommentAction extends MultiCaretCodeInsightAction implements DumbAware {
public CommentByBlockCommentAction() {
setEnabledInModalContext(true);
}
@NotNull
@Override
- protected CodeInsightActionHandler getHandler() {
+ protected MultiCaretCodeInsightActionHandler getHandler() {
return new CommentByBlockCommentHandler();
}
@Override
- protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull final PsiFile file) {
+ protected boolean isValidFor(@NotNull Project project, @NotNull Editor editor, @NotNull Caret caret, @NotNull final PsiFile file) {
final FileType fileType = file.getFileType();
if (fileType instanceof AbstractFileType) {
return ((AbstractFileType)fileType).getCommenter() != null;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/CommentByLineCommentAction.java b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/CommentByLineCommentAction.java
index 990e64701ce1..3ee4ecc4d65e 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/CommentByLineCommentAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/generation/actions/CommentByLineCommentAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * 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.
@@ -16,9 +16,10 @@
package com.intellij.codeInsight.generation.actions;
-import com.intellij.codeInsight.CodeInsightActionHandler;
-import com.intellij.codeInsight.actions.BaseCodeInsightAction;
+import com.intellij.codeInsight.actions.MultiCaretCodeInsightAction;
+import com.intellij.codeInsight.actions.MultiCaretCodeInsightActionHandler;
import com.intellij.codeInsight.generation.CommentByLineCommentHandler;
+import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.fileTypes.impl.AbstractFileType;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.FileType;
@@ -28,19 +29,19 @@ import com.intellij.psi.PsiFile;
import com.intellij.lang.LanguageCommenters;
import org.jetbrains.annotations.NotNull;
-public class CommentByLineCommentAction extends BaseCodeInsightAction implements DumbAware {
+public class CommentByLineCommentAction extends MultiCaretCodeInsightAction implements DumbAware {
public CommentByLineCommentAction() {
setEnabledInModalContext(true);
}
@NotNull
@Override
- protected CodeInsightActionHandler getHandler() {
+ protected MultiCaretCodeInsightActionHandler getHandler() {
return new CommentByLineCommentHandler();
}
@Override
- protected boolean isValidForFile(@NotNull Project project, @NotNull Editor editor, @NotNull final PsiFile file) {
+ protected boolean isValidFor(@NotNull Project project, @NotNull Editor editor, @NotNull Caret caret, @NotNull final PsiFile file) {
final FileType fileType = file.getFileType();
if (fileType instanceof AbstractFileType) {
return ((AbstractFileType)fileType).getCommenter() != null;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java
index 284a8ecb85bf..3a1f04b80414 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java
@@ -623,10 +623,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable,
}
public boolean performGuardedChange(Runnable change) {
- return performGuardedChange(change, null);
- }
-
- public boolean performGuardedChange(Runnable change, @Nullable final String debug) {
checkValid();
assert !myChangeGuard : "already in change";
@@ -634,7 +630,7 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable,
myChangeGuard = true;
boolean result;
try {
- result = myOffsets.performGuardedChange(change, debug);
+ result = myOffsets.performGuardedChange(change);
}
finally {
myEditor.getDocument().stopGuardedBlockChecking();
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupOffsets.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupOffsets.java
index fe53f1796dbd..9d918cc0e175 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupOffsets.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupOffsets.java
@@ -15,27 +15,26 @@
*/
package com.intellij.codeInsight.lookup.impl;
-import com.intellij.codeInsight.completion.RangeMarkerSpy;
import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
+import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
-import org.jetbrains.annotations.Nullable;
+import com.intellij.psi.impl.DebugUtil;
+import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* @author peter
*/
-public class LookupOffsets {
- private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.lookup.impl.LookupOffsets");
+public class LookupOffsets extends DocumentAdapter {
private String myAdditionalPrefix = "";
private String myInitialPrefix;
private boolean myStableStart;
- private RangeMarker myLookupStartMarker;
+ private String myStartDisposeTrace;
+ @NotNull private RangeMarker myLookupStartMarker;
private int myRemovedPrefix;
private final RangeMarker myLookupOriginalStartMarker;
private final Editor myEditor;
@@ -43,23 +42,22 @@ public class LookupOffsets {
public LookupOffsets(Editor editor) {
myEditor = editor;
int caret = getPivotOffset();
- myLookupOriginalStartMarker = editor.getDocument().createRangeMarker(caret, caret);
- myLookupOriginalStartMarker.setGreedyToLeft(true);
- updateLookupStart(0);
+ myLookupOriginalStartMarker = createLeftGreedyMarker(caret);
+ myLookupStartMarker = createLeftGreedyMarker(caret);
+ myEditor.getDocument().addDocumentListener(this);
}
- private void updateLookupStart(int minPrefixLength) {
- int offset = getPivotOffset();
- int start = offset - minPrefixLength - myAdditionalPrefix.length() + myRemovedPrefix;
- start = Math.max(Math.min(start, myEditor.getDocument().getTextLength()), 0);
- if (myLookupStartMarker != null) {
- if (myLookupStartMarker.isValid() && myLookupStartMarker.getStartOffset() == start && myLookupStartMarker.getEndOffset() == start) {
- return;
- }
- myLookupStartMarker.dispose();
+ @Override
+ public void documentChanged(DocumentEvent e) {
+ if (myStartDisposeTrace == null && !myLookupStartMarker.isValid()) {
+ myStartDisposeTrace = e + "\n" + DebugUtil.currentStackTrace();
}
- myLookupStartMarker = myEditor.getDocument().createRangeMarker(start, start);
- myLookupStartMarker.setGreedyToLeft(true);
+ }
+
+ private RangeMarker createLeftGreedyMarker(int start) {
+ RangeMarker marker = myEditor.getDocument().createRangeMarker(start, start);
+ marker.setGreedyToLeft(true);
+ return marker;
}
private int getPivotOffset() {
@@ -101,15 +99,20 @@ public class LookupOffsets {
}
}
- updateLookupStart(minPrefixLength);
+ int start = getPivotOffset() - minPrefixLength - myAdditionalPrefix.length() + myRemovedPrefix;
+ start = Math.max(Math.min(start, myEditor.getDocument().getTextLength()), 0);
+ if (myLookupStartMarker.isValid() && myLookupStartMarker.getStartOffset() == start && myLookupStartMarker.getEndOffset() == start) {
+ return;
+ }
+
+ myLookupStartMarker.dispose();
+ myLookupStartMarker = createLeftGreedyMarker(start);
+ myStartDisposeTrace = null;
}
int getLookupStart(String disposeTrace) {
- if (myLookupStartMarker == null) {
- LOG.error("disposed: " + disposeTrace);
- }
if (!myLookupStartMarker.isValid()) {
- LOG.error("invalid marker: " + disposeTrace);
+ throw new AssertionError("Invalid lookup start: " + disposeTrace + ";\n" + myStartDisposeTrace);
}
return myLookupStartMarker.getStartOffset();
}
@@ -118,33 +121,14 @@ public class LookupOffsets {
return myLookupOriginalStartMarker.isValid() ? myLookupOriginalStartMarker.getStartOffset() : -1;
}
- boolean performGuardedChange(Runnable change, @Nullable final String debug) {
- if (myLookupStartMarker == null) {
- throw new AssertionError("null start before");
- }
+ boolean performGuardedChange(Runnable change) {
if (!myLookupStartMarker.isValid()) {
- throw new AssertionError("invalid start");
- }
- final Document document = myEditor.getDocument();
- RangeMarkerSpy spy = new RangeMarkerSpy(myLookupStartMarker) {
- @Override
- protected void invalidated(DocumentEvent e) {
- LOG.info("Lookup start marker invalidated, say thanks to the " + e +
- ", doc=" + document +
- ", debug=" + debug);
- }
- };
- document.addDocumentListener(spy);
- try {
- change.run();
- }
- finally {
- document.removeDocumentListener(spy);
+ throw new AssertionError("Invalid start: " + myStartDisposeTrace);
}
+ change.run();
return myLookupStartMarker.isValid();
}
-
void setInitialPrefix(String presentPrefix, boolean explicitlyInvoked) {
if (myAdditionalPrefix.length() == 0 && myInitialPrefix == null && !explicitlyInvoked) {
myInitialPrefix = presentPrefix;
@@ -165,11 +149,9 @@ public class LookupOffsets {
}
}
- public void disposeMarkers() {
- if (myLookupStartMarker != null) {
- myLookupStartMarker.dispose();
- myLookupStartMarker = null;
- }
+ void disposeMarkers() {
+ myEditor.getDocument().removeDocumentListener(this);
+ myLookupStartMarker.dispose();
myLookupOriginalStartMarker.dispose();
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java b/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java
index 512bfa1b27fb..9678ef213f45 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/LiveTemplateBuilder.java
@@ -247,8 +247,13 @@ public class LiveTemplateBuilder {
else {
newVarName = varName;
}
- Variable var =
- new Variable(newVarName, template.getExpressionStringAt(i), template.getDefaultValueStringAt(i), template.isAlwaysStopAt(i));
+ Variable var = new Variable(newVarName, template.getExpressionStringAt(i), template.getDefaultValueStringAt(i), template.isAlwaysStopAt(i));
+ if (mySegmentLimit >= 0 && myVariables.size() >= mySegmentLimit) {
+ if (mySegmentLimit > 0) {
+ LOGGER.warn("Template with more than " + mySegmentLimit + " segments had been build. Text: " + myText);
+ }
+ break;
+ }
myVariables.add(var);
myVarNames.add(newVarName);
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/settings/PostfixDescriptionPanel.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/settings/PostfixDescriptionPanel.java
index 6032cbe63e66..c5c10ceefcb1 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/settings/PostfixDescriptionPanel.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/settings/PostfixDescriptionPanel.java
@@ -42,6 +42,7 @@ class PostfixDescriptionPanel implements Disposable {
private JEditorPane myDescriptionBrowser;
public PostfixDescriptionPanel() {
+ myDescriptionBrowser.setMargin(new Insets(5, 5, 5, 5));
initializeExamplePanel(myAfterPanel);
initializeExamplePanel(myBeforePanel);
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/settings/PostfixTemplatesConfigurable.form b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/settings/PostfixTemplatesConfigurable.form
index 9af302be1d97..2417e0b689d2 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/settings/PostfixTemplatesConfigurable.form
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/settings/PostfixTemplatesConfigurable.form
@@ -13,7 +13,7 @@
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="1" hsize-policy="3" anchor="1" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
- <text value="&amp;Enable postfix templates"/>
+ <text value="&amp;Enable postfix completion"/>
</properties>
</component>
<component id="9f784" class="com.intellij.ui.components.JBCheckBox" binding="myCompletionEnabledCheckbox">
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java b/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java
index 391232cd2857..86cbe6f1d6b7 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/InspectionApplication.java
@@ -105,7 +105,7 @@ public class InspectionApplication {
LOG.error(e);
}
finally {
- if (myErrorCodeRequired) application.exit(true);
+ if (myErrorCodeRequired) application.exit(true, true);
}
}
});
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/Descriptor.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/Descriptor.java
index c3d4e158c070..b27befd36b00 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/ex/Descriptor.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/Descriptor.java
@@ -40,6 +40,7 @@ public class Descriptor {
private final InspectionToolWrapper myToolWrapper;
private final HighlightDisplayLevel myLevel;
private boolean myEnabled = false;
+ @Nullable
private final NamedScope myScope;
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.Descriptor");
private final ScopeToolState myState;
@@ -99,6 +100,13 @@ public class Descriptor {
return myConfig;
}
+ public void loadConfig() {
+ if (myConfig == null) {
+ InspectionToolWrapper toolWrapper = getToolWrapper();
+ myConfig = createConfigElement(toolWrapper);
+ }
+ }
+
@NotNull
public InspectionToolWrapper getToolWrapper() {
return myToolWrapper;
@@ -106,11 +114,7 @@ public class Descriptor {
@Nullable
public String loadDescription() {
- if (myConfig == null) {
- InspectionToolWrapper toolWrapper = getToolWrapper();
- myConfig = createConfigElement(toolWrapper);
- }
-
+ loadConfig();
return myToolWrapper.loadDescription();
}
@@ -133,6 +137,7 @@ public class Descriptor {
return myGroup;
}
+ @Nullable
public NamedScope getScope() {
return myScope;
}
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/SeverityEditorDialog.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/SeverityEditorDialog.java
index b5333e8bd63e..527235b5166c 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/ex/SeverityEditorDialog.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/SeverityEditorDialog.java
@@ -301,6 +301,9 @@ public class SeverityEditorDialog extends DialogWrapper {
}
private void reset(SeverityBasedTextAttributes info) {
+ if (info == null) {
+ return;
+ }
final MyTextAttributesDescription description =
new MyTextAttributesDescription(info.getType().toString(), null, info.getAttributes(), info.getType().getAttributesKey());
@NonNls Element textAttributes = new Element("temp");
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/VisibleTreeState.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/VisibleTreeState.java
index 8f81c0589c92..d81fbf692812 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/ex/VisibleTreeState.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/VisibleTreeState.java
@@ -16,7 +16,7 @@
package com.intellij.codeInspection.ex;
-import com.intellij.profile.codeInspection.ui.InspectionConfigTreeNode;
+import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionConfigTreeNode;
import com.intellij.psi.search.scope.packageSet.NamedScope;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.ui.tree.TreeUtil;
@@ -106,7 +106,7 @@ public class VisibleTreeState{
}
private static State getState(InspectionConfigTreeNode node) {
- Descriptor descriptor = node.getDescriptor();
+ Descriptor descriptor = node.getDefaultDescriptor();
final State expandedNode;
if (descriptor != null) {
expandedNode = new State(descriptor);
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java
index cab3fbeeedda..b36ab755a9ac 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionResultsViewComparator.java
@@ -36,7 +36,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.profile.codeInspection.ui.InspectionsConfigTreeComparator;
+import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionsConfigTreeComparator;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java
index d50bddc322e8..d1c3c3a2d7f1 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionTree.java
@@ -31,7 +31,7 @@ import com.intellij.codeInspection.reference.RefEntity;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FileStatus;
-import com.intellij.profile.codeInspection.ui.InspectionsConfigTreeComparator;
+import com.intellij.profile.codeInspection.ui.inspectionsTree.InspectionsConfigTreeComparator;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.JBColor;
import com.intellij.ui.SimpleTextAttributes;
diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleViewImpl.java
index bb738098f3b8..8a4b1f85125a 100644
--- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleViewImpl.java
+++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleViewImpl.java
@@ -30,7 +30,7 @@ import javax.swing.*;
*/
public class LanguageConsoleViewImpl extends ConsoleViewImpl implements LanguageConsoleView {
@NotNull
- protected LanguageConsoleImpl myConsole;
+ protected final LanguageConsoleImpl myConsole;
public LanguageConsoleViewImpl(Project project, String title, Language language) {
this(new LanguageConsoleImpl(project, title, language));
diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java
index 8c5864c6569b..8a36638d993c 100644
--- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java
+++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * 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.
@@ -48,6 +48,7 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -68,11 +69,12 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
private final Project myProject;
private ActionToolbar myActionsToolbar;
-
+ @NotNull
public Editor getEditor() {
return myEditor;
}
+ @NotNull
private final Editor myEditor;
public JTextComponent getSearchField() {
@@ -173,7 +175,7 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
return findModel;
}
- public EditorSearchComponent(Editor editor, Project project) {
+ public EditorSearchComponent(@NotNull Editor editor, Project project) {
this(editor, project, createDefaultFindModel(project, editor));
}
@@ -225,7 +227,7 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
}
@Override
- public void cursorMoved(boolean toChangeSelection) {
+ public void cursorMoved() {
updateExcludeStatus();
}
@@ -233,10 +235,7 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
public void updateFinished() {
}
- @Override
- public void editorChanged(SearchResults sr, Editor oldEditor) { }
-
- public EditorSearchComponent(final Editor editor, final Project project, FindModel findModel) {
+ public EditorSearchComponent(@NotNull final Editor editor, final Project project, FindModel findModel) {
myFindModel = findModel;
myProject = project;
@@ -367,6 +366,9 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
actionGroup.add(new ShowHistoryAction(mySearchFieldGetter, this));
actionGroup.add(new PrevOccurrenceAction(this, mySearchFieldGetter));
actionGroup.add(new NextOccurrenceAction(this, mySearchFieldGetter));
+ actionGroup.add(new AddOccurrenceAction(this));
+ actionGroup.add(new RemoveOccurrenceAction(this));
+ actionGroup.add(new SelectAllAction(this));
actionGroup.add(new FindAllAction(this));
actionGroup.add(new ToggleMultiline(this));
actionGroup.add(new ToggleMatchCase(this));
@@ -803,10 +805,6 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
}
public void close() {
- if (myEditor.getSelectionModel().hasSelection()) {
- myEditor.getCaretModel().moveToOffset(myEditor.getSelectionModel().getSelectionStart());
- myEditor.getSelectionModel().removeSelection();
- }
IdeFocusManager.getInstance(myProject).requestFocus(myEditor.getContentComponent(), false);
myLivePreviewController.dispose();
@@ -937,6 +935,18 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
return insets;
}
+ public void selectAllOccurrences() {
+ FindUtil.selectSearchResultsInEditor(myEditor, mySearchResults.getOccurrences().iterator(), -1);
+ }
+
+ public void removeOccurrence() {
+ mySearchResults.prevOccurrence(true);
+ }
+
+ public void addNextOccurrence() {
+ mySearchResults.nextOccurrence(true);
+ }
+
private static class MyUndoProvider extends TextComponentUndoProvider {
private boolean myEnabled = true;
public MyUndoProvider(JTextComponent textComponent) {
diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java
index 0728ea07e2b3..edc906481398 100644
--- a/platform/lang-impl/src/com/intellij/find/FindUtil.java
+++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java
@@ -31,6 +31,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.actionSystem.EditorActionManager;
+import com.intellij.openapi.editor.actions.EditorActionUtil;
import com.intellij.openapi.editor.actions.IncrementalFindAction;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
@@ -70,10 +71,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
+import java.util.*;
public class FindUtil {
private static final Key<Direction> KEY = Key.create("FindUtil.KEY");
@@ -385,7 +383,7 @@ public class FindUtil {
}
else {
editor.putUserData(KEY, null);
- offset = editor.getCaretModel().getOffset();
+ offset = model.isGlobal() && model.isForward() ? editor.getSelectionModel().getSelectionEnd() : editor.getCaretModel().getOffset();
if (!model.isForward() && offset > 0) {
offset--;
}
@@ -714,7 +712,18 @@ public class FindUtil {
final ScrollType scrollType = forward ? ScrollType.CENTER_DOWN : ScrollType.CENTER_UP;
if (model.isGlobal()) {
- caretModel.moveToOffset(result.getEndOffset());
+ int targetCaretPosition = result.getEndOffset();
+ if (selection.getSelectionEnd() - selection.getSelectionStart() == result.getLength()) {
+ // keeping caret's position relative to selection
+ // use case: FindNext is used after SelectNextOccurrence action
+ targetCaretPosition = caretModel.getOffset() - selection.getSelectionStart() + result.getStartOffset();
+ }
+ if (caretModel.getCaretAt(editor.offsetToVisualPosition(targetCaretPosition)) != null) {
+ // if there's a different caret at target position, don't move current caret/selection
+ // use case: FindNext is used after SelectNextOccurrence action
+ return result;
+ }
+ caretModel.moveToOffset(targetCaretPosition);
selection.removeSelection();
scrollingModel.scrollToCaret(scrollType);
scrollingModel.runActionOnScrollingFinished(
@@ -829,17 +838,12 @@ public class FindUtil {
editor.getCaretModel().addCaretListener(listener);
}
JComponent component = HintUtil.createInformationLabel(JDOMUtil.escapeText(message, false, false));
-
- if (ApplicationManager.getApplication().isUnitTestMode()) {
- LivePreview.processNotFound();
- } else {
- final LightweightHint hint = new LightweightHint(component);
- HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, position,
- HintManager.HIDE_BY_ANY_KEY |
- HintManager.HIDE_BY_TEXT_CHANGE |
- HintManager.HIDE_BY_SCROLLING,
- 0, false);
- }
+ final LightweightHint hint = new LightweightHint(component);
+ HintManagerImpl.getInstanceImpl().showEditorHint(hint, editor, position,
+ HintManager.HIDE_BY_ANY_KEY |
+ HintManager.HIDE_BY_TEXT_CHANGE |
+ HintManager.HIDE_BY_SCROLLING,
+ 0, false);
}
public static TextRange doReplace(final Project project,
@@ -954,4 +958,68 @@ public class FindUtil {
});
return view;
}
+
+ /**
+ * Creates a selection in editor per each search result. Existing carets and selections in editor are discarded.
+ *
+ * @param caretShiftFromSelectionStart if non-negative, defines caret position relative to selection start, for each created selection.
+ * if negative, carets will be positioned at selection ends
+ */
+ public static void selectSearchResultsInEditor(@NotNull Editor editor,
+ @NotNull Iterator<FindResult> resultIterator,
+ int caretShiftFromSelectionStart) {
+ if (!editor.getCaretModel().supportsMultipleCarets()) {
+ return;
+ }
+ ArrayList<CaretState> caretStates = new ArrayList<CaretState>();
+ while (resultIterator.hasNext()) {
+ FindResult findResult = resultIterator.next();
+ int caretOffset = getCaretPosition(findResult, caretShiftFromSelectionStart);
+ int selectionStartOffset = findResult.getStartOffset();
+ int selectionEndOffset = findResult.getEndOffset();
+ EditorActionUtil.makePositionVisible(editor, caretOffset);
+ EditorActionUtil.makePositionVisible(editor, selectionStartOffset);
+ EditorActionUtil.makePositionVisible(editor, selectionEndOffset);
+ caretStates.add(new CaretState(editor.offsetToLogicalPosition(caretOffset),
+ editor.offsetToLogicalPosition(selectionStartOffset),
+ editor.offsetToLogicalPosition(selectionEndOffset)));
+ }
+ if (caretStates.isEmpty()) {
+ return;
+ }
+ editor.getCaretModel().setCaretsAndSelections(caretStates);
+ }
+
+ /**
+ * Attempts to add a new caret to editor, with selection corresponding to given search result.
+ *
+ * @param caretShiftFromSelectionStart if non-negative, defines caret position relative to selection start, for each created selection.
+ * if negative, caret will be positioned at selection end
+ * @return <code>true</code> if caret was added successfully, <code>false</code> if it cannot be done, e.g. because a caret already
+ * exists at target position
+ */
+ public static boolean selectSearchResultInEditor(@NotNull Editor editor, @NotNull FindResult result, int caretShiftFromSelectionStart) {
+ if (!editor.getCaretModel().supportsMultipleCarets()) {
+ return false;
+ }
+ int caretOffset = getCaretPosition(result, caretShiftFromSelectionStart);
+ EditorActionUtil.makePositionVisible(editor, caretOffset);
+ Caret newCaret = editor.getCaretModel().addCaret(editor.offsetToVisualPosition(caretOffset));
+ if (newCaret == null) {
+ return false;
+ }
+ else {
+ int selectionStartOffset = result.getStartOffset();
+ int selectionEndOffset = result.getEndOffset();
+ EditorActionUtil.makePositionVisible(editor, selectionStartOffset);
+ EditorActionUtil.makePositionVisible(editor, selectionEndOffset);
+ newCaret.setSelection(selectionStartOffset, selectionEndOffset);
+ return true;
+ }
+ }
+
+ private static int getCaretPosition(FindResult findResult, int caretShiftFromSelectionStart) {
+ return caretShiftFromSelectionStart < 0
+ ? findResult.getEndOffset() : Math.min(findResult.getStartOffset() + caretShiftFromSelectionStart, findResult.getEndOffset());
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java
new file mode 100644
index 000000000000..9064113d9c9b
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/AddOccurrenceAction.java
@@ -0,0 +1,46 @@
+/*
+ * 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.find.editorHeaderActions;
+
+import com.intellij.find.EditorSearchComponent;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.project.DumbAware;
+
+import java.util.Arrays;
+
+public class AddOccurrenceAction extends EditorHeaderAction implements DumbAware {
+ public AddOccurrenceAction(EditorSearchComponent editorSearchComponent) {
+ super(editorSearchComponent);
+
+ copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_SELECT_NEXT_OCCURENCE));
+ getTemplatePresentation().setIcon(AllIcons.General.Add);
+
+ registerShortcutsForComponent(Arrays.asList(getShortcutSet().getShortcuts()), editorSearchComponent.getSearchField());
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ getEditorSearchComponent().addNextOccurrence();
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ boolean isFind = !getEditorSearchComponent().getFindModel().isReplaceState();
+ boolean hasMatches = getEditorSearchComponent().hasMatches();
+ e.getPresentation().setVisible(isFind);
+ e.getPresentation().setEnabled(isFind && hasMatches);
+ }}
diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java
index 6cdba4b1e6eb..15348730a41d 100644
--- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java
+++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/EditorHeaderAction.java
@@ -1,21 +1,34 @@
+/*
+ * 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.find.editorHeaderActions;
import com.intellij.find.EditorSearchComponent;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
-import com.intellij.openapi.actionSystem.KeyboardShortcut;
import com.intellij.openapi.actionSystem.Shortcut;
import javax.swing.*;
-import java.util.ArrayList;
import java.util.List;
public abstract class EditorHeaderAction extends AnAction {
private final EditorSearchComponent myEditorSearchComponent;
- protected static void registerShortcutsForComponent(List<Shortcut> shortcuts, JComponent component, AnAction a) {
- a.registerCustomShortcutSet(
+ protected void registerShortcutsForComponent(List<Shortcut> shortcuts, JComponent component) {
+ registerCustomShortcutSet(
new CustomShortcutSet(shortcuts.toArray(new Shortcut[shortcuts.size()])),
component);
}
diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java
index 1eb933cf2d03..0e6e67168521 100644
--- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java
+++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/NextOccurrenceAction.java
@@ -1,3 +1,18 @@
+/*
+ * 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.find.editorHeaderActions;
import com.intellij.find.EditorSearchComponent;
@@ -35,7 +50,7 @@ public class NextOccurrenceAction extends EditorHeaderAction implements DumbAwar
shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), null));
}
- registerShortcutsForComponent(shortcuts, editorTextField.get(), this);
+ registerShortcutsForComponent(shortcuts, editorTextField.get());
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java
index f5a2d3911b43..586f90a835d1 100644
--- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java
+++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/PrevOccurrenceAction.java
@@ -1,3 +1,18 @@
+/*
+ * 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.find.editorHeaderActions;
import com.intellij.find.EditorSearchComponent;
@@ -34,7 +49,7 @@ public class PrevOccurrenceAction extends EditorHeaderAction implements DumbAwar
shortcuts.add(new KeyboardShortcut(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK), null));
}
- registerShortcutsForComponent(shortcuts, editorTextField.get(), this);
+ registerShortcutsForComponent(shortcuts, editorTextField.get());
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java
new file mode 100644
index 000000000000..b739f942991d
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RemoveOccurrenceAction.java
@@ -0,0 +1,49 @@
+/*
+ * 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.find.editorHeaderActions;
+
+import com.intellij.find.EditorSearchComponent;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.IdeActions;
+import com.intellij.openapi.project.DumbAware;
+
+import java.util.Arrays;
+
+public class RemoveOccurrenceAction extends EditorHeaderAction implements DumbAware {
+ public RemoveOccurrenceAction(EditorSearchComponent editorSearchComponent) {
+ super(editorSearchComponent);
+
+ copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_UNSELECT_PREVIOUS_OCCURENCE));
+ getTemplatePresentation().setIcon(AllIcons.General.Remove);
+
+ registerShortcutsForComponent(Arrays.asList(getShortcutSet().getShortcuts()), editorSearchComponent.getSearchField());
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ getEditorSearchComponent().removeOccurrence();
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ boolean isFind = !getEditorSearchComponent().getFindModel().isReplaceState();
+ boolean hasMatches = getEditorSearchComponent().hasMatches();
+ e.getPresentation().setVisible(isFind);
+ e.getPresentation().setEnabled(isFind && hasMatches);
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java
index cad2be2ddc20..2607ebf0557b 100644
--- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java
+++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/RestorePreviousSettingsAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * 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.
@@ -39,8 +39,7 @@ public class RestorePreviousSettingsAction extends EditorHeaderAction implements
public RestorePreviousSettingsAction(EditorSearchComponent editorSearchComponent, JTextComponent textField) {
super(editorSearchComponent);
myTextField = textField;
- registerShortcutsForComponent(Collections.<Shortcut>singletonList(SHORTCUT),
- textField, this);
+ registerShortcutsForComponent(Collections.<Shortcut>singletonList(SHORTCUT), textField);
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java
new file mode 100644
index 000000000000..0e52566f6fbc
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SelectAllAction.java
@@ -0,0 +1,53 @@
+/*
+ * 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.find.editorHeaderActions;
+
+import com.intellij.find.EditorSearchComponent;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.util.containers.ContainerUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SelectAllAction extends EditorHeaderAction implements DumbAware {
+ public SelectAllAction(EditorSearchComponent editorSearchComponent) {
+ super(editorSearchComponent);
+
+ copyFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_SELECT_ALL_OCCURRENCES));
+ getTemplatePresentation().setIcon(AllIcons.Actions.Selectall);
+
+ List<Shortcut> shortcuts = new ArrayList<Shortcut>();
+ ContainerUtil.addAll(shortcuts, getShortcutSet().getShortcuts());
+ ContainerUtil.addAll(shortcuts, CommonShortcuts.ALT_ENTER.getShortcuts());
+ registerShortcutsForComponent(shortcuts, editorSearchComponent.getSearchField());
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ getEditorSearchComponent().selectAllOccurrences();
+ getEditorSearchComponent().close();
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ boolean isFind = !getEditorSearchComponent().getFindModel().isReplaceState();
+ boolean hasMatches = getEditorSearchComponent().hasMatches();
+ e.getPresentation().setVisible(isFind);
+ e.getPresentation().setEnabled(isFind && hasMatches);
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java
index 23f14c5eb0b4..e4570b7379bf 100644
--- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java
+++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java
@@ -47,6 +47,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.ex.VirtualFileManagerEx;
import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.ui.content.Content;
@@ -54,6 +55,7 @@ import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewManager;
import com.intellij.usages.ConfigurableUsageTarget;
import com.intellij.usages.FindUsagesProcessPresentation;
+import com.intellij.usages.UsageView;
import com.intellij.usages.UsageViewPresentation;
import com.intellij.util.Function;
import com.intellij.util.PatternUtil;
@@ -324,7 +326,7 @@ public class FindInProjectUtil {
return processPresentation;
}
- public static class StringUsageTarget implements ConfigurableUsageTarget, ItemPresentation {
+ public static class StringUsageTarget implements ConfigurableUsageTarget, ItemPresentation, TypeSafeDataProvider {
@NotNull protected final Project myProject;
@NotNull protected final FindModel myFindModel;
@@ -423,5 +425,12 @@ public class FindInProjectUtil {
public KeyboardShortcut getShortcut() {
return ActionManager.getInstance().getKeyboardShortcut("FindInPath");
}
+
+ @Override
+ public void calcData(DataKey key, DataSink sink) {
+ if (key == UsageView.USAGE_SCOPE) {
+ sink.put(UsageView.USAGE_SCOPE, GlobalSearchScope.allScope(myProject));
+ }
+ }
}
}
diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java
index c20b5925721d..4ba97e0151e5 100644
--- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java
+++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * 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.
@@ -121,7 +121,7 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search
}
highlightUsages();
- updateCursorHighlighting(false);
+ updateCursorHighlighting();
if (myInSmartUpdate) {
clearUnusedHightlighters();
myInSmartUpdate = false;
@@ -218,9 +218,9 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search
}
@Override
- public void cursorMoved(boolean toChangeSelection) {
+ public void cursorMoved() {
updateInSelectionHighlighters();
- updateCursorHighlighting(toChangeSelection);
+ updateCursorHighlighting();
}
@Override
@@ -228,14 +228,7 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search
dumpState();
}
- @Override
- public void editorChanged(SearchResults sr, Editor oldEditor) {
- removeFromEditor();
- oldEditor.getDocument().removeDocumentListener(this);
- mySearchResults.getEditor().getDocument().addDocumentListener(this);
- }
-
- private void updateCursorHighlighting(boolean scroll) {
+ private void updateCursorHighlighting() {
hideBalloon();
if (myCursorHighlighter != null) {
@@ -245,7 +238,6 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search
final FindResult cursor = mySearchResults.getCursor();
Editor editor = mySearchResults.getEditor();
- SelectionModel selection = editor.getSelectionModel();
if (cursor != null) {
Set<RangeHighlighter> dummy = new HashSet<RangeHighlighter>();
highlightRange(cursor, new TextAttributes(null, null, Color.BLACK, EffectType.ROUNDED_BOX, 0), dummy);
@@ -253,33 +245,6 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search
myCursorHighlighter = dummy.iterator().next();
}
- if (scroll) {
- if (mySearchResults.getFindModel().isGlobal()) {
- FoldingModel foldingModel = editor.getFoldingModel();
- final FoldRegion[] allRegions = editor.getFoldingModel().getAllFoldRegions();
-
- foldingModel.runBatchFoldingOperation(new Runnable() {
- @Override
- public void run() {
- for (FoldRegion region : allRegions) {
- if (!region.isValid()) continue;
- if (cursor.intersects(TextRange.create(region))) {
- region.setExpanded(true);
- }
- }
- }
- });
- selection.setSelection(cursor.getStartOffset(), cursor.getEndOffset());
-
- editor.getCaretModel().moveToOffset(cursor.getEndOffset());
- editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
- } else {
- if (!SearchResults.insideVisibleArea(editor, cursor)) {
- LogicalPosition pos = editor.offsetToLogicalPosition(cursor.getStartOffset());
- editor.getScrollingModel().scrollTo(pos, ScrollType.CENTER);
- }
- }
- }
editor.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
@Override
public void run() {
@@ -496,6 +461,8 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search
new Processor<RangeHighlighterEx>() {
@Override
public boolean process(RangeHighlighterEx highlighter) {
+ if (!highlighter.getEditorFilter().avaliableIn(mySearchResults.getEditor())) return true;
+
TextAttributes textAttributes =
highlighter.getTextAttributes();
if (highlighter.getUserData(SEARCH_MARKER) != null &&
diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java
index 8368f1b2f2aa..94a6c3f9c1bc 100644
--- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java
+++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java
@@ -1,3 +1,18 @@
+/*
+ * 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.find.impl.livePreview;
import com.intellij.find.*;
@@ -83,9 +98,9 @@ public class LivePreviewController implements LivePreview.Delegate, FindUtil.Rep
public void moveCursor(SearchResults.Direction direction) {
if (direction == SearchResults.Direction.UP) {
- mySearchResults.prevOccurrence();
+ mySearchResults.prevOccurrence(false);
} else {
- mySearchResults.nextOccurrence();
+ mySearchResults.nextOccurrence(false);
}
}
diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java
index dff4989bb2f6..39b17dd2acc8 100644
--- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java
+++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SearchResults.java
@@ -21,9 +21,7 @@ import com.intellij.find.FindModel;
import com.intellij.find.FindResult;
import com.intellij.find.FindUtil;
import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.RangeMarker;
-import com.intellij.openapi.editor.SelectionModel;
+import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.fileEditor.FileDocumentManager;
@@ -38,6 +36,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.Stack;
import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -70,6 +69,7 @@ public class SearchResults implements DocumentListener {
private @Nullable FindResult myCursor;
+ @NotNull
private List<FindResult> myOccurrences = new ArrayList<FindResult>();
private final Set<RangeMarker> myExcluded = new HashSet<RangeMarker>();
@@ -90,6 +90,8 @@ public class SearchResults implements DocumentListener {
private final Stack<Pair<FindModel, FindResult>> myCursorPositions = new Stack<Pair<FindModel, FindResult>>();
+ private final SelectionManager mySelectionManager = new SelectionManager(this);
+
public SearchResults(Editor editor, Project project) {
myEditor = editor;
myProject = project;
@@ -127,9 +129,8 @@ public class SearchResults implements DocumentListener {
public void exclude(FindResult occurrence) {
boolean include = false;
- final TextRange r = occurrence;
for (RangeMarker rangeMarker : myExcluded) {
- if (TextRange.areSegmentsEqual(rangeMarker, r)) {
+ if (TextRange.areSegmentsEqual(rangeMarker, occurrence)) {
myExcluded.remove(rangeMarker);
rangeMarker.dispose();
include = true;
@@ -137,7 +138,7 @@ public class SearchResults implements DocumentListener {
}
}
if (!include) {
- myExcluded.add(myEditor.getDocument().createRangeMarker(r.getStartOffset(), r.getEndOffset(), true));
+ myExcluded.add(myEditor.getDocument().createRangeMarker(occurrence.getStartOffset(), occurrence.getEndOffset(), true));
}
notifyChanged();
}
@@ -149,8 +150,7 @@ public class SearchResults implements DocumentListener {
public interface SearchResultsListener {
void searchResultsUpdated(SearchResults sr);
- void editorChanged(SearchResults sr, Editor oldEditor);
- void cursorMoved(boolean toChangeSelection);
+ void cursorMoved();
void updateFinished();
}
@@ -175,6 +175,7 @@ public class SearchResults implements DocumentListener {
return myCursor;
}
+ @NotNull
public List<FindResult> getOccurrences() {
return myOccurrences;
}
@@ -184,19 +185,7 @@ public class SearchResults implements DocumentListener {
return myProject;
}
- public synchronized void setEditor(Editor editor) {
- Editor oldOne = myEditor;
- myEditor = editor;
- notifyEditorChanged(oldOne);
- }
-
- private void notifyEditorChanged(Editor oldOne) {
- for (SearchResultsListener listener : myListeners) {
- listener.editorChanged(this, oldOne);
- }
- }
-
- public synchronized Editor getEditor() {
+ public Editor getEditor() {
return myEditor;
}
@@ -334,7 +323,7 @@ public class SearchResults implements DocumentListener {
myEditor.getDocument().removeDocumentListener(this);
}
- private void searchCompleted(List<FindResult> occurrences, Editor editor, @Nullable FindModel findModel,
+ private void searchCompleted(@NotNull List<FindResult> occurrences, Editor editor, @Nullable FindModel findModel,
boolean toChangeSelection, @Nullable TextRange next, int stamp) {
if (stamp < myLastUpdatedStamp){
return;
@@ -344,7 +333,7 @@ public class SearchResults implements DocumentListener {
return;
}
myOccurrences = occurrences;
- final TextRange oldCursorRange = myCursor != null ? myCursor : null;
+ final TextRange oldCursorRange = myCursor;
Collections.sort(myOccurrences, new Comparator<FindResult>() {
@Override
public int compare(FindResult findResult, FindResult findResult1) {
@@ -357,7 +346,10 @@ public class SearchResults implements DocumentListener {
updateExcluded();
notifyChanged();
if (oldCursorRange == null || myCursor == null || !myCursor.equals(oldCursorRange)) {
- notifyCursorMoved(toChangeSelection);
+ if (toChangeSelection) {
+ mySelectionManager.updateSelection(true, true);
+ }
+ notifyCursorMoved();
}
dumpIfNeeded();
}
@@ -389,7 +381,7 @@ public class SearchResults implements DocumentListener {
myCursor = firstOccurrenceAfterOffset(oldCursorRange.getEndOffset());
} else {
if (justReplaced) {
- nextOccurrence(false, next, false, justReplaced);
+ nextOccurrence(false, next, false, true, false);
} else {
FindResult afterCaret = oldCursorRange == null ? firstOccurrenceAtOrAfterCaret() : firstOccurrenceAfterCaret();
if (afterCaret != null) {
@@ -405,7 +397,7 @@ public class SearchResults implements DocumentListener {
}
}
if (!justReplaced && myCursor == null && hasMatches()) {
- nextOccurrence(true, oldCursorRange, false, false);
+ nextOccurrence(true, oldCursorRange, false, false, false);
}
if (toPush && myCursor != null){
push();
@@ -445,6 +437,13 @@ public class SearchResults implements DocumentListener {
return occurrence;
}
}
+ int selectionStartOffset = getEditor().getSelectionModel().getSelectionStart();
+ int selectionEndOffset = getEditor().getSelectionModel().getSelectionEnd();
+ for (FindResult occurrence : myOccurrences) {
+ if (selectionEndOffset >= occurrence.getEndOffset() && selectionStartOffset <= occurrence.getStartOffset()) {
+ return occurrence;
+ }
+ }
return firstOccurrenceAfterCaret();
}
@@ -462,25 +461,6 @@ public class SearchResults implements DocumentListener {
}
@Nullable
- private FindResult firstVisibleOccurrence() {
- int offset = Integer.MAX_VALUE;
- FindResult firstOccurrence = null;
- FindResult firstVisibleOccurrence = null;
- for (FindResult o : getOccurrences()) {
- if (insideVisibleArea(myEditor, o)) {
- if (firstVisibleOccurrence == null || o.getStartOffset() < firstVisibleOccurrence.getStartOffset()) {
- firstVisibleOccurrence = o;
- }
- }
- if (o.getStartOffset() < offset) {
- offset = o.getStartOffset();
- firstOccurrence = o;
- }
- }
- return firstVisibleOccurrence != null ? firstVisibleOccurrence : firstOccurrence;
- }
-
- @Nullable
private FindResult firstOccurrenceBeforeCaret() {
int offset = getEditor().getCaretModel().getOffset();
return firstOccurrenceBeforeOffset(offset);
@@ -554,32 +534,45 @@ public class SearchResults implements DocumentListener {
return null;
}
- public void prevOccurrence() {
- FindResult next = null;
- if (myFindModel == null) return;
- boolean processFromTheBeginning = false;
- if (myNotFoundState) {
- myNotFoundState = false;
- processFromTheBeginning = true;
- }
- if (!myFindModel.isGlobal()) {
- if (myCursor != null) {
- next = prevOccurrence(myCursor);
+ public void prevOccurrence(boolean findSelected) {
+ if (findSelected) {
+ if (mySelectionManager.removeCurrentSelection()) {
+ myCursor = firstOccurrenceAtOrAfterCaret();
}
- } else {
- next = firstOccurrenceBeforeCaret();
- }
- if (next == null) {
- if (processFromTheBeginning) {
- if (hasMatches()) {
- next = getOccurrences().get(getOccurrences().size()-1);
+ else {
+ myCursor = null;
+ }
+ notifyCursorMoved();
+ }
+ else {
+ FindResult next = null;
+ if (myFindModel == null) return;
+ boolean processFromTheBeginning = false;
+ if (myNotFoundState) {
+ myNotFoundState = false;
+ processFromTheBeginning = true;
+ }
+ if (!myFindModel.isGlobal()) {
+ if (myCursor != null) {
+ next = prevOccurrence(myCursor);
+ }
+ }
+ else {
+ next = firstOccurrenceBeforeCaret();
+ }
+ if (next == null) {
+ if (processFromTheBeginning) {
+ if (hasMatches()) {
+ next = getOccurrences().get(getOccurrences().size() - 1);
+ }
+ }
+ else {
+ setNotFoundState(false);
}
- } else {
- setNotFoundState(false);
}
- }
- moveCursorTo(next);
+ moveCursorTo(next, false);
+ }
push();
}
@@ -587,13 +580,13 @@ public class SearchResults implements DocumentListener {
myCursorPositions.push(Pair.create(myFindModel, myCursor));
}
- public void nextOccurrence() {
+ public void nextOccurrence(boolean retainOldSelection) {
if (myFindModel == null) return;
- nextOccurrence(false, myCursor != null ? myCursor : null, true, false);
+ nextOccurrence(false, myCursor, true, false, retainOldSelection);
push();
}
- private void nextOccurrence(boolean processFromTheBeginning, TextRange cursor, boolean toNotify, boolean justReplaced) {
+ private void nextOccurrence(boolean processFromTheBeginning, TextRange cursor, boolean toNotify, boolean justReplaced, boolean retainOldSelection) {
FindResult next;
if (myNotFoundState) {
myNotFoundState = false;
@@ -614,22 +607,24 @@ public class SearchResults implements DocumentListener {
}
}
if (toNotify) {
- moveCursorTo(next);
+ moveCursorTo(next, retainOldSelection);
} else {
myCursor = next;
}
}
- public void moveCursorTo(FindResult next) {
- if (next != null) {
+ public void moveCursorTo(FindResult next, boolean retainOldSelection) {
+ if (next != null && !mySelectionManager.isSelected(next)) {
+ retainOldSelection &= (myCursor != null && mySelectionManager.isSelected(myCursor));
myCursor = next;
- notifyCursorMoved(true);
+ mySelectionManager.updateSelection(!retainOldSelection, false);
+ notifyCursorMoved();
}
}
- private void notifyCursorMoved(boolean toChangeSelection) {
+ private void notifyCursorMoved() {
for (SearchResultsListener listener : myListeners) {
- listener.cursorMoved(toChangeSelection);
+ listener.cursorMoved();
}
}
}
diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java
new file mode 100644
index 000000000000..50f37927c506
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/SelectionManager.java
@@ -0,0 +1,90 @@
+/*
+ * 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.find.impl.livePreview;
+
+import com.intellij.find.FindResult;
+import com.intellij.find.FindUtil;
+import com.intellij.openapi.editor.*;
+import com.intellij.openapi.util.TextRange;
+import org.jetbrains.annotations.NotNull;
+
+public class SelectionManager {
+ @NotNull private final SearchResults mySearchResults;
+
+ public SelectionManager(@NotNull SearchResults results) {
+ mySearchResults = results;
+ }
+
+ public void updateSelection(boolean removePreviousSelection, boolean removeAllPreviousSelections) {
+ Editor editor = mySearchResults.getEditor();
+ if (removeAllPreviousSelections) {
+ editor.getCaretModel().removeSecondaryCarets();
+ }
+ final FindResult cursor = mySearchResults.getCursor();
+ if (cursor == null) {
+ return;
+ }
+ if (mySearchResults.getFindModel().isGlobal()) {
+ if (removePreviousSelection || removeAllPreviousSelections) {
+ FoldingModel foldingModel = editor.getFoldingModel();
+ final FoldRegion[] allRegions = editor.getFoldingModel().getAllFoldRegions();
+
+ foldingModel.runBatchFoldingOperation(new Runnable() {
+ @Override
+ public void run() {
+ for (FoldRegion region : allRegions) {
+ if (!region.isValid()) continue;
+ if (cursor.intersects(TextRange.create(region))) {
+ region.setExpanded(true);
+ }
+ }
+ }
+ });
+ editor.getSelectionModel().setSelection(cursor.getStartOffset(), cursor.getEndOffset());
+ editor.getCaretModel().moveToOffset(cursor.getEndOffset());
+ }
+ else {
+ FindUtil.selectSearchResultInEditor(editor, cursor, -1);
+ }
+ editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
+ } else {
+ if (!SearchResults.insideVisibleArea(editor, cursor)) {
+ LogicalPosition pos = editor.offsetToLogicalPosition(cursor.getStartOffset());
+ editor.getScrollingModel().scrollTo(pos, ScrollType.CENTER);
+ }
+ }
+ }
+
+ public boolean removeCurrentSelection() {
+ Editor editor = mySearchResults.getEditor();
+ CaretModel caretModel = editor.getCaretModel();
+ Caret primaryCaret = caretModel.getPrimaryCaret();
+ if (caretModel.getCaretCount() > 1) {
+ caretModel.removeCaret(primaryCaret);
+ return true;
+ }
+ else {
+ primaryCaret.moveToOffset(primaryCaret.getSelectionStart());
+ primaryCaret.removeSelection();
+ return false;
+ }
+ }
+
+ public boolean isSelected(@NotNull FindResult result) {
+ Editor editor = mySearchResults.getEditor();
+ return editor.getCaretModel().getCaretAt(editor.offsetToVisualPosition(result.getEndOffset())) != null;
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java
index 90f2387a157a..7d3c7c649fd2 100644
--- a/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java
+++ b/platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java
@@ -16,6 +16,7 @@
package com.intellij.formatting;
+import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
@@ -25,6 +26,8 @@ import com.intellij.openapi.editor.impl.BulkChangesMerger;
import com.intellij.openapi.editor.impl.TextChangeImpl;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.util.ui.UIUtil;
@@ -145,6 +148,7 @@ class FormatProcessor {
private WhiteSpace myLastWhiteSpace;
private boolean myDisposed;
private CommonCodeStyleSettings.IndentOptions myJavaIndentOptions;
+ private final int myRightMargin;
@NotNull
private State myCurrentState;
@@ -172,6 +176,23 @@ class FormatProcessor {
mySettings = settings;
myDocument = docModel.getDocument();
myCurrentState = new WrapBlocksState(rootBlock, docModel, affectedRanges, interestingOffset);
+ myRightMargin = getRightMargin(rootBlock);
+ }
+
+ private int getRightMargin(Block rootBlock) {
+ if (rootBlock instanceof ASTBlock) {
+ ASTNode node = ((ASTBlock)rootBlock).getNode();
+ if (node != null) {
+ PsiElement psiElement = node.getPsi();
+ if (psiElement.isValid()) {
+ PsiFile psiFile = psiElement.getContainingFile();
+ if (psiFile != null) {
+ return mySettings.getRightMargin(psiFile.getViewProvider().getBaseLanguage());
+ }
+ }
+ }
+ }
+ return mySettings.RIGHT_MARGIN;
}
private LeafBlockWrapper getLastBlock() {
@@ -813,7 +834,7 @@ class FormatProcessor {
*/
private boolean lineOver() {
return !myCurrentBlock.containsLineFeeds() &&
- CoreFormatterUtil.getStartColumn(myCurrentBlock) + myCurrentBlock.getLength() > mySettings.RIGHT_MARGIN;
+ CoreFormatterUtil.getStartColumn(myCurrentBlock) + myCurrentBlock.getLength() > myRightMargin;
}
private void defineAlignOffset(final LeafBlockWrapper block) {
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java
index c939787fb632..e57d1eba05ef 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java
@@ -20,9 +20,8 @@ import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.ide.DataManager;
import com.intellij.ide.ui.search.OptionDescription;
import com.intellij.ide.util.gotoByName.ChooseByNamePopup;
-import com.intellij.ide.util.gotoByName.DefaultChooseByNameItemProvider;
+import com.intellij.ide.util.gotoByName.GotoActionItemProvider;
import com.intellij.ide.util.gotoByName.GotoActionModel;
-import com.intellij.ide.util.gotoByName.MatchResult;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.application.ApplicationManager;
@@ -33,27 +32,11 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiFile;
-import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
public class GotoActionAction extends GotoActionBase implements DumbAware {
- public static final Comparator<MatchResult> ELEMENTS_COMPARATOR = new Comparator<MatchResult>() {
- @Override
- public int compare(@NotNull MatchResult o1, @NotNull MatchResult o2) {
- if (o1.elementName.equals(GotoActionModel.INTENTIONS_KEY)) return -1;
- if (o2.elementName.equals(GotoActionModel.INTENTIONS_KEY)) return 1;
-
- if (o1.elementName.equals(GotoActionModel.SETTINGS_KEY)) return 1;
- if (o2.elementName.equals(GotoActionModel.SETTINGS_KEY)) return -1;
-
- return o1.elementName.compareToIgnoreCase(o2.elementName);
- }
- };
@Override
public void gotoActionPerformed(final AnActionEvent e) {
@@ -68,7 +51,7 @@ public class GotoActionAction extends GotoActionBase implements DumbAware {
@Override
public void elementChosen(ChooseByNamePopup popup, final Object element) {
final String enteredText = popup.getEnteredText();
- openOptionOrPerformAction(element, enteredText, project, component, e);
+ openOptionOrPerformAction(((GotoActionModel.MatchedValue)element).value, enteredText, project, component, e);
}
};
@@ -79,12 +62,7 @@ public class GotoActionAction extends GotoActionBase implements DumbAware {
private static ChooseByNamePopup createPopup(Project project, GotoActionModel model, String initialText, int initialIndex) {
return ChooseByNamePopup.createPopup(project,
model,
- new DefaultChooseByNameItemProvider(null) {
- @Override
- protected void sortNamesList(@NotNull String namePattern, @NotNull List<MatchResult> namesList) {
- Collections.sort(namesList, ELEMENTS_COMPARATOR);
- }
- },
+ new GotoActionItemProvider(model),
initialText,
false,
initialIndex);
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java
new file mode 100644
index 000000000000..6d734d52a584
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedFileAction.java
@@ -0,0 +1,46 @@
+/*
+ * 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.ide.actions;
+
+import com.intellij.navigation.GotoRelatedItem;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.ui.popup.JBPopup;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+/**
+ * @deprecated API compatibility. Utility methods will be moved to NavigationUtil
+ * @author gregsh
+ */
+public class GotoRelatedFileAction {
+
+ /**
+ * @deprecated This method will be moved to NavigationUtil
+ */
+ public static JBPopup createPopup(List<? extends GotoRelatedItem> items, final String title) {
+ return GotoRelatedSymbolAction.createPopup(items, title);
+ }
+
+ /**
+ * @deprecated This method will be moved to NavigationUtil
+ */
+ public static List<GotoRelatedItem> getItems(@NotNull PsiElement contextElement, @Nullable DataContext dataContext) {
+ return GotoRelatedSymbolAction.getItems(contextElement, dataContext);
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedSymbolAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedSymbolAction.java
index f333c0f35db8..2870f806ab8a 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedSymbolAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoRelatedSymbolAction.java
@@ -42,6 +42,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import java.awt.*;
@@ -56,26 +57,23 @@ public class GotoRelatedSymbolAction extends AnAction {
@Override
public void update(AnActionEvent e) {
- PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
- PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(e.getDataContext());
- e.getPresentation().setEnabled(element != null || file != null);
+ PsiElement element = getContextElement(e.getDataContext());
+ e.getPresentation().setEnabled(element != null);
}
@Override
public void actionPerformed(AnActionEvent e) {
- DataContext dataContext = e.getDataContext();
- PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
- Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
- PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
- if (element == null && file == null) return;
+ PsiElement element = getContextElement(e.getDataContext());
+ if (element == null) return;
- List<GotoRelatedItem> items = element == null? getItems(file, editor, dataContext) : getItems(element, dataContext);
+ List<GotoRelatedItem> items = getItems(element, e.getDataContext());
if (items.isEmpty()) return;
+
if (items.size() == 1 && items.get(0).getElement() != null) {
items.get(0).navigate();
return;
}
- createPopup(items, "Choose Target").showInBestPositionFor(dataContext);
+ createPopup(items, "Choose Target").showInBestPositionFor(e.getDataContext());
}
public static JBPopup createPopup(final List<? extends GotoRelatedItem> items, final String title) {
@@ -268,8 +266,25 @@ public class GotoRelatedSymbolAction extends AnAction {
return popup;
}
+ @TestOnly
@NotNull
public static List<GotoRelatedItem> getItems(@NotNull PsiFile psiFile, @Nullable Editor editor, @Nullable DataContext dataContext) {
+ return getItems(getContextElement(psiFile, editor), dataContext);
+ }
+
+ @Nullable
+ private static PsiElement getContextElement(@NotNull DataContext dataContext) {
+ PsiFile file = CommonDataKeys.PSI_FILE.getData(dataContext);
+ Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
+ PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
+ if (file != null && editor != null) {
+ return getContextElement(file, editor);
+ }
+ return element;
+ }
+
+ @NotNull
+ private static PsiElement getContextElement(@NotNull PsiFile psiFile, @Nullable Editor editor) {
PsiElement contextElement = psiFile;
if (editor != null) {
PsiElement element = psiFile.findElementAt(editor.getCaretModel().getOffset());
@@ -277,7 +292,7 @@ public class GotoRelatedSymbolAction extends AnAction {
contextElement = element;
}
}
- return getItems(contextElement, dataContext);
+ return contextElement;
}
@NotNull
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java
index 996601065278..ae7ee4363247 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/actions/SearchEverywhereAction.java
@@ -56,10 +56,9 @@ import com.intellij.openapi.fileEditor.impl.EditorHistoryManager;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.keymap.MacKeymapUtil;
+import com.intellij.openapi.keymap.impl.ModifierKeyDoubleClickHandler;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.SearchableConfigurable;
-import com.intellij.openapi.options.ex.IdeConfigurablesGroup;
-import com.intellij.openapi.options.ex.ProjectConfigurablesGroup;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
@@ -96,6 +95,7 @@ import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.popup.AbstractPopup;
import com.intellij.ui.popup.PopupPositionManager;
import com.intellij.util.*;
+import com.intellij.util.text.Matcher;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.StatusText;
import com.intellij.util.ui.UIUtil;
@@ -138,9 +138,8 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
MySearchTextField myPopupField;
private volatile GotoClassModel2 myClassModel;
private volatile GotoFileModel myFileModel;
- private volatile GotoActionModel myActionModel;
+ private volatile GotoActionItemProvider myActionProvider;
private volatile GotoSymbolModel2 mySymbolsModel;
- private volatile String[] myActions;
private Component myFocusComponent;
private JBPopup myPopup;
private Map<String, String> myConfigurables = new HashMap<String, String>();
@@ -153,106 +152,25 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
private Component myContextComponent;
private CalcThread myCalcThread;
private static AtomicBoolean ourShiftIsPressed = new AtomicBoolean(false);
- private final static Couple<AtomicBoolean> ourPressed = Couple.of(new AtomicBoolean(false), new AtomicBoolean(false));
- private final static Couple<AtomicBoolean> ourReleased = Couple.of(new AtomicBoolean(false), new AtomicBoolean(false));
- private static AtomicBoolean ourOtherKeyWasPressed = new AtomicBoolean(false);
- private static AtomicLong ourLastTimePressed = new AtomicLong(0);
private static AtomicBoolean showAll = new AtomicBoolean(false);
private volatile ActionCallback myCurrentWorker = ActionCallback.DONE;
private int myHistoryIndex = 0;
boolean mySkipFocusGain = false;
static {
+ ModifierKeyDoubleClickHandler.getInstance().registerAction(IdeActions.ACTION_SEARCH_EVERYWHERE, KeyEvent.VK_SHIFT, -1);
+
IdeEventQueue.getInstance().addPostprocessor(new IdeEventQueue.EventDispatcher() {
@Override
public boolean dispatch(AWTEvent event) {
if (event instanceof KeyEvent) {
- final KeyEvent keyEvent = (KeyEvent)event;
- final int keyCode = keyEvent.getKeyCode();
-
+ final int keyCode = ((KeyEvent)event).getKeyCode();
if (keyCode == KeyEvent.VK_SHIFT) {
ourShiftIsPressed.set(event.getID() == KeyEvent.KEY_PRESSED);
-
- if (keyEvent.isControlDown() || keyEvent.isAltDown() || keyEvent.isMetaDown()) {
- resetState();
- return false;
- }
- if (ourOtherKeyWasPressed.get() && System.currentTimeMillis() - ourLastTimePressed.get() < 500) {
- resetState();
- return false;
- }
- ourOtherKeyWasPressed.set(false);
- if (ourPressed.first.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 500) {
- resetState();
- }
- handleShift((KeyEvent)event);
- return false;
- } else {
- ourLastTimePressed.set(System.currentTimeMillis());
- ourOtherKeyWasPressed.set(true);
- if (keyCode == KeyEvent.VK_ESCAPE || keyCode == KeyEvent.VK_TAB) {
- ourLastTimePressed.set(0);
- }
}
- resetState();
}
return false;
}
-
- private void resetState() {
- ourPressed.first.set(false);
- ourPressed.second.set(false);
- ourReleased.first.set(false);
- ourReleased.second.set(false);
- }
-
- private void handleShift(KeyEvent event) {
- if (ourPressed.first.get() && System.currentTimeMillis() - ourLastTimePressed.get() > 300) {
- resetState();
- return;
- }
-
- if (event.getID() == KeyEvent.KEY_PRESSED) {
- if (!ourPressed.first.get()) {
- resetState();
- ourPressed.first.set(true);
- ourLastTimePressed.set(System.currentTimeMillis());
- return;
- } else {
- if (ourPressed.first.get() && ourReleased.first.get()) {
- ourPressed.second.set(true);
- ourLastTimePressed.set(System.currentTimeMillis());
- return;
- }
- }
- } else if (event.getID() == KeyEvent.KEY_RELEASED) {
- if (ourPressed.first.get() && !ourReleased.first.get()) {
- ourReleased.first.set(true);
- ourLastTimePressed.set(System.currentTimeMillis());
- return;
- } else if (ourPressed.first.get() && ourReleased.first.get() && ourPressed.second.get()) {
- resetState();
- run(event);
- return;
- }
- }
- resetState();
- }
-
- private void run(KeyEvent event) {
- final ActionManager actionManager = ActionManager.getInstance();
- final AnAction action = actionManager.getAction(IdeActions.ACTION_SEARCH_EVERYWHERE);
- if (KeymapManager.getInstance().getActiveKeymap().getShortcuts(IdeActions.ACTION_SEARCH_EVERYWHERE).length > 0) {
- return;
- }
- final AnActionEvent anActionEvent = new AnActionEvent(event,
- DataManager.getInstance().getDataContext(IdeFocusManager.findInstance().getFocusOwner()),
- ActionPlaces.MAIN_MENU,
- action.getTemplatePresentation(),
- actionManager,
- 0);
- action.actionPerformed(anActionEvent);
- }
}, null);
}
@@ -840,7 +758,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
if (split.length != 3 || text.equals(split[0])) {
continue;
}
- history.add(new HistoryItem(split[0], split[1], split[2]));
+ if (!StringUtil.isEmpty(split[0])) {
+ history.add(new HistoryItem(split[0], split[1], split[2]));
+ }
}
}
history.add(0, new HistoryItem(text, type == null ? null : type.name(), fqn));
@@ -1008,14 +928,18 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
Component cmp;
PsiFile file = null;
myLocationString = null;
+ String pattern = "*" + myPopupField.getText();
+ Matcher matcher = NameUtil.buildMatcher(pattern, 0, true, true, pattern.toLowerCase().equals(pattern));
if (isMoreItem(index)) {
cmp = More.get(isSelected);
} else if (value instanceof VirtualFile
&& myProject != null
&& (((VirtualFile)value).isDirectory()
|| (file = PsiManager.getInstance(myProject).findFile((VirtualFile)value)) != null)) {
+ myFileRenderer.setPatternMatcher(matcher);
cmp = myFileRenderer.getListCellRendererComponent(list, file == null ? value : file, index, isSelected, cellHasFocus);
} else if (value instanceof PsiElement) {
+ myPsiRenderer.setPatternMatcher(matcher);
cmp = myPsiRenderer.getListCellRendererComponent(list, value, index, isSelected, isSelected);
} else {
cmp = super.getListCellRendererComponent(list, value, index, isSelected, isSelected);
@@ -1185,16 +1109,6 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
return text;
}
- private void schedulePopupUpdate() {
- myUpdateAlarm.cancelAllRequests();
- myUpdateAlarm.addRequest(new Runnable() {
- @Override
- public void run() {
- updatePopupBounds();
- }
- }, 50);
- }
-
private static boolean isActionValue(Object o) {
return o instanceof GotoActionModel.ActionWrapper || o instanceof AnAction;
}
@@ -1353,21 +1267,16 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
private SearchResult getActionsOrSettings(final String pattern, final int max, final boolean actions) {
final SearchResult result = new SearchResult();
final MinusculeMatcher matcher = new MinusculeMatcher("*" +pattern, NameUtil.MatchingCaseSensitivity.NONE);
- if (myActions == null) {
- if (myActionModel == null) {
- myActionModel = createActionModel();
- }
- myActions = myActionModel.getNames(true);
+ if (myActionProvider == null) {
+ myActionProvider = createActionProvider();
}
- List<MatchResult> matches = collectResults(pattern, myActions, myActionModel);
-
- for (MatchResult o : matches) {
- check();
- Object[] objects = myActionModel.getElementsByName(o.elementName, true, pattern);
- for (Object object : objects) {
+ myActionProvider.filterElements(pattern, true, new Processor<GotoActionModel.MatchedValue>() {
+ @Override
+ public boolean process(GotoActionModel.MatchedValue matched) {
check();
- if (myListModel.contains(object)) continue;
+ Object object = matched.value;
+ if (myListModel.contains(object)) return true;
if (!actions && isSetting(object)) {
if (matcher.matches(getSettingText((OptionDescription)object))) {
@@ -1376,9 +1285,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
} else if (actions && !isToolWindowAction(object) && isActionValue(object)) {
result.add(object);
}
- if (result.size() == max) return result;
+ return result.size() <= max;
}
- }
+ });
+
return result;
}
@@ -1411,7 +1321,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
private synchronized void buildFiles(final String pattern) {
- final SearchResult files = getFiles(pattern, MAX_FILES);
+ final SearchResult files = getFiles(pattern, MAX_FILES, myFileChooseByName);
check();
@@ -1434,7 +1344,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
private synchronized void buildSymbols(final String pattern) {
- final SearchResult symbols = getSymbols(pattern, MAX_SYMBOLS);
+ final SearchResult symbols = getSymbols(pattern, MAX_SYMBOLS, mySymbolsChooseByName);
check();
if (symbols.size() > 0) {
@@ -1522,7 +1432,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
check();
- final SearchResult classes = getClasses(pattern, showAll.get(), MAX_CLASSES);
+ final SearchResult classes = getClasses(pattern, showAll.get(), MAX_CLASSES, myClassChooseByName);
check();
@@ -1544,10 +1454,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
}
- private SearchResult getSymbols(String pattern, final int max) {
+ private SearchResult getSymbols(String pattern, final int max, ChooseByNamePopup chooseByNamePopup) {
final SearchResult symbols = new SearchResult();
final GlobalSearchScope scope = GlobalSearchScope.projectScope(project);
- mySymbolsChooseByName.getProvider().filterElements(mySymbolsChooseByName, pattern, false,
+ chooseByNamePopup.getProvider().filterElements(chooseByNamePopup, pattern, false,
myProgressIndicator, new Processor<Object>() {
@Override
public boolean process(Object o) {
@@ -1567,9 +1477,12 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
return symbols;
}
- private SearchResult getClasses(String pattern, boolean includeLibs, final int max) {
+ private SearchResult getClasses(String pattern, boolean includeLibs, final int max, ChooseByNamePopup chooseByNamePopup) {
final SearchResult classes = new SearchResult();
- myClassChooseByName.getProvider().filterElements(myClassChooseByName, pattern, includeLibs,
+ if (chooseByNamePopup == null) {
+ return classes;
+ }
+ chooseByNamePopup.getProvider().filterElements(chooseByNamePopup, pattern, includeLibs,
myProgressIndicator, new Processor<Object>() {
@Override
public boolean process(Object o) {
@@ -1584,15 +1497,18 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
}
});
if (!includeLibs && classes.isEmpty()) {
- return getClasses(pattern, true, max);
+ return getClasses(pattern, true, max, chooseByNamePopup);
}
return classes;
}
- private SearchResult getFiles(final String pattern, final int max) {
+ private SearchResult getFiles(final String pattern, final int max, ChooseByNamePopup chooseByNamePopup) {
final SearchResult files = new SearchResult();
+ if (chooseByNamePopup == null) {
+ return files;
+ }
final GlobalSearchScope scope = GlobalSearchScope.projectScope(project);
- myFileChooseByName.getProvider().filterElements(myFileChooseByName, pattern, true,
+ chooseByNamePopup.getProvider().filterElements(chooseByNamePopup, pattern, true,
myProgressIndicator, new Processor<Object>() {
@Override
public boolean process(Object o) {
@@ -1786,10 +1702,9 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
myClassChooseByName = ChooseByNamePopup.createPopup(project, myClassModel, (PsiElement)null);
mySymbolsChooseByName = ChooseByNamePopup.createPopup(project, mySymbolsModel, (PsiElement)null);
project.putUserData(ChooseByNamePopup.CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, null);
- myActionModel = createActionModel();
+ myActionProvider = createActionProvider();
myConfigurables.clear();
- fillConfigurablesIds(null, new IdeConfigurablesGroup().getConfigurables());
- fillConfigurablesIds(null, new ProjectConfigurablesGroup(project).getConfigurables());
+ fillConfigurablesIds(null, ShowSettingsUtilImpl.getConfigurables(project, true));
}
}
@@ -1797,14 +1712,16 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
buildRecentFiles("");
}
- private GotoActionModel createActionModel() {
- return new GotoActionModel(project, myFocusComponent, myEditor, myFile) {
+ private GotoActionItemProvider createActionProvider() {
+ GotoActionModel model = new GotoActionModel(project, myFocusComponent, myEditor, myFile) {
@Override
protected MatchMode actionMatches(String pattern, @NotNull AnAction anAction) {
- return NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE)
- .matches(anAction.getTemplatePresentation().getText()) ? MatchMode.NAME : MatchMode.NONE;
+ String text = anAction.getTemplatePresentation().getText();
+ return text != null && NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE)
+ .matches(text) ? MatchMode.NAME : MatchMode.NONE;
}
};
+ return new GotoActionItemProvider(model);
}
@SuppressWarnings("SSBasedInspection")
@@ -1880,57 +1797,6 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
});
}
- private List<MatchResult> collectResults(String pattern, String[] names, final ChooseByNameModel model) {
- if (names == null) return Collections.emptyList();
- pattern = ChooseByNamePopup.getTransformedPattern(pattern, model);
- pattern = DefaultChooseByNameItemProvider.getNamePattern(model, pattern);
- if (model != myFileModel && model != myActionModel && !pattern.startsWith("*") && pattern.length() > 1) {
- pattern = "*" + pattern;
- }
- final ArrayList<MatchResult> results = new ArrayList<MatchResult>();
- final String p = pattern;
- MinusculeMatcher matcher = new MinusculeMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE) {
- @Override
- public boolean matches(@NotNull String name) {
- if (!(model instanceof GotoActionModel) && p.indexOf(' ') > 0 && name.trim().indexOf(' ') < 0) {
- return false;
- }
- return super.matches(name);
- }
- };
- MatchResult result;
-
- for (String name : names) {
- check();
- result = null;
- if (model instanceof CustomMatcherModel) {
- try {
- result = ((CustomMatcherModel)model).matches(name, pattern) ? new MatchResult(name, 0, true) : null;
- if (result != null && model == myActionModel) {
- ((CustomMatcherModel)model).matches(name, pattern);
- }
- }
- catch (Exception ignore) {
- }
- }
- else {
- result = matcher.matches(name) ? new MatchResult(name, matcher.matchingDegree(name), matcher.isStartMatch(name)) : null;
- }
-
- if (result != null) {
- results.add(result);
- }
- }
-
- Collections.sort(results, new Comparator<MatchResult>() {
- @Override
- public int compare(MatchResult o1, MatchResult o2) {
- return o1.compareTo(o2);
- }
- });
- return results;
- }
-
public ActionCallback cancel() {
myProgressIndicator.cancel();
myDone.setRejected();
@@ -1945,10 +1811,10 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
public void run() {
try {
final SearchResult result
- = id == WidgetID.CLASSES ? getClasses(pattern, showAll.get(), DEFAULT_MORE_STEP_COUNT)
- : id == WidgetID.FILES ? getFiles(pattern, DEFAULT_MORE_STEP_COUNT)
+ = id == WidgetID.CLASSES ? getClasses(pattern, showAll.get(), DEFAULT_MORE_STEP_COUNT, myClassChooseByName)
+ : id == WidgetID.FILES ? getFiles(pattern, DEFAULT_MORE_STEP_COUNT, myFileChooseByName)
: id == WidgetID.RUN_CONFIGURATIONS ? getConfigurations(pattern, DEFAULT_MORE_STEP_COUNT)
- : id == WidgetID.SYMBOLS ? getSymbols(pattern, DEFAULT_MORE_STEP_COUNT)
+ : id == WidgetID.SYMBOLS ? getSymbols(pattern, DEFAULT_MORE_STEP_COUNT, mySymbolsChooseByName)
: id == WidgetID.ACTIONS ? getActionsOrSettings(pattern, DEFAULT_MORE_STEP_COUNT, true)
: id == WidgetID.SETTINGS ? getActionsOrSettings(pattern, DEFAULT_MORE_STEP_COUNT, false)
: new SearchResult();
@@ -2030,8 +1896,7 @@ public class SearchEverywhereAction extends AnAction implements CustomComponentA
if (lock != null) {
synchronized (lock) {
myClassModel = null;
- myActionModel = null;
- myActions = null;
+ myActionProvider = null;
mySymbolsModel = null;
myConfigurables.clear();
myFocusComponent = null;
diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java
index 58bef64556c2..e2c79cffef46 100644
--- a/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java
+++ b/platform/lang-impl/src/com/intellij/ide/projectView/ProjectViewPsiTreeChangeListener.java
@@ -125,8 +125,10 @@ public abstract class ProjectViewPsiTreeChangeListener extends PsiTreeChangeAdap
updater.addSubtreeToUpdate(rootNode);
return;
}
-
- updater.addSubtreeToUpdateByElement(element);
+ final PsiElement parent = element.getParent();
+ if (parent == null || !updater.addSubtreeToUpdateByElement(parent)) {
+ updater.addSubtreeToUpdateByElement(element);
+ }
}
else if (propertyName.equals(PsiTreeChangeEvent.PROP_FILE_TYPES)){
updater.addSubtreeToUpdate(rootNode);
diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkExcludeRootAction.java b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkExcludeRootAction.java
index 85964857c5d0..2e55b4aee11a 100644
--- a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkExcludeRootAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkExcludeRootAction.java
@@ -21,6 +21,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
@@ -32,11 +33,13 @@ public class MarkExcludeRootAction extends MarkRootActionBase {
public void actionPerformed(AnActionEvent e) {
VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY);
- String message = files.length == 1 ? FileUtil.toSystemDependentName(files[0].getPath()) : files.length + " selected files";
- final int rc = Messages.showOkCancelDialog(e.getData(CommonDataKeys.PROJECT), getPromptText(message), "Mark as Excluded",
- Messages.getQuestionIcon());
- if (rc != Messages.OK) {
- return;
+ if (Registry.is("ide.hide.excluded.files")) {
+ String message = files.length == 1 ? FileUtil.toSystemDependentName(files[0].getPath()) : files.length + " selected files";
+ final int rc = Messages.showOkCancelDialog(e.getData(CommonDataKeys.PROJECT), getPromptText(message), "Mark as Excluded",
+ Messages.getQuestionIcon());
+ if (rc != Messages.OK) {
+ return;
+ }
}
super.actionPerformed(e);
}
diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java
index 815c3e8815ac..ac2326da6dac 100644
--- a/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java
+++ b/platform/lang-impl/src/com/intellij/ide/projectView/actions/MarkRootActionBase.java
@@ -22,7 +22,9 @@ import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
+import com.intellij.openapi.roots.impl.DirectoryIndex;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
@@ -38,23 +40,24 @@ import java.util.List;
public abstract class MarkRootActionBase extends DumbAwareAction {
@Override
public void actionPerformed(AnActionEvent e) {
- final Module module = e.getData(LangDataKeys.MODULE);
- VirtualFile[] vFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY);
- if (module == null || vFiles == null) {
+ VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY);
+ final Module module = getModule(e, files);
+ if (module == null) {
return;
}
+
final ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
- for (VirtualFile vFile : vFiles) {
- ContentEntry entry = findContentEntry(model, vFile);
+ for (VirtualFile file : files) {
+ ContentEntry entry = findContentEntry(model, file);
if (entry != null) {
final SourceFolder[] sourceFolders = entry.getSourceFolders();
for (SourceFolder sourceFolder : sourceFolders) {
- if (Comparing.equal(sourceFolder.getFile(), vFile)) {
+ if (Comparing.equal(sourceFolder.getFile(), file)) {
entry.removeSourceFolder(sourceFolder);
break;
}
}
- modifyRoots(vFile, entry);
+ modifyRoots(file, entry);
}
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@@ -66,7 +69,7 @@ public abstract class MarkRootActionBase extends DumbAwareAction {
});
}
- protected abstract void modifyRoots(VirtualFile vFile, ContentEntry entry);
+ protected abstract void modifyRoots(VirtualFile file, ContentEntry entry);
@Nullable
public static ContentEntry findContentEntry(@NotNull ModuleRootModel model, @NotNull VirtualFile vFile) {
@@ -82,21 +85,22 @@ public abstract class MarkRootActionBase extends DumbAwareAction {
@Override
public void update(AnActionEvent e) {
- Module module = e.getData(LangDataKeys.MODULE);
RootsSelection selection = getSelection(e);
- boolean enabled = module != null && (!selection.mySelectedRoots.isEmpty() || !selection.mySelectedDirectories.isEmpty()) && isEnabled(selection, module);
- e.getPresentation().setVisible(enabled);
- e.getPresentation().setEnabled(enabled);
+ doUpdate(e, e.getData(LangDataKeys.MODULE), selection);
+ }
+
+ protected void doUpdate(@NotNull AnActionEvent e, @Nullable Module module, @NotNull RootsSelection selection) {
+ boolean enabled = module != null && (!selection.mySelectedRoots.isEmpty() || !selection.mySelectedDirectories.isEmpty())
+ && selection.mySelectedExcludeRoots.isEmpty() && isEnabled(selection, module);
+ e.getPresentation().setEnabledAndVisible(enabled);
}
protected abstract boolean isEnabled(@NotNull RootsSelection selection, @NotNull Module module);
protected static RootsSelection getSelection(AnActionEvent e) {
- Module module = e.getData(LangDataKeys.MODULE);
VirtualFile[] files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY);
- if (module == null || files == null) {
- return RootsSelection.EMPTY;
- }
+ Module module = getModule(e, files);
+ if (module == null) return RootsSelection.EMPTY;
RootsSelection selection = new RootsSelection();
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(module.getProject()).getFileIndex();
@@ -105,7 +109,14 @@ public abstract class MarkRootActionBase extends DumbAwareAction {
return RootsSelection.EMPTY;
}
if (!fileIndex.isInContent(file)) {
- return RootsSelection.EMPTY;
+ ExcludeFolder excludeFolder = ProjectRootsUtil.findExcludeFolder(module, file);
+ if (excludeFolder != null) {
+ selection.mySelectedExcludeRoots.add(excludeFolder);
+ continue;
+ }
+ else {
+ return RootsSelection.EMPTY;
+ }
}
SourceFolder folder;
if (Comparing.equal(fileIndex.getSourceRootForFile(file), file) && ((folder = ProjectRootsUtil.findSourceFolder(module, file)) != null)) {
@@ -121,10 +132,39 @@ public abstract class MarkRootActionBase extends DumbAwareAction {
return selection;
}
+ @Nullable
+ private static Module getModule(@NotNull AnActionEvent e, @Nullable VirtualFile[] files) {
+ if (files == null) return null;
+ Module module = e.getData(LangDataKeys.MODULE);
+ if (module == null) {
+ module = findParentModule(e.getProject(), files);
+ }
+ return module;
+ }
+
+ @Nullable
+ private static Module findParentModule(@Nullable Project project, @NotNull VirtualFile[] files) {
+ if (project == null) return null;
+ Module result = null;
+ DirectoryIndex index = DirectoryIndex.getInstance(project);
+ for (VirtualFile file : files) {
+ Module module = index.getInfoForFile(file).getModule();
+ if (module == null) return null;
+ if (result == null) {
+ result = module;
+ }
+ else if (!result.equals(module)) {
+ return null;
+ }
+ }
+ return result;
+ }
+
protected static class RootsSelection {
public static final RootsSelection EMPTY = new RootsSelection();
public List<SourceFolder> mySelectedRoots = new ArrayList<SourceFolder>();
+ public List<ExcludeFolder> mySelectedExcludeRoots = new ArrayList<ExcludeFolder>();
public List<VirtualFile> mySelectedDirectories = new ArrayList<VirtualFile>();
public boolean myHaveSelectedFilesUnderSourceRoots;
}
diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/actions/UnmarkRootAction.java b/platform/lang-impl/src/com/intellij/ide/projectView/actions/UnmarkRootAction.java
index cf2724dc039f..0689fe13c2d3 100644
--- a/platform/lang-impl/src/com/intellij/ide/projectView/actions/UnmarkRootAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/projectView/actions/UnmarkRootAction.java
@@ -18,12 +18,15 @@ package com.intellij.ide.projectView.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.ExcludeFolder;
import com.intellij.openapi.roots.SourceFolder;
import com.intellij.openapi.roots.ui.configuration.ModuleSourceRootEditHandler;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import java.util.Set;
@@ -33,9 +36,16 @@ import java.util.Set;
*/
public class UnmarkRootAction extends MarkRootActionBase {
@Override
- public void update(AnActionEvent e) {
- super.update(e);
- RootsSelection selection = getSelection(e);
+ protected void doUpdate(@NotNull AnActionEvent e, @Nullable Module module, @NotNull RootsSelection selection) {
+ if (!Registry.is("ide.hide.excluded.files") && !selection.mySelectedExcludeRoots.isEmpty()
+ && selection.mySelectedDirectories.isEmpty() && selection.mySelectedRoots.isEmpty()) {
+ e.getPresentation().setEnabledAndVisible(true);
+ e.getPresentation().setText("Cancel Exclusion");
+ return;
+ }
+
+ super.doUpdate(e, module, selection);
+
Set<JpsModuleSourceRootType<?>> selectedRootTypes = new HashSet<JpsModuleSourceRootType<?>>();
for (SourceFolder root : selection.mySelectedRoots) {
selectedRootTypes.add(root.getRootType());
@@ -60,6 +70,12 @@ public class UnmarkRootAction extends MarkRootActionBase {
return selection.mySelectedDirectories.isEmpty() && !selection.mySelectedRoots.isEmpty();
}
- protected void modifyRoots(VirtualFile vFile, ContentEntry entry) {
+ protected void modifyRoots(VirtualFile file, ContentEntry entry) {
+ for (ExcludeFolder excludeFolder : entry.getExcludeFolders()) {
+ if (file.equals(excludeFolder.getFile())) {
+ entry.removeExcludeFolder(excludeFolder);
+ break;
+ }
+ }
}
}
diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java
index ee05f0a10283..13ba91900521 100644
--- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java
+++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/ProjectViewDirectoryHelper.java
@@ -25,6 +25,7 @@ import com.intellij.ide.projectView.ViewSettings;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleFileIndex;
@@ -32,7 +33,9 @@ import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.impl.DirectoryIndex;
+import com.intellij.openapi.roots.impl.DirectoryInfo;
import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
@@ -123,7 +126,7 @@ public class ProjectViewDirectoryHelper {
final Module module = fileIndex.getModuleForFile(psiDirectory.getVirtualFile());
final ModuleFileIndex moduleFileIndex = module == null ? null : ModuleRootManager.getInstance(module).getFileIndex();
if (!settings.isFlattenPackages() || skipDirectory(psiDirectory)) {
- processPsiDirectoryChildren(psiDirectory, directoryChildrenInProject(psiDirectory),
+ processPsiDirectoryChildren(psiDirectory, directoryChildrenInProject(fileIndex, psiDirectory),
children, fileIndex, null, settings, withSubDirectories);
}
else { // source directory in "flatten packages" mode
@@ -137,7 +140,13 @@ public class ProjectViewDirectoryHelper {
continue;
}
VirtualFile directoryFile = subdir.getVirtualFile();
- if (fileIndex.isIgnored(directoryFile)) continue;
+
+ if (Registry.is("ide.hide.excluded.files")) {
+ if (fileIndex.isExcluded(directoryFile)) continue;
+ }
+ else {
+ if (FileTypeRegistry.getInstance().isFileIgnored(directoryFile)) continue;
+ }
if (withSubDirectories) {
children.add(new PsiDirectoryNode(project, subdir, settings));
@@ -163,9 +172,9 @@ public class ProjectViewDirectoryHelper {
return topLevelContentRoots;
}
- private PsiElement[] directoryChildrenInProject(PsiDirectory psiDirectory) {
+ private PsiElement[] directoryChildrenInProject(ProjectFileIndex fileIndex, PsiDirectory psiDirectory) {
VirtualFile dir = psiDirectory.getVirtualFile();
- if (myIndex.getInfoForDirectory(dir) != null) {
+ if (isInProject(dir)) {
return psiDirectory.getChildren();
}
@@ -189,6 +198,16 @@ public class ProjectViewDirectoryHelper {
return PsiUtilCore.toPsiElementArray(directoriesOnTheWayToContentRoots);
}
+ private boolean isInProject(VirtualFile dir) {
+ DirectoryInfo directoryInfo = myIndex.getInfoForFile(dir);
+ if (directoryInfo.isInProject()) return true;
+
+ if (!Registry.is("ide.hide.excluded.files")) {
+ return directoryInfo.isExcluded();
+ }
+ return false;
+ }
+
// used only for non-flatten packages mode
public void processPsiDirectoryChildren(final PsiDirectory psiDir,
PsiElement[] children,
@@ -211,7 +230,7 @@ public class ProjectViewDirectoryHelper {
vFile = dir.getVirtualFile();
if (!vFile.equals(projectFileIndex.getSourceRootForFile(vFile))) { // if is not a source root
if (viewSettings.isHideEmptyMiddlePackages() && !skipDirectory(psiDir) && isEmptyMiddleDirectory(dir, true)) {
- processPsiDirectoryChildren(dir, directoryChildrenInProject(dir),
+ processPsiDirectoryChildren(dir, directoryChildrenInProject(projectFileIndex, dir),
container, projectFileIndex, moduleFileIndex, viewSettings, withSubDirectories); // expand it recursively
continue;
}
diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java
index a010828cd8ec..16aa930b806a 100644
--- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java
+++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/PsiDirectoryNode.java
@@ -26,6 +26,7 @@ import com.intellij.ide.projectView.impl.ProjectRootsUtil;
import com.intellij.ide.projectView.impl.ProjectViewImpl;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
@@ -38,6 +39,7 @@ import com.intellij.openapi.roots.ui.configuration.ModuleSourceRootEditHandler;
import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VFileProperty;
import com.intellij.openapi.vfs.VfsUtilCore;
@@ -183,9 +185,14 @@ public class PsiDirectoryNode extends BasePsiNode<PsiDirectory> implements Navig
return false;
}
- final Project project = value.getProject();
- final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
- return !fileIndex.isIgnored(file);
+ if (Registry.is("ide.hide.excluded.files")) {
+ final Project project = value.getProject();
+ final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
+ return !fileIndex.isExcluded(file);
+ }
+ else {
+ return !FileTypeRegistry.getInstance().isFileIgnored(file);
+ }
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java b/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java
index b1c1e25e978c..eb22b72eb810 100644
--- a/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java
+++ b/platform/lang-impl/src/com/intellij/ide/ui/search/TraverseUIStarter.java
@@ -129,7 +129,7 @@ public class TraverseUIStarter implements ApplicationStarter {
System.out.println("Searchable options index builder completed");
- ((ApplicationEx)ApplicationManager.getApplication()).exit(true);
+ ((ApplicationEx)ApplicationManager.getApplication()).exit(true, true);
}
private static void processFileTemplates(Element configurableElement) {
diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java
new file mode 100644
index 000000000000..a6e6c8fdf658
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java
@@ -0,0 +1,169 @@
+/*
+ * 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.ide.util.gotoByName;
+
+import com.intellij.ide.DataManager;
+import com.intellij.ide.actions.ApplyIntentionAction;
+import com.intellij.ide.ui.search.ActionFromOptionDescriptorProvider;
+import com.intellij.ide.ui.search.OptionDescription;
+import com.intellij.ide.ui.search.SearchableOptionsRegistrar;
+import com.intellij.ide.ui.search.SearchableOptionsRegistrarImpl;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.impl.ActionManagerImpl;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.util.Function;
+import com.intellij.util.Processor;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+import static com.intellij.ide.util.gotoByName.GotoActionModel.*;
+
+/**
+ * @author peter
+ */
+public class GotoActionItemProvider implements ChooseByNameItemProvider {
+ private final ActionManager myActionManager = ActionManager.getInstance();
+ protected final SearchableOptionsRegistrar myIndex = SearchableOptionsRegistrar.getInstance();
+ private final GotoActionModel myModel;
+
+ public GotoActionItemProvider(GotoActionModel model) {
+ myModel = model;
+ }
+
+ @NotNull
+ @Override
+ public List<String> filterNames(@NotNull ChooseByNameBase base, @NotNull String[] names, @NotNull String pattern) {
+ return Collections.emptyList(); // no common prefix insertion in goto action
+ }
+
+ @Override
+ public boolean filterElements(@NotNull final ChooseByNameBase base,
+ @NotNull final String pattern,
+ boolean everywhere,
+ @NotNull ProgressIndicator cancelled,
+ @NotNull final Processor<Object> consumer) {
+ return filterElements(pattern, everywhere, new Processor<MatchedValue>() {
+ @Override
+ public boolean process(MatchedValue value) {
+ return consumer.process(value);
+ }
+ });
+ }
+
+ public boolean filterElements(String pattern, boolean everywhere, Processor<MatchedValue> consumer) {
+ DataContext dataContext = DataManager.getInstance().getDataContext(myModel.getContextComponent());
+
+ if (!processIntentions(pattern, consumer, dataContext)) return false;
+ if (!processActions(pattern, everywhere, consumer, dataContext)) return false;
+ if (!processOptions(pattern, consumer, dataContext)) return false;
+
+ return true;
+ }
+
+ private boolean processOptions(String pattern, Processor<MatchedValue> consumer, DataContext dataContext) {
+ List<Comparable> options = ContainerUtil.newArrayList();
+ final Set<String> words = myIndex.getProcessedWords(pattern);
+ Set<OptionDescription> optionDescriptions = null;
+ final String actionManagerName = myActionManager.getComponentName();
+ for (String word : words) {
+ final Set<OptionDescription> descriptions = ((SearchableOptionsRegistrarImpl)myIndex).getAcceptableDescriptions(word);
+ if (descriptions != null) {
+ for (Iterator<OptionDescription> iterator = descriptions.iterator(); iterator.hasNext(); ) {
+ OptionDescription description = iterator.next();
+ if (actionManagerName.equals(description.getPath())) {
+ iterator.remove();
+ }
+ }
+ if (!descriptions.isEmpty()) {
+ if (optionDescriptions == null) {
+ optionDescriptions = descriptions;
+ }
+ else {
+ optionDescriptions.retainAll(descriptions);
+ }
+ }
+ } else {
+ optionDescriptions = null;
+ break;
+ }
+ }
+ if (optionDescriptions != null && !optionDescriptions.isEmpty()) {
+ Set<String> currentHits = new HashSet<String>();
+ for (Iterator<OptionDescription> iterator = optionDescriptions.iterator(); iterator.hasNext(); ) {
+ OptionDescription description = iterator.next();
+ final String hit = description.getHit();
+ if (hit == null || !currentHits.add(hit.trim())) {
+ iterator.remove();
+ }
+ }
+ for (OptionDescription description : optionDescriptions) {
+ for (ActionFromOptionDescriptorProvider converter : ActionFromOptionDescriptorProvider.EP.getExtensions()) {
+ AnAction action = converter.provide(description);
+ if (action != null) options.add(new ActionWrapper(action, null, MatchMode.NAME, dataContext));
+ options.add(description);
+ }
+ }
+ }
+ return processItems(pattern, options, consumer);
+ }
+
+ private boolean processActions(String pattern, boolean everywhere, Processor<MatchedValue> consumer, DataContext dataContext) {
+ List<AnAction> actions = ContainerUtil.newArrayList();
+ if (everywhere) {
+ for (String id : ((ActionManagerImpl)myActionManager).getActionIds()) {
+ ContainerUtil.addIfNotNull(actions, myActionManager.getAction(id));
+ }
+ } else {
+ actions.addAll(myModel.myActionsMap.keySet());
+ }
+
+ List<ActionWrapper> actionWrappers = ContainerUtil.newArrayList();
+ for (AnAction action : actions) {
+ MatchMode mode = myModel.actionMatches(pattern, action);
+ if (mode != MatchMode.NONE) {
+ actionWrappers.add(new ActionWrapper(action, myModel.myActionsMap.get(action), mode, dataContext));
+ }
+ }
+ return processItems(pattern, actionWrappers, consumer);
+ }
+
+ private boolean processIntentions(String pattern, Processor<MatchedValue> consumer, DataContext dataContext) {
+ List<ActionWrapper> intentions = ContainerUtil.newArrayList();
+ for (String intentionText : myModel.myIntentions.keySet()) {
+ final ApplyIntentionAction intentionAction = myModel.myIntentions.get(intentionText);
+ if (myModel.actionMatches(pattern, intentionAction) != MatchMode.NONE) {
+ intentions.add(new ActionWrapper(intentionAction, intentionText, MatchMode.INTENTION, dataContext));
+ }
+ }
+ return processItems(pattern, intentions, consumer);
+ }
+
+ private static boolean processItems(final String pattern, List<? extends Comparable> items, Processor<MatchedValue> consumer) {
+ List<MatchedValue> matched = ContainerUtil.map(items, new Function<Comparable, MatchedValue>() {
+ @Override
+ public MatchedValue fun(Comparable comparable) {
+ return new MatchedValue(comparable, pattern);
+ }
+ });
+ Collections.sort(matched);
+ return ContainerUtil.process(matched, consumer);
+ }
+
+}
diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java
index 45fe6a9a074c..91f0d3368521 100644
--- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java
+++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java
@@ -16,34 +16,28 @@
package com.intellij.ide.util.gotoByName;
-import com.intellij.ide.DataManager;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.actions.ApplyIntentionAction;
-import com.intellij.ide.ui.search.ActionFromOptionDescriptorProvider;
+import com.intellij.ide.actions.ShowSettingsUtilImpl;
import com.intellij.ide.ui.search.OptionDescription;
import com.intellij.ide.ui.search.SearchableOptionsRegistrar;
-import com.intellij.ide.ui.search.SearchableOptionsRegistrarImpl;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
-import com.intellij.openapi.actionSystem.impl.ActionManagerImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.SearchableConfigurable;
-import com.intellij.openapi.options.ex.IdeConfigurablesGroup;
-import com.intellij.openapi.options.ex.ProjectConfigurablesGroup;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiFile;
-import com.intellij.ui.ColorUtil;
-import com.intellij.ui.IdeBorderFactory;
-import com.intellij.ui.LayeredIcon;
-import com.intellij.ui.LightColors;
+import com.intellij.ui.*;
import com.intellij.ui.components.JBLabel;
+import com.intellij.ui.speedSearch.SpeedSearchUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.EmptyIcon;
@@ -58,9 +52,10 @@ import java.awt.*;
import java.util.*;
import java.util.List;
+import static com.intellij.ui.SimpleTextAttributes.STYLE_PLAIN;
+import static com.intellij.ui.SimpleTextAttributes.STYLE_SEARCH_MATCH;
+
public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, Comparator<Object>, EdtSortingModel {
- @NonNls public static final String SETTINGS_KEY = "$$$SETTINGS$$$";
- @NonNls public static final String INTENTIONS_KEY = "$$$INTENTIONS_KEY$$$";
@Nullable private final Project myProject;
private final Component myContextComponent;
@@ -103,10 +98,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
}
}
myIndex = SearchableOptionsRegistrar.getInstance();
- fillConfigurablesNames(new IdeConfigurablesGroup().getConfigurables());
- if (project != null) {
- fillConfigurablesNames(new ProjectConfigurablesGroup(project).getConfigurables());
- }
+ fillConfigurablesNames(ShowSettingsUtilImpl.getConfigurables(project, true));
}
private void fillConfigurablesNames(Configurable[] configurables) {
@@ -151,13 +143,61 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
public void saveInitialCheckBoxState(boolean state) {
}
+ public static class MatchedValue implements Comparable<MatchedValue> {
+ @NotNull public final Comparable value;
+ @NotNull final String pattern;
+
+ MatchedValue(@NotNull Comparable value, @NotNull String pattern) {
+ this.value = value;
+ this.pattern = pattern;
+ }
+
+ @Nullable
+ private String getValueText() {
+ if (value instanceof OptionDescription) return ((OptionDescription)value).getHit();
+ if (!(value instanceof ActionWrapper)) return null;
+ return ((ActionWrapper)value).getAction().getTemplatePresentation().getText();
+ }
+
+ private int getMatchingDegree() {
+ String text = getValueText();
+ if (text != null) {
+ if (StringUtil.equalsIgnoreCase(StringUtil.trimEnd(text, "..."), pattern)) return 3;
+ if (StringUtil.startsWithIgnoreCase(text, pattern)) return 2;
+ if (StringUtil.containsIgnoreCase(text, pattern)) return 1;
+ }
+ return 0;
+ }
+
+ @Override
+ public int compareTo(@NotNull MatchedValue o) {
+ if (value instanceof OptionDescription && !(o.value instanceof OptionDescription)) {
+ return 1;
+ }
+ if (o.value instanceof OptionDescription && !(value instanceof OptionDescription)) {
+ return -1;
+ }
+
+ if (value instanceof ActionWrapper && o.value instanceof ActionWrapper && ApplicationManager.getApplication().isDispatchThread()) {
+ boolean p1Enable = ((ActionWrapper)value).isAvailable();
+ boolean p2enable = ((ActionWrapper)o.value).isAvailable();
+ if (p1Enable && !p2enable) return -1;
+ if (!p1Enable && p2enable) return 1;
+ }
+
+ int diff = o.getMatchingDegree() - getMatchingDegree();
+ //noinspection unchecked
+ return diff != 0 ? diff : value.compareTo(o.value);
+ }
+ }
+
@Override
public ListCellRenderer getListCellRenderer() {
return new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(@NotNull final JList list,
- final Object value,
+ final Object matchedValue,
final int index, final boolean isSelected, final boolean cellHasFocus) {
final JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(IdeBorderFactory.createEmptyBorder(2));
@@ -165,21 +205,40 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
Color bg = UIUtil.getListBackground(isSelected);
panel.setBackground(bg);
+ if (matchedValue instanceof String) { //...
+ final JBLabel label = new JBLabel((String)matchedValue);
+ label.setIcon(EMPTY_ICON);
+ panel.add(label, BorderLayout.WEST);
+ return panel;
+ }
+
Color groupFg = isSelected ? UIUtil.getListSelectionForeground() : UIUtil.getLabelDisabledForeground();
+ Object value = ((MatchedValue) matchedValue).value;
+ String pattern = ((MatchedValue)matchedValue).pattern;
+
+ SimpleColoredComponent nameComponent = new SimpleColoredComponent();
+ nameComponent.setBackground(bg);
+ panel.add(nameComponent, BorderLayout.CENTER);
+
if (value instanceof ActionWrapper) {
final ActionWrapper actionWithParentGroup = (ActionWrapper)value;
final AnAction anAction = actionWithParentGroup.getAction();
final Presentation templatePresentation = anAction.getTemplatePresentation();
- final Icon icon = templatePresentation.getIcon();
final Color fg = defaultActionForeground(isSelected, actionWithParentGroup.getPresentation());
- final JLabel actionLabel = createActionLabel(anAction, templatePresentation.getText(), fg, bg, icon);
- panel.add(actionLabel, BorderLayout.WEST);
+ panel.add(createIconLabel(templatePresentation.getIcon()), BorderLayout.WEST);
+
+ appendWithColoredMatches(nameComponent, templatePresentation.getText(), pattern, fg, isSelected);
- final String groupName = actionWithParentGroup.getGroupName();
+ final Shortcut shortcut = preferKeyboardShortcut(KeymapManager.getInstance().getActiveKeymap().getShortcuts(getActionId(anAction)));
+ if (shortcut != null) {
+ nameComponent.append(" (" + KeymapUtil.getShortcutText(shortcut) + ")", new SimpleTextAttributes(STYLE_PLAIN, groupFg));
+ }
+
+ String groupName = actionWithParentGroup.getAction() instanceof ApplyIntentionAction ? null : actionWithParentGroup.getGroupName();
if (groupName != null) {
final JLabel groupLabel = new JLabel(groupName);
groupLabel.setBackground(bg);
@@ -189,7 +248,9 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
}
else if (value instanceof OptionDescription) {
if (!isSelected) {
- panel.setBackground(UIUtil.isUnderDarcula() ? ColorUtil.brighter(UIUtil.getListBackground(), 1) : LightColors.SLIGHTLY_GRAY);
+ Color descriptorBg = UIUtil.isUnderDarcula() ? ColorUtil.brighter(UIUtil.getListBackground(), 1) : LightColors.SLIGHTLY_GRAY;
+ panel.setBackground(descriptorBg);
+ nameComponent.setBackground(descriptorBg);
}
String hit = ((OptionDescription)value).getHit();
if (hit == null) {
@@ -200,23 +261,31 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
hit = hit.replace(" ", " "); //avoid extra spaces from mnemonics and xml conversion
final Color fg = UIUtil.getListForeground(isSelected);
- final JLabel label = new JLabel(hit.trim());
- label.setIcon(EMPTY_ICON);
- label.setForeground(fg);
- label.setBackground(bg);
- panel.add(label, BorderLayout.WEST);
+
+ appendWithColoredMatches(nameComponent, hit.trim(), pattern, fg, isSelected);
+
+ panel.add(new JLabel(EMPTY_ICON), BorderLayout.WEST);
+
final JLabel settingsLabel = new JLabel(getGroupName((OptionDescription)value));
settingsLabel.setForeground(groupFg);
settingsLabel.setBackground(bg);
panel.add(settingsLabel, BorderLayout.EAST);
}
- else if (value instanceof String) {
- final JBLabel label = new JBLabel((String)value);
- label.setIcon(EMPTY_ICON);
- panel.add(label, BorderLayout.WEST);
- }
return panel;
}
+
+ private void appendWithColoredMatches(SimpleColoredComponent nameComponent, String name, String pattern, Color fg, boolean selected) {
+ final SimpleTextAttributes plain = new SimpleTextAttributes(STYLE_PLAIN, fg);
+ final SimpleTextAttributes highlighted = new SimpleTextAttributes(null, fg, null, STYLE_SEARCH_MATCH);
+ List<TextRange> fragments = ContainerUtil.newArrayList();
+ if (selected) {
+ int matchStart = StringUtil.indexOfIgnoreCase(name, pattern, 0);
+ if (matchStart >= 0) {
+ fragments.add(TextRange.from(matchStart, pattern.length()));
+ }
+ }
+ SpeedSearchUtil.appendColoredFragments(nameComponent, name, fragments, plain, highlighted);
+ }
};
}
@@ -224,6 +293,18 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
return myActionManager.getId(anAction);
}
+ private static JLabel createIconLabel(final Icon icon) {
+ final LayeredIcon layeredIcon = new LayeredIcon(2);
+ layeredIcon.setIcon(EMPTY_ICON, 0);
+ if (icon != null && icon.getIconWidth() <= EMPTY_ICON.getIconWidth() && icon.getIconHeight() <= EMPTY_ICON.getIconHeight()) {
+ layeredIcon
+ .setIcon(icon, 1, (-icon.getIconWidth() + EMPTY_ICON.getIconWidth()) / 2, (EMPTY_ICON.getIconHeight() - icon.getIconHeight()) / 2);
+ }
+
+ return new JLabel(layeredIcon);
+ }
+
+
protected JLabel createActionLabel(final AnAction anAction, final String anActionName,
final Color fg, final Color bg,
final Icon icon) {
@@ -256,23 +337,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
public int compare(@NotNull Object o1, @NotNull Object o2) {
if (ChooseByNameBase.EXTRA_ELEM.equals(o1)) return 1;
if (ChooseByNameBase.EXTRA_ELEM.equals(o2)) return -1;
-
- if (o1 instanceof OptionDescription && !(o2 instanceof OptionDescription)) {
- return 1;
- }
- if (o2 instanceof OptionDescription && !(o1 instanceof OptionDescription)) {
- return -1;
- }
-
- if (o1 instanceof OptionDescription) {
- return ((OptionDescription)o1).compareTo(o2);
- }
-
- if (o1 instanceof ActionWrapper && o2 instanceof ActionWrapper) {
- return ((ActionWrapper)o1).compareTo((ActionWrapper)o2);
- }
-
- return StringUtil.compare(getFullName(o1), getFullName(o2), true);
+ return ((MatchedValue) o1).compareTo((MatchedValue)o2);
}
public static AnActionEvent updateActionBeforeShow(AnAction anAction, DataContext dataContext) {
@@ -293,107 +358,17 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
@Override
@NotNull
public String[] getNames(boolean checkBoxState) {
- final LinkedHashSet<String> result = new LinkedHashSet<String>();
- result.add(INTENTIONS_KEY);
- for (AnAction action : myActionsMap.keySet()) {
- result.add(getActionId(action));
- }
- if (checkBoxState) {
- final Set<String> ids = ((ActionManagerImpl)myActionManager).getActionIds();
- for (String id : ids) {
- result.add(id);
- }
- }
- result.add(SETTINGS_KEY);
- return ArrayUtil.toStringArray(result);
+ return ArrayUtil.EMPTY_STRING_ARRAY;
}
@Override
@NotNull
public Object[] getElementsByName(final String id, final boolean checkBoxState, final String pattern) {
- List<Object> objects = new ArrayList<Object>();
- final AnAction act = myActionManager.getAction(id);
- DataContext dataContext = DataManager.getInstance().getDataContext(myContextComponent);
- if (act != null) {
- final HashMap<AnAction, String> map = new HashMap<AnAction, String>();
- final MatchMode matchMode = actionMatches(pattern, act);
- final String groupName = myActionsMap.get(act);
- if (map.put(act, groupName) == null) {
- objects.add(new ActionWrapper(act, groupName, matchMode, dataContext));
- }
- if (checkBoxState) {
- final Set<String> ids = ((ActionManagerImpl)myActionManager).getActionIds();
- for (AnAction action : map.keySet()) { //do not add already included actions
- ids.remove(getActionId(action));
- }
- if (ids.contains(id)) {
- final AnAction anAction = myActionManager.getAction(id);
- map.put(anAction, null);
- if (anAction != null) {
- objects.add(new ActionWrapper(anAction, null, MatchMode.NON_MENU, dataContext));
- }
- }
- }
- } else if (Comparing.strEqual(id, INTENTIONS_KEY)) {
- for (String intentionText : myIntentions.keySet()) {
- final ApplyIntentionAction intentionAction = myIntentions.get(intentionText);
- if (actionMatches(pattern, intentionAction) != MatchMode.NONE) {
- objects.add(new ActionWrapper(intentionAction, intentionText, MatchMode.INTENTION, dataContext));
- }
- }
- }
- if (Comparing.strEqual(id, SETTINGS_KEY)) {
- final Set<String> words = myIndex.getProcessedWords(pattern);
- Set<OptionDescription> optionDescriptions = null;
- final String actionManagerName = myActionManager.getComponentName();
- for (String word : words) {
- final Set<OptionDescription> descriptions = ((SearchableOptionsRegistrarImpl)myIndex).getAcceptableDescriptions(word);
- if (descriptions != null) {
- for (Iterator<OptionDescription> iterator = descriptions.iterator(); iterator.hasNext(); ) {
- OptionDescription description = iterator.next();
- if (actionManagerName.equals(description.getPath())) {
- iterator.remove();
- }
- }
- if (!descriptions.isEmpty()) {
- if (optionDescriptions == null) {
- optionDescriptions = descriptions;
- }
- else {
- optionDescriptions.retainAll(descriptions);
- }
- }
- } else {
- optionDescriptions = null;
- break;
- }
- }
- if (optionDescriptions != null && !optionDescriptions.isEmpty()) {
- Set<String> currentHits = new HashSet<String>();
- for (Iterator<OptionDescription> iterator = optionDescriptions.iterator(); iterator.hasNext(); ) {
- OptionDescription description = iterator.next();
- final String hit = description.getHit();
- if (hit == null || !currentHits.add(hit.trim())) {
- iterator.remove();
- }
- }
- for (OptionDescription description : optionDescriptions) {
- for (ActionFromOptionDescriptorProvider converter : ActionFromOptionDescriptorProvider.EP.getExtensions()) {
- AnAction action = converter.provide(description);
- if (action != null) {
- String title = getGroupName(description);
- objects.add(new ActionWrapper(action, title, MatchMode.NAME, dataContext));
- }
- objects.add(description);
- }
- }
- }
- }
- return objects.toArray(new Object[objects.size()]);
+ return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@NotNull
- private String getGroupName(@NotNull OptionDescription description) {
+ String getGroupName(@NotNull OptionDescription description) {
String id = description.getConfigurableId();
String name = myConfigurablesNames.get(id);
String settings = SystemInfo.isMac ? "Preferences" : "Settings";
@@ -459,10 +434,8 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
}
@Override
- public String getElementName(final Object element) {
- if (element instanceof OptionDescription) return ((OptionDescription)element).getHit();
- if (!(element instanceof ActionWrapper)) return null;
- return ((ActionWrapper)element).getAction().getTemplatePresentation().getText();
+ public String getElementName(final Object mv) {
+ return ((MatchedValue) mv).getValueText();
}
@Override
@@ -485,7 +458,10 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
return MatchMode.DESCRIPTION;
}
final String groupName = myActionsMap.get(anAction);
- return groupName != null && text != null && matcher.matches(groupName + " " + text, compiledPattern) ? MatchMode.GROUP : MatchMode.NONE;
+ if (groupName == null) {
+ return text != null && matcher.matches(text, compiledPattern) ? MatchMode.NON_MENU : MatchMode.NONE;
+ }
+ return text != null && matcher.matches(groupName + " " + text, compiledPattern) ? MatchMode.GROUP : MatchMode.NONE;
}
@Nullable
@@ -498,7 +474,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
}
@NotNull
- private Pattern getPattern(@NotNull String pattern) {
+ Pattern getPattern(@NotNull String pattern) {
String converted = convertPattern(pattern.trim());
Pattern compiledPattern = myCompiledPattern;
if (compiledPattern != null && !Comparing.strEqual(converted, compiledPattern.getPattern())) {
@@ -528,7 +504,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
NONE, INTENTION, NAME, DESCRIPTION, GROUP, NON_MENU
}
- private static String convertPattern(String pattern) {
+ static String convertPattern(String pattern) {
final int eol = pattern.indexOf('\n');
if (eol != -1) {
pattern = pattern.substring(0, eol);
@@ -632,7 +608,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
return new Perl5Matcher();
}
};
- private PatternMatcher getMatcher() {
+ PatternMatcher getMatcher() {
return myMatcher.get();
}
@@ -660,20 +636,13 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
@Override
public int compareTo(@NotNull ActionWrapper o) {
- if (ApplicationManager.getApplication().isDispatchThread()) {
- boolean p1Enable = visible();
- boolean p2enable = o.visible();
- if (p1Enable && !p2enable) return -1;
- if (!p1Enable && p2enable) return 1;
- }
-
int compared = myMode.compareTo(o.getMode());
return compared != 0
? compared
: StringUtil.compare(myAction.getTemplatePresentation().getText(), o.getAction().getTemplatePresentation().getText(), true);
}
- private boolean visible() {
+ private boolean isAvailable() {
return getPresentation().isEnabledAndVisible();
}
diff --git a/platform/lang-impl/src/com/intellij/injected/editor/InjectedCaret.java b/platform/lang-impl/src/com/intellij/injected/editor/InjectedCaret.java
index 19651a7f68a8..e52fa66ccefc 100644
--- a/platform/lang-impl/src/com/intellij/injected/editor/InjectedCaret.java
+++ b/platform/lang-impl/src/com/intellij/injected/editor/InjectedCaret.java
@@ -15,17 +15,14 @@
*/
package com.intellij.injected.editor;
-import com.intellij.openapi.editor.Caret;
-import com.intellij.openapi.editor.CaretModel;
-import com.intellij.openapi.editor.LogicalPosition;
-import com.intellij.openapi.editor.VisualPosition;
+import com.intellij.openapi.editor.*;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.util.TextRange;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-class InjectedCaret implements Caret {
+public class InjectedCaret implements Caret {
private final EditorWindow myEditorWindow;
final Caret myDelegate;
@@ -36,10 +33,20 @@ class InjectedCaret implements Caret {
@NotNull
@Override
+ public Editor getEditor() {
+ return myEditorWindow;
+ }
+
+ @NotNull
+ @Override
public CaretModel getCaretModel() {
return myEditorWindow.getCaretModel();
}
+ public Caret getDelegate() {
+ return myDelegate;
+ }
+
@Override
public boolean isValid() {
return myDelegate.isValid();
diff --git a/platform/lang-impl/src/com/intellij/internal/DumpDirectoryInfoAction.java b/platform/lang-impl/src/com/intellij/internal/DumpDirectoryInfoAction.java
index b5d0ae16a0ca..2f278bb97919 100644
--- a/platform/lang-impl/src/com/intellij/internal/DumpDirectoryInfoAction.java
+++ b/platform/lang-impl/src/com/intellij/internal/DumpDirectoryInfoAction.java
@@ -18,14 +18,12 @@ package com.intellij.internal;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.impl.DirectoryIndex;
-import com.intellij.openapi.roots.impl.DirectoryInfo;
import com.intellij.openapi.vfs.VirtualFile;
/**
@@ -53,10 +51,7 @@ public class DumpDirectoryInfoAction extends AnAction {
public boolean processFile(VirtualFile fileOrDir) {
LOG.info(fileOrDir.getPath());
- final DirectoryInfo directoryInfo = index.getInfoForDirectory(fileOrDir);
- if (directoryInfo != null) {
- LOG.info(directoryInfo.toString());
- }
+ LOG.info(index.getInfoForFile(fileOrDir).toString());
return true;
}
};
diff --git a/platform/lang-impl/src/com/intellij/internal/DumpVfsInfoForExcludedFilesAction.java b/platform/lang-impl/src/com/intellij/internal/DumpVfsInfoForExcludedFilesAction.java
new file mode 100644
index 000000000000..c4fb34c5ce54
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/internal/DumpVfsInfoForExcludedFilesAction.java
@@ -0,0 +1,114 @@
+/*
+ * 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.internal;
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.impl.DirectoryIndexExcludePolicy;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
+import com.intellij.openapi.vfs.newvfs.persistent.FSRecords;
+import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
+
+import java.util.*;
+
+/**
+ * @author nik
+ */
+@SuppressWarnings("UseOfSystemOutOrSystemErr")
+public class DumpVfsInfoForExcludedFilesAction extends DumbAwareAction {
+ public DumpVfsInfoForExcludedFilesAction() {
+ super("Dump VFS content for files under excluded roots");
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ if (project == null) return;
+
+ Set<String> excludeRoots = new HashSet<String>();
+ for (Module module : ModuleManager.getInstance(project).getModules()) {
+ Collections.addAll(excludeRoots, ModuleRootManager.getInstance(module).getExcludeRootUrls());
+ }
+ for (DirectoryIndexExcludePolicy policy : DirectoryIndexExcludePolicy.EP_NAME.getExtensions(project)) {
+ for (VirtualFile file : policy.getExcludeRootsForProject()) {
+ excludeRoots.add(file.getUrl());
+ }
+ }
+
+ if (excludeRoots.isEmpty()) {
+ System.out.println("No excluded roots found in project.");
+ }
+
+ for (String root : excludeRoots) {
+ VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(root);
+ if (file == null) {
+ System.out.println(root + " not in VFS");
+ continue;
+ }
+ dumpChildrenInDbRecursively(file, 0);
+ }
+ }
+
+ private static void dumpChildrenInDbRecursively(VirtualFile dir, int depth) {
+ if (!(dir instanceof NewVirtualFile)) {
+ System.out.println(dir.getPresentableUrl() + ": not in db (" + dir.getClass().getName() + ")");
+ return;
+ }
+
+ List<VirtualFile> dirs = new ArrayList<VirtualFile>();
+ int inDb = 0, contentInDb = 0, nullChildren = 0;
+ PersistentFS persistentFS = PersistentFS.getInstance();
+ if (persistentFS.wereChildrenAccessed(dir)) {
+ for (String name : persistentFS.listPersisted(dir)) {
+ inDb++;
+ NewVirtualFile child = ((NewVirtualFile)dir).refreshAndFindChild(name);
+ if (child == null) {
+ nullChildren++;
+ continue;
+ }
+ if (child.isDirectory()) {
+ dirs.add(child);
+ }
+ else if (FSRecords.getContentId(child.getId()) != 0) {
+ contentInDb++;
+ }
+ }
+ }
+ System.out.print(dir.getPresentableUrl() + ": " + inDb + " children in db");
+ if (contentInDb > 0) {
+ System.out.print(", content of " + contentInDb + " files in db");
+ }
+ if (nullChildren > 0) {
+ System.out.print(", " + nullChildren + " invalid files in db");
+ }
+ System.out.println();
+
+ if (depth > 10) {
+ System.out.println("too deep, skipping children");
+ }
+ else {
+ for (VirtualFile childDir : dirs) {
+ dumpChildrenInDbRecursively(childDir, depth+1);
+ }
+ }
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/lang/LanguagePerFileMappings.java b/platform/lang-impl/src/com/intellij/lang/LanguagePerFileMappings.java
deleted file mode 100644
index c1a186b614c7..000000000000
--- a/platform/lang-impl/src/com/intellij/lang/LanguagePerFileMappings.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright 2000-2009 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.lang;
-
-import com.intellij.injected.editor.VirtualFileWindow;
-import com.intellij.openapi.components.PersistentStateComponent;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.impl.FilePropertyPusher;
-import com.intellij.openapi.roots.impl.PushedFilePropertiesUpdater;
-import com.intellij.openapi.util.Comparing;
-import com.intellij.openapi.util.Key;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.VirtualFileManager;
-import com.intellij.psi.PsiDocumentManager;
-import com.intellij.testFramework.LightVirtualFile;
-import com.intellij.util.containers.ContainerUtil;
-import gnu.trove.THashMap;
-import org.jdom.Element;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.annotations.TestOnly;
-
-import java.util.*;
-
-/**
- * @author peter
- */
-public abstract class LanguagePerFileMappings<T> implements PersistentStateComponent<Element>, PerFileMappings<T> {
-
- private static final Logger LOG = Logger.getInstance("com.intellij.lang.LanguagePerFileMappings");
-
- private final Map<VirtualFile, T> myMappings = new HashMap<VirtualFile, T>();
- private final Project myProject;
-
- public LanguagePerFileMappings(final Project project) {
- myProject = project;
- }
-
- @Nullable
- protected FilePropertyPusher<T> getFilePropertyPusher() {
- return null;
- }
-
- @Override
- public Map<VirtualFile, T> getMappings() {
- synchronized (myMappings) {
- cleanup();
- return Collections.unmodifiableMap(myMappings);
- }
- }
-
- private void cleanup() {
- for (final VirtualFile file : new ArrayList<VirtualFile>(myMappings.keySet())) {
- if (file != null //PROJECT, top-level
- && !file.isValid()) {
- myMappings.remove(file);
- }
- }
- }
-
- @Override
- @Nullable
- public T getMapping(@Nullable VirtualFile file) {
- FilePropertyPusher<T> pusher = getFilePropertyPusher();
- T t = getMappingInner(file, myMappings, pusher == null? null : pusher.getFileDataKey());
- return t == null? getDefaultMapping(file) : t;
- }
-
- @Nullable
- protected static <T> T getMappingInner(@Nullable VirtualFile file, @Nullable Map<VirtualFile, T> mappings, @Nullable Key<T> pusherKey) {
- if (file instanceof VirtualFileWindow) {
- final VirtualFileWindow window = (VirtualFileWindow)file;
- file = window.getDelegate();
- }
- VirtualFile originalFile = file instanceof LightVirtualFile ? ((LightVirtualFile)file).getOriginalFile() : null;
- if (Comparing.equal(originalFile, file)) originalFile = null;
-
- if (file != null) {
- final T pushedValue = pusherKey == null? null : file.getUserData(pusherKey);
- if (pushedValue != null) return pushedValue;
- }
- if (originalFile != null) {
- final T pushedValue = pusherKey == null? null : originalFile.getUserData(pusherKey);
- if (pushedValue != null) return pushedValue;
- }
- if (mappings == null) return null;
- synchronized (mappings) {
- for (VirtualFile cur = file; ; cur = cur.getParent()) {
- T t = mappings.get(cur);
- if (t != null) return t;
- if (originalFile != null) {
- t = mappings.get(originalFile);
- if (t != null) return t;
- originalFile = originalFile.getParent();
- }
- if (cur == null) break;
- }
- }
- return null;
- }
-
- @Override
- public T chosenToStored(VirtualFile file, T value) {
- return value;
- }
-
- @Override
- public boolean isSelectable(T value) {
- return true;
- }
-
- @Override
- @Nullable
- public T getDefaultMapping(@Nullable final VirtualFile file) {
- return null;
- }
-
- @Nullable
- public T getImmediateMapping(@Nullable final VirtualFile file) {
- synchronized (myMappings) {
- return myMappings.get(file);
- }
- }
-
- @Override
- public void setMappings(final Map<VirtualFile, T> mappings) {
- final Collection<VirtualFile> oldFiles;
- synchronized (myMappings) {
- oldFiles = new ArrayList<VirtualFile>(myMappings.keySet());
- myMappings.clear();
- myMappings.putAll(mappings);
- cleanup();
- }
- handleMappingChange(mappings.keySet(), oldFiles, !getProject().isDefault());
- }
-
- public void setMapping(@Nullable final VirtualFile file, @Nullable T dialect) {
- synchronized (myMappings) {
- if (dialect == null) {
- myMappings.remove(file);
- }
- else {
- myMappings.put(file, dialect);
- }
- }
- final List<VirtualFile> files = ContainerUtil.createMaybeSingletonList(file);
- handleMappingChange(files, files, false);
- }
-
- private void handleMappingChange(final Collection<VirtualFile> files, Collection<VirtualFile> oldFiles, final boolean includeOpenFiles) {
- final FilePropertyPusher<T> pusher = getFilePropertyPusher();
- if (pusher != null) {
- for (VirtualFile oldFile : oldFiles) {
- if (oldFile == null) continue; // project
- oldFile.putUserData(pusher.getFileDataKey(), null);
- }
- PushedFilePropertiesUpdater updater = PushedFilePropertiesUpdater.getInstance(myProject);
- if (updater == null) {
- if (!myProject.isDefault()) {
- LOG.error("updater = null. project=" + myProject.getName()+", this="+getClass().getSimpleName());
- }
- }
- else {
- updater.pushAll(pusher);
- }
- }
- if (shouldReparseFiles()) {
- PsiDocumentManager.getInstance(myProject).reparseFiles(files, includeOpenFiles);
- }
- }
-
- @Override
- public Collection<T> getAvailableValues(VirtualFile file) {
- return getAvailableValues();
- }
-
- protected abstract List<T> getAvailableValues();
-
- @Nullable
- protected abstract String serialize(T t);
-
- @Override
- public Element getState() {
- synchronized (myMappings) {
- cleanup();
- final Element element = new Element("x");
- final List<VirtualFile> files = new ArrayList<VirtualFile>(myMappings.keySet());
- Collections.sort(files, new Comparator<VirtualFile>() {
- @Override
- public int compare(final VirtualFile o1, final VirtualFile o2) {
- if (o1 == null || o2 == null) return o1 == null ? o2 == null ? 0 : 1 : -1;
- return o1.getPath().compareTo(o2.getPath());
- }
- });
- for (VirtualFile file : files) {
- final T dialect = myMappings.get(file);
- String value = serialize(dialect);
- if (value != null) {
- final Element child = new Element("file");
- element.addContent(child);
- child.setAttribute("url", file == null ? "PROJECT" : file.getUrl());
- child.setAttribute(getValueAttribute(), value);
- }
- }
- return element;
- }
- }
-
- @Nullable
- protected T handleUnknownMapping(VirtualFile file, String value) {
- return null;
- }
-
- @NotNull
- protected String getValueAttribute() {
- return "dialect";
- }
-
- @Override
- public void loadState(final Element state) {
- synchronized (myMappings) {
- final THashMap<String, T> dialectMap = new THashMap<String, T>();
- for (T dialect : getAvailableValues()) {
- String key = serialize(dialect);
- if (key != null) {
- dialectMap.put(key, dialect);
- }
- }
- final List<Element> files = state.getChildren("file");
- for (Element fileElement : files) {
- final String url = fileElement.getAttributeValue("url");
- final String dialectID = fileElement.getAttributeValue(getValueAttribute());
- final VirtualFile file = url.equals("PROJECT") ? null : VirtualFileManager.getInstance().findFileByUrl(url);
- T dialect = dialectMap.get(dialectID);
- if (dialect == null) {
- dialect = handleUnknownMapping(file, dialectID);
- if (dialect == null) continue;
- }
- if (file != null || url.equals("PROJECT")) {
- myMappings.put(file, dialect);
- }
- }
- }
- }
-
- @TestOnly
- public void cleanupForNextTest() {
- synchronized (myMappings) {
- myMappings.clear();
- }
- }
-
- protected Project getProject() {
- return myProject;
- }
-
- protected boolean shouldReparseFiles() {
- return true;
- }
-
- public boolean hasMappings() {
- synchronized (myMappings) {
- return !myMappings.isEmpty();
- }
- }
-
-}
diff --git a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java
index ecda31db8355..ad322c232fa0 100644
--- a/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java
+++ b/platform/lang-impl/src/com/intellij/lang/parser/GeneratedParserUtilBase.java
@@ -2,6 +2,7 @@
// Do not modify or refactor without complete investigation and/or review.
package com.intellij.lang.parser;
+import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
import com.intellij.lang.*;
import com.intellij.lang.impl.PsiBuilderAdapter;
import com.intellij.lang.impl.PsiBuilderImpl;
@@ -337,18 +338,18 @@ public class GeneratedParserUtilBase {
}
else if (diff > 0 && diff <= length) {
CharSequence fragment = builder_.getOriginalText().subSequence(offset, completionState.offset);
- add = StringUtil.startsWithIgnoreCase(text, fragment.toString());
+ add = completionState.prefixMatches(fragment.toString(), text);
}
else if (diff < 0) {
for (int i=-1; ; i--) {
IElementType type = builder_.rawLookup(i);
int tokenStart = builder_.rawTokenTypeStart(i);
- if (((PsiBuilderImpl)((Builder)builder_).getDelegate()).whitespaceOrComment(type)) {
+ if (isWhitespaceOrComment(builder_, type)) {
diff = completionState.offset - tokenStart;
}
else if (type != null && tokenStart < completionState.offset) {
CharSequence fragment = builder_.getOriginalText().subSequence(tokenStart, completionState.offset);
- if (StringUtil.startsWithIgnoreCase(text, fragment.toString())) {
+ if (completionState.prefixMatches(fragment.toString(), text)) {
diff = completionState.offset - tokenStart;
}
break;
@@ -364,6 +365,10 @@ public class GeneratedParserUtilBase {
}
}
+ public static boolean isWhitespaceOrComment(@NotNull PsiBuilder builder_, @Nullable IElementType type) {
+ return ((PsiBuilderImpl)((Builder)builder_).getDelegate()).whitespaceOrComment(type);
+ }
+
// here's the new section API for compact parsers & less IntelliJ platform API exposure
public static final int _NONE_ = 0x0;
public static final int _COLLAPSE_ = 0x1;
@@ -514,7 +519,9 @@ public class GeneratedParserUtilBase {
}
// propagate errorReportedAt up the stack to avoid duplicate reporting
Frame prevFrame = willFail && eatMore == null ? null : state.frameStack.peekLast();
- if (prevFrame != null && prevFrame.errorReportedAt < frame.errorReportedAt) prevFrame.errorReportedAt = frame.errorReportedAt;
+ if (prevFrame != null && prevFrame.errorReportedAt < frame.errorReportedAt) {
+ prevFrame.errorReportedAt = frame.errorReportedAt;
+ }
state.FRAMES.recycle(frame);
}
@@ -657,9 +664,17 @@ public class GeneratedParserUtilBase {
return o.toString();
}
- public void addItem(PsiBuilder builder, String text) {
+ public void addItem(@NotNull PsiBuilder builder, @NotNull String text) {
items.add(text);
}
+
+ public boolean prefixMatches(@NotNull String prefix, @NotNull String variant) {
+ boolean matches = new CamelHumpMatcher(prefix, false).prefixMatches(variant.replace(' ', '_'));
+ if (matches && StringUtil.isWhiteSpace(prefix.charAt(prefix.length() - 1))) {
+ return StringUtil.startsWithIgnoreCase(variant, prefix);
+ }
+ return matches;
+ }
}
public static class Builder extends PsiBuilderAdapter {
diff --git a/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewProvider.java b/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewProvider.java
index 7aa83adfd275..1de4d4a96357 100644
--- a/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewProvider.java
+++ b/platform/lang-impl/src/com/intellij/openapi/diff/impl/settings/DiffPreviewProvider.java
@@ -66,7 +66,7 @@ public abstract class DiffPreviewProvider {
" long value;\n" +
"\n" +
" void foo() {\n" +
- " // Left changes\n" +
+ " // Right changes\n" +
" }\n" +
"\n" +
" void removedFromLeft() {}\n" +
diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java
index d135b528f5e2..3e284ff6b2cc 100644
--- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java
+++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectAllOccurrencesAction.java
@@ -15,9 +15,9 @@
*/
package com.intellij.openapi.editor.actions;
-import com.intellij.find.FindManager;
-import com.intellij.find.FindModel;
-import com.intellij.find.FindResult;
+import com.intellij.find.*;
+import com.intellij.find.editorHeaderActions.EditorHeaderAction;
+import com.intellij.find.editorHeaderActions.SelectAllAction;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
@@ -27,6 +27,8 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import org.jetbrains.annotations.Nullable;
+import java.util.Iterator;
+
public class SelectAllOccurrencesAction extends EditorAction {
protected SelectAllOccurrencesAction() {
super(new Handler());
@@ -39,7 +41,9 @@ public class SelectAllOccurrencesAction extends EditorAction {
}
@Override
- public void doExecute(Editor editor, @Nullable Caret c, DataContext dataContext) {
+ public void doExecute(final Editor editor, @Nullable Caret c, DataContext dataContext) {
+ if (executeEquivalentFindPanelAction(editor, dataContext)) return;
+
Caret caret = c == null ? editor.getCaretModel().getPrimaryCaret() : c;
boolean wholeWordsSearch = false;
@@ -58,25 +62,36 @@ public class SelectAllOccurrencesAction extends EditorAction {
}
int caretShiftFromSelectionStart = caret.getOffset() - caret.getSelectionStart();
- FindManager findManager = FindManager.getInstance(project);
+ final FindManager findManager = FindManager.getInstance(project);
+
+ final FindModel model = getFindModel(selectedText, wholeWordsSearch);
- FindModel model = new FindModel();
- model.setStringToFind(selectedText);
- model.setCaseSensitive(true);
- model.setWholeWordsOnly(wholeWordsSearch);
+ FindUtil.selectSearchResultsInEditor(editor, new Iterator<FindResult>() {
+ FindResult findResult = findManager.findString(editor.getDocument().getCharsSequence(), 0, model);
- int searchStartOffset = 0;
- FindResult findResult = findManager.findString(editor.getDocument().getCharsSequence(), searchStartOffset, model);
- while (findResult.isStringFound()) {
- int newCaretOffset = caretShiftFromSelectionStart + findResult.getStartOffset();
- EditorActionUtil.makePositionVisible(editor, newCaretOffset);
- Caret newCaret = editor.getCaretModel().addCaret(editor.offsetToVisualPosition(newCaretOffset));
- if (newCaret != null) {
- setSelection(editor, newCaret, findResult);
+ @Override
+ public boolean hasNext() {
+ return findResult.isStringFound();
}
- findResult = findManager.findString(editor.getDocument().getCharsSequence(), findResult.getEndOffset(), model);
- }
+
+ @Override
+ public FindResult next() {
+ FindResult result = findResult;
+ findResult = findManager.findString(editor.getDocument().getCharsSequence(), findResult.getEndOffset(), model);
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }, caretShiftFromSelectionStart);
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
+
+ @Override
+ protected EditorHeaderAction getEquivalentFindPanelAction(EditorSearchComponent searchComponent) {
+ return new SelectAllAction(searchComponent);
+ }
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java
index cc4783b4d4db..7d3c408ee152 100644
--- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java
+++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectNextOccurrenceAction.java
@@ -15,9 +15,9 @@
*/
package com.intellij.openapi.editor.actions;
-import com.intellij.find.FindManager;
-import com.intellij.find.FindModel;
-import com.intellij.find.FindResult;
+import com.intellij.find.*;
+import com.intellij.find.editorHeaderActions.AddOccurrenceAction;
+import com.intellij.find.editorHeaderActions.EditorHeaderAction;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
@@ -40,6 +40,8 @@ public class SelectNextOccurrenceAction extends EditorAction {
@Override
public void doExecute(Editor editor, @Nullable Caret c, DataContext dataContext) {
+ if (executeEquivalentFindPanelAction(editor, dataContext)) return;
+
Caret caret = c == null ? editor.getCaretModel().getPrimaryCaret() : c;
TextRange wordSelectionRange = getSelectionRange(editor, caret);
boolean notFoundPreviously = getAndResetNotFoundStatus(editor);
@@ -52,26 +54,21 @@ public class SelectNextOccurrenceAction extends EditorAction {
}
FindManager findManager = FindManager.getInstance(project);
- FindModel model = new FindModel();
- model.setStringToFind(selectedText);
- model.setCaseSensitive(true);
- model.setWholeWordsOnly(wholeWordSearch);
+ FindModel model = getFindModel(selectedText, wholeWordSearch);
+
+ findManager.setFindWasPerformed();
+ findManager.setFindNextModel(model);
int searchStartOffset = notFoundPreviously ? 0 : caret.getSelectionEnd();
FindResult findResult = findManager.findString(editor.getDocument().getCharsSequence(), searchStartOffset, model);
if (findResult.isStringFound()) {
- int newCaretOffset = caret.getOffset() - caret.getSelectionStart() + findResult.getStartOffset();
- EditorActionUtil.makePositionVisible(editor, newCaretOffset);
- Caret newCaret = editor.getCaretModel().addCaret(editor.offsetToVisualPosition(newCaretOffset));
- if (newCaret == null) {
+ boolean caretAdded = FindUtil.selectSearchResultInEditor(editor, findResult, caret.getOffset() - caret.getSelectionStart());
+ if (!caretAdded) {
// this means that the found occurence is already selected
if (notFoundPreviously) {
setNotFoundStatus(editor); // to make sure we won't show hint anymore if there are no more occurrences
}
}
- else {
- setSelection(editor, newCaret, findResult);
- }
}
else {
setNotFoundStatus(editor);
@@ -87,5 +84,10 @@ public class SelectNextOccurrenceAction extends EditorAction {
}
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
+
+ @Override
+ protected EditorHeaderAction getEquivalentFindPanelAction(EditorSearchComponent searchComponent) {
+ return new AddOccurrenceAction(searchComponent);
+ }
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java
index c43eae703fd5..7b189281dfd0 100644
--- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java
+++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/SelectOccurrencesActionHandler.java
@@ -19,8 +19,11 @@ import com.intellij.codeInsight.editorActions.SelectWordUtil;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.hint.HintManagerImpl;
import com.intellij.codeInsight.hint.HintUtil;
+import com.intellij.find.EditorSearchComponent;
import com.intellij.find.FindBundle;
-import com.intellij.openapi.actionSystem.IdeActions;
+import com.intellij.find.FindModel;
+import com.intellij.find.editorHeaderActions.EditorHeaderAction;
+import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorLastActionTracker;
@@ -28,13 +31,24 @@ import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.ui.LightweightHint;
+import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.Nullable;
+import java.util.Arrays;
+import java.util.Set;
+
abstract public class SelectOccurrencesActionHandler extends EditorActionHandler {
private static final Key<Boolean> NOT_FOUND = Key.create("select.next.occurence.not.found");
private static final Key<Boolean> WHOLE_WORDS = Key.create("select.next.occurence.whole.words");
+ private static final Set<String> SELECT_ACTIONS = new HashSet<String>(Arrays.asList(
+ IdeActions.ACTION_SELECT_NEXT_OCCURENCE,
+ IdeActions.ACTION_UNSELECT_PREVIOUS_OCCURENCE,
+ IdeActions.ACTION_FIND_NEXT,
+ IdeActions.ACTION_FIND_PREVIOUS
+ ));
+
protected static void setSelection(Editor editor, Caret caret, TextRange selectionRange) {
EditorActionUtil.makePositionVisible(editor, selectionRange.getStartOffset());
EditorActionUtil.makePositionVisible(editor, selectionRange.getEndOffset());
@@ -83,6 +97,35 @@ abstract public class SelectOccurrencesActionHandler extends EditorActionHandler
protected static boolean isRepeatedActionInvocation() {
String lastActionId = EditorLastActionTracker.getInstance().getLastActionId();
- return IdeActions.ACTION_SELECT_NEXT_OCCURENCE.equals(lastActionId) || IdeActions.ACTION_UNSELECT_PREVIOUS_OCCURENCE.equals(lastActionId);
+ return SELECT_ACTIONS.contains(lastActionId);
+ }
+
+ protected static FindModel getFindModel(String text, boolean wholeWords) {
+ FindModel model = new FindModel();
+ model.setStringToFind(text);
+ model.setCaseSensitive(true);
+ model.setWholeWordsOnly(wholeWords);
+ return model;
+ }
+
+ protected boolean executeEquivalentFindPanelAction(Editor editor, DataContext context) {
+ if (editor.getHeaderComponent() instanceof EditorSearchComponent) {
+ EditorSearchComponent searchComponent = (EditorSearchComponent)editor.getHeaderComponent();
+ EditorHeaderAction action = getEquivalentFindPanelAction(searchComponent);
+ if (action != null) {
+ Presentation presentation = new Presentation();
+ AnActionEvent event = new AnActionEvent(null, context, ActionPlaces.MAIN_MENU, presentation, ActionManager.getInstance(), 0);
+ action.update(event);
+ if (presentation.isEnabled()) {
+ action.actionPerformed(event);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ protected EditorHeaderAction getEquivalentFindPanelAction(EditorSearchComponent searchComponent) {
+ return null;
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectPreviousOccurrenceAction.java b/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectPreviousOccurrenceAction.java
index a5657ff89b27..fffff56b12dc 100644
--- a/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectPreviousOccurrenceAction.java
+++ b/platform/lang-impl/src/com/intellij/openapi/editor/actions/UnselectPreviousOccurrenceAction.java
@@ -15,6 +15,9 @@
*/
package com.intellij.openapi.editor.actions;
+import com.intellij.find.EditorSearchComponent;
+import com.intellij.find.editorHeaderActions.EditorHeaderAction;
+import com.intellij.find.editorHeaderActions.RemoveOccurrenceAction;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
@@ -35,6 +38,8 @@ public class UnselectPreviousOccurrenceAction extends EditorAction {
@Override
public void doExecute(Editor editor, @Nullable Caret caret, DataContext dataContext) {
+ if (executeEquivalentFindPanelAction(editor, dataContext)) return;
+
if (editor.getCaretModel().getCaretCount() > 1) {
editor.getCaretModel().removeCaret(editor.getCaretModel().getPrimaryCaret());
}
@@ -44,5 +49,10 @@ public class UnselectPreviousOccurrenceAction extends EditorAction {
getAndResetNotFoundStatus(editor);
editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
}
+
+ @Override
+ protected EditorHeaderAction getEquivalentFindPanelAction(EditorSearchComponent searchComponent) {
+ return new RemoveOccurrenceAction(searchComponent);
+ }
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java
index 2f5485d6deae..b1385686bc3a 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java
@@ -149,12 +149,19 @@ public class DirectoryIndexImpl extends DirectoryIndex {
@Override
public DirectoryInfo getInfoForDirectory(@NotNull VirtualFile dir) {
+ DirectoryInfo info = getInfoForFile(dir);
+ return info.isInProject() ? info : null;
+ }
+
+ @NotNull
+ @Override
+ public DirectoryInfo getInfoForFile(@NotNull VirtualFile file) {
checkAvailability();
dispatchPendingEvents();
- if (!(dir instanceof NewVirtualFile)) return null;
+ if (!(file instanceof NewVirtualFile)) return NonProjectDirectoryInfo.NOT_SUPPORTED_VIRTUAL_FILE_IMPLEMENTATION;
- return getRootIndex().getInfoForDirectory(dir);
+ return getRootIndex().getInfoForFile(file);
}
@Override
@@ -167,22 +174,6 @@ public class DirectoryIndexImpl extends DirectoryIndex {
}
@Override
- public boolean isProjectExcludeRoot(@NotNull VirtualFile dir) {
- checkAvailability();
- if (!(dir instanceof NewVirtualFile)) return false;
-
- return getRootIndex().isProjectExcludeRoot(dir);
- }
-
- @Override
- public boolean isModuleExcludeRoot(@NotNull VirtualFile dir) {
- checkAvailability();
- if (!(dir instanceof NewVirtualFile)) return false;
-
- return getRootIndex().isModuleExcludeRoot(dir);
- }
-
- @Override
public String getPackageName(@NotNull VirtualFile dir) {
checkAvailability();
if (!(dir instanceof NewVirtualFile)) return null;
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java
index cb4b94016611..a96432e2b64c 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java
@@ -53,7 +53,7 @@ import java.io.IOException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
-public class PushedFilePropertiesUpdater {
+public class PushedFilePropertiesUpdaterImpl extends PushedFilePropertiesUpdater {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.PushedFilePropertiesUpdater");
private final Project myProject;
@@ -62,12 +62,7 @@ public class PushedFilePropertiesUpdater {
private final Queue<Runnable> myTasks = new ConcurrentLinkedQueue<Runnable>();
private final MessageBusConnection myConnection;
- @NotNull
- public static PushedFilePropertiesUpdater getInstance(Project project) {
- return project.getComponent(PushedFilePropertiesUpdater.class);
- }
-
- public PushedFilePropertiesUpdater(final Project project) {
+ public PushedFilePropertiesUpdaterImpl(final Project project) {
myProject = project;
myPushers = Extensions.getExtensions(FilePropertyPusher.EP_NAME);
myFilePushers = ContainerUtil.findAllAsArray(myPushers, new Condition<FilePropertyPusher>() {
@@ -122,22 +117,24 @@ public class PushedFilePropertiesUpdater {
});
}
+ @Override
public void initializeProperties() {
for (final FilePropertyPusher pusher : myPushers) {
pusher.initExtra(myProject, myProject.getMessageBus(), new FilePropertyPusher.Engine() {
@Override
public void pushAll() {
- PushedFilePropertiesUpdater.this.pushAll(pusher);
+ PushedFilePropertiesUpdaterImpl.this.pushAll(pusher);
}
@Override
public void pushRecursively(VirtualFile file, Project project) {
- PushedFilePropertiesUpdater.this.schedulePushRecursively(file, pusher);
+ PushedFilePropertiesUpdaterImpl.this.schedulePushRecursively(file, pusher);
}
});
}
}
+ @Override
public void pushAllPropertiesNow() {
performPushTasks();
doPushAll(myPushers);
@@ -222,6 +219,7 @@ public class PushedFilePropertiesUpdater {
return projectValue != null ? projectValue : pusher.getDefaultValue();
}
+ @Override
public void pushAll(final FilePropertyPusher... pushers) {
queueTask(new Runnable() {
@Override
@@ -289,7 +287,7 @@ public class PushedFilePropertiesUpdater {
pusher = pushers[i];
if (!isDir && (pusher.pushDirectoriesOnly() || !pusher.acceptsFile(fileOrDir))) continue;
else if (isDir && !pusher.acceptsDirectory(fileOrDir, myProject)) continue;
- findAndUpdateValue(myProject, fileOrDir, pusher, moduleValues != null ? moduleValues[i]:null);
+ findAndUpdateValue(fileOrDir, pusher, moduleValues != null ? moduleValues[i]:null);
}
}
catch (AbstractMethodError ame) { // acceptsDirectory is missed
@@ -298,17 +296,18 @@ public class PushedFilePropertiesUpdater {
}
}
- public static <T> void findAndUpdateValue(final Project project, final VirtualFile fileOrDir, final FilePropertyPusher<T> pusher, final T moduleValue) {
- final T value = findPusherValuesUpwards(project, fileOrDir, pusher, moduleValue);
- updateValue(fileOrDir, value, pusher);
+ @Override
+ public <T> void findAndUpdateValue(final VirtualFile fileOrDir, final FilePropertyPusher<T> pusher, final T moduleValue) {
+ final T value = findPusherValuesUpwards(myProject, fileOrDir, pusher, moduleValue);
+ updateValue(myProject, fileOrDir, value, pusher);
}
- private static <T> void updateValue(final VirtualFile fileOrDir, final T value, final FilePropertyPusher<T> pusher) {
+ private static <T> void updateValue(final Project project, final VirtualFile fileOrDir, final T value, final FilePropertyPusher<T> pusher) {
final T oldValue = fileOrDir.getUserData(pusher.getFileDataKey());
if (value != oldValue) {
fileOrDir.putUserData(pusher.getFileDataKey(), value);
try {
- pusher.persistAttribute(fileOrDir, value);
+ pusher.persistAttribute(project, fileOrDir, value);
}
catch (IOException e) {
LOG.error(e);
@@ -316,7 +315,8 @@ public class PushedFilePropertiesUpdater {
}
}
- public static void filePropertiesChanged(@NotNull final VirtualFile file) {
+ @Override
+ public void filePropertiesChanged(@NotNull final VirtualFile file) {
ApplicationManager.getApplication().assertReadAccessAllowed();
FileBasedIndex.getInstance().requestReindex(file);
for (final Project project : ProjectManager.getInstance().getOpenProjects()) {
@@ -344,6 +344,7 @@ public class PushedFilePropertiesUpdater {
}
}
+ @Override
public void processPendingEvents() {
myConnection.deliverImmediately();
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java b/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java
index 5937af147648..0978f8f09ec7 100644
--- a/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java
+++ b/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java
@@ -109,11 +109,11 @@ public class RegistryUi implements Disposable {
final RegistryValue value = myModel.getRegistryValue(selected);
String desc = value.getDescription();
if (value.isRestartRequired()) {
- String required = "Requires IDE restart.";
+ String required = " Requires IDE restart.";
if (desc.endsWith(".")) {
desc += required;
} else {
- desc += ". " + required;
+ desc += "." + required;
}
}
myDescriptionLabel.setText(desc);
diff --git a/platform/lang-impl/src/com/intellij/packageDependencies/ui/ProjectPatternProvider.java b/platform/lang-impl/src/com/intellij/packageDependencies/ui/ProjectPatternProvider.java
index 5fd50cfeaf6c..df0a5caa1f97 100644
--- a/platform/lang-impl/src/com/intellij/packageDependencies/ui/ProjectPatternProvider.java
+++ b/platform/lang-impl/src/com/intellij/packageDependencies/ui/ProjectPatternProvider.java
@@ -27,11 +27,14 @@ import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packageDependencies.DependencyUISettings;
+import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.scope.packageSet.FilePatternPackageSet;
import com.intellij.psi.search.scope.packageSet.PackageSet;
@@ -103,7 +106,10 @@ public class ProjectPatternProvider extends PatternDialectProvider {
pattern += recursively ? "*/" : "*";
}
}
- return new FilePatternPackageSet(getModulePattern(node), pattern);
+ final VirtualFile vDir = ((DirectoryNode)node).getDirectory();
+ final PsiElement psiElement = node.getPsiElement();
+ final Module module = psiElement != null ? ModuleUtilCore.findModuleForFile(vDir, psiElement.getProject()) : null;
+ return new FilePatternPackageSet(module != null ? module.getName() : null, pattern);
}
else if (node instanceof FileNode) {
if (recursively) return null;
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);
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/file/DirectoryIconProvider.java b/platform/lang-impl/src/com/intellij/psi/impl/file/DirectoryIconProvider.java
index d12bc939293f..6aaa810340bd 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/file/DirectoryIconProvider.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/file/DirectoryIconProvider.java
@@ -20,11 +20,15 @@
*/
package com.intellij.psi.impl.file;
+import com.intellij.icons.AllIcons;
import com.intellij.ide.IconProvider;
import com.intellij.ide.projectView.impl.ProjectRootsUtil;
import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.SourceFolder;
import com.intellij.openapi.roots.ui.configuration.SourceRootPresentation;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
@@ -39,11 +43,18 @@ public class DirectoryIconProvider extends IconProvider implements DumbAware {
if (element instanceof PsiDirectory) {
final PsiDirectory psiDirectory = (PsiDirectory)element;
final VirtualFile vFile = psiDirectory.getVirtualFile();
- SourceFolder sourceFolder = ProjectRootsUtil.getModuleSourceRoot(vFile, psiDirectory.getProject());
+ Project project = psiDirectory.getProject();
+ SourceFolder sourceFolder = ProjectRootsUtil.getModuleSourceRoot(vFile, project);
if (sourceFolder != null) {
return SourceRootPresentation.getSourceRootIcon(sourceFolder);
}
else {
+ if (!Registry.is("ide.hide.excluded.files")) {
+ boolean ignored = ProjectRootManager.getInstance(project).getFileIndex().isExcluded(vFile);
+ if (ignored) {
+ return AllIcons.Modules.ExcludeRoot;
+ }
+ }
return PlatformIcons.DIRECTORY_CLOSED_ICON;
}
}
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java
index bb2c938e3d08..17dd2bca1f17 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/PsiVFSListener.java
@@ -443,7 +443,7 @@ public class PsiVFSListener extends VirtualFileAdapter {
public void run() {
PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager);
- boolean isExcluded = vFile.isDirectory() && myProjectRootManager.getFileIndex().isIgnored(vFile);
+ boolean isExcluded = vFile.isDirectory() && myProjectRootManager.getFileIndex().isExcluded(vFile);
if (oldParentDir != null && !isExcluded) {
if (newParentDir != null) {
treeEvent.setOldParent(oldParentDir);
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java b/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java
index 63413321ce41..c5b183c3594b 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/source/PostprocessReformattingAspect.java
@@ -636,7 +636,7 @@ public class PostprocessReformattingAspect implements PomModelAspect {
final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myPsiManager.getProject());
final Document document = viewProvider.getDocument();
assert document != null;
- final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(styleSettings);
+ final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(styleSettings, viewProvider.getBaseLanguage());
documentManager.commitDocument(document);
return codeFormatter;
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java
index e76aecfa1e0b..fa1dd9e86b4a 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeFormatterFacade.java
@@ -78,10 +78,12 @@ public class CodeFormatterFacade {
private final CodeStyleSettings mySettings;
private final FormatterTagHandler myTagHandler;
+ private final int myRightMargin;
- public CodeFormatterFacade(CodeStyleSettings settings) {
+ public CodeFormatterFacade(CodeStyleSettings settings, @Nullable Language language) {
mySettings = settings;
myTagHandler = new FormatterTagHandler(settings);
+ myRightMargin = mySettings.getRightMargin(language);
}
public ASTNode processElement(ASTNode element) {
@@ -637,8 +639,8 @@ public class CodeFormatterFacade {
}
private int wrapPositionForTextWithoutTabs(int startLineOffset, int endLineOffset, int targetRangeEndOffset) {
- if (Math.min(endLineOffset, targetRangeEndOffset) - startLineOffset > mySettings.RIGHT_MARGIN) {
- return startLineOffset + mySettings.RIGHT_MARGIN - FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS;
+ if (Math.min(endLineOffset, targetRangeEndOffset) - startLineOffset > myRightMargin) {
+ return startLineOffset + myRightMargin - FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS;
}
return -1;
}
@@ -659,13 +661,13 @@ public class CodeFormatterFacade {
case '\t': symbolWidth = tabSize - (width % tabSize); break;
default: symbolWidth = 1;
}
- if (width + symbolWidth + FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS >= mySettings.RIGHT_MARGIN
+ if (width + symbolWidth + FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS >= myRightMargin
&& (Math.min(endLineOffset, targetRangeEndOffset) - i) >= FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS)
{
// Remember preferred position.
result = i - 1;
}
- if (width + symbolWidth >= mySettings.RIGHT_MARGIN) {
+ if (width + symbolWidth >= myRightMargin) {
wrapLine = true;
break;
}
@@ -700,12 +702,12 @@ public class CodeFormatterFacade {
break;
default: newX = x + EditorUtil.charWidth(c, Font.PLAIN, editor); symbolWidth = 1;
}
- if (width + symbolWidth + FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS >= mySettings.RIGHT_MARGIN
+ if (width + symbolWidth + FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS >= myRightMargin
&& (Math.min(endLineOffset, targetRangeEndOffset) - i) >= FormatConstants.RESERVED_LINE_WRAP_WIDTH_IN_COLUMNS)
{
result = i - 1;
}
- if (width + symbolWidth >= mySettings.RIGHT_MARGIN) {
+ if (width + symbolWidth >= myRightMargin) {
wrapLine = true;
break;
}
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java
index a9031f3133a3..81eda35222dd 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleFacadeImpl.java
@@ -20,6 +20,7 @@
package com.intellij.psi.impl.source.codeStyle;
import com.intellij.codeStyle.CodeStyleFacade;
+import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.options.Configurable;
@@ -68,8 +69,8 @@ public class CodeStyleFacadeImpl extends CodeStyleFacade {
}
@Override
- public int getRightMargin() {
- return CodeStyleSettingsManager.getSettings(myProject).RIGHT_MARGIN;
+ public int getRightMargin(Language language) {
+ return CodeStyleSettingsManager.getSettings(myProject).getRightMargin(language);
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java
index 043ac483d2ed..767152fc1e2b 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleManagerImpl.java
@@ -101,7 +101,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
}
ASTNode treeElement = SourceTreeToPsiMap.psiElementToTree(element);
- final PsiElement formatted = SourceTreeToPsiMap.treeElementToPsi(new CodeFormatterFacade(getSettings()).processElement(treeElement));
+ final PsiElement formatted = SourceTreeToPsiMap.treeElementToPsi(new CodeFormatterFacade(getSettings(), element.getLanguage()).processElement(treeElement));
if (!canChangeWhiteSpacesOnly) {
return postProcessElement(formatted);
}
@@ -180,7 +180,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
ASTNode treeElement = SourceTreeToPsiMap.psiElementToTree(file);
transformAllChildren(treeElement);
- final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings());
+ final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings(), file.getLanguage());
LOG.assertTrue(file.isValid());
if (editor == null) {
@@ -274,7 +274,7 @@ public class CodeStyleManagerImpl extends CodeStyleManager {
}
ASTNode treeElement = SourceTreeToPsiMap.psiElementToTree(element);
- final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings());
+ final CodeFormatterFacade codeFormatter = new CodeFormatterFacade(getSettings(), element.getLanguage());
final PsiElement formatted = SourceTreeToPsiMap.treeElementToPsi(codeFormatter.processRange(treeElement, startOffset, endOffset));
return canChangeWhiteSpacesOnly ? formatted : postProcessElement(formatted);
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java
index f2863469d614..27089fa70e91 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java
@@ -20,6 +20,7 @@ import com.intellij.injected.editor.*;
import com.intellij.lang.Language;
import com.intellij.lang.LanguageUtil;
import com.intellij.lang.injection.InjectedLanguageManager;
+import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.SelectionModel;
@@ -158,6 +159,22 @@ public class InjectedLanguageUtil {
return getEditorForInjectedLanguageNoCommit(editor, file, offset);
}
+ public static Caret getCaretForInjectedLanguageNoCommit(@Nullable Caret caret, @Nullable PsiFile file) {
+ if (caret == null || file == null || caret instanceof InjectedCaret) return caret;
+
+ PsiFile injectedFile = findInjectedPsiNoCommit(file, caret.getOffset());
+ Editor injectedEditor = getInjectedEditorForInjectedFile(caret.getEditor(), injectedFile);
+ if (!(injectedEditor instanceof EditorWindow)) {
+ return caret;
+ }
+ for (Caret injectedCaret : injectedEditor.getCaretModel().getAllCarets()) {
+ if (((InjectedCaret)injectedCaret).getDelegate() == caret) {
+ return injectedCaret;
+ }
+ }
+ return null;
+ }
+
public static Editor getEditorForInjectedLanguageNoCommit(@Nullable Editor editor, @Nullable PsiFile file, final int offset) {
if (editor == null || file == null || editor instanceof EditorWindow) return editor;
PsiFile injectedFile = findInjectedPsiNoCommit(file, offset);
diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java
index fc17bf25a33f..d791f14aa841 100644
--- a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java
+++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java
@@ -154,15 +154,24 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
break;
}
catch (IOException e) {
- LOG.info(e);
needRebuild = true;
- FileUtil.delete(indexRootDir);
- IndexingStamp.rewriteVersion(versionFile, version); // todo snapshots indices
+ onExceptionInstantiatingIndex(version, versionFile, indexRootDir, e);
+ } catch (RuntimeException e) {
+ //noinspection ThrowableResultOfMethodCallIgnored
+ Throwable cause = FileBasedIndexImpl.getCauseToRebuildIndex(e);
+ if (cause == null) throw e;
+ onExceptionInstantiatingIndex(version, versionFile, indexRootDir, e);
}
}
return needRebuild;
}
+ private static void onExceptionInstantiatingIndex(int version, File versionFile, File indexRootDir, Exception e) throws IOException {
+ LOG.info(e);
+ FileUtil.delete(indexRootDir);
+ IndexingStamp.rewriteVersion(versionFile, version); // todo snapshots indices
+ }
+
private static class StubIdExternalizer implements DataExternalizer<StubIdList> {
@Override
public void save(@NotNull final DataOutput out, @NotNull final StubIdList value) throws IOException {
@@ -207,7 +216,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
public <Key, Psi extends PsiElement> Collection<Psi> get(@NotNull final StubIndexKey<Key, Psi> indexKey,
@NotNull final Key key,
@NotNull final Project project,
- final GlobalSearchScope scope) {
+ @Nullable final GlobalSearchScope scope) {
return get(indexKey, key, project, scope, null);
}
@@ -215,7 +224,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
public <Key, Psi extends PsiElement> Collection<Psi> get(@NotNull StubIndexKey<Key, Psi> indexKey,
@NotNull Key key,
@NotNull Project project,
- GlobalSearchScope scope,
+ @Nullable GlobalSearchScope scope,
IdFilter filter) {
final List<Psi> result = new SmartList<Psi>();
process(indexKey, key, project, scope, filter, new CommonProcessors.CollectProcessor<Psi>(result));
@@ -226,7 +235,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
public <Key, Psi extends PsiElement> boolean processElements(@NotNull StubIndexKey<Key, Psi> indexKey,
@NotNull Key key,
@NotNull Project project,
- GlobalSearchScope scope,
+ @Nullable GlobalSearchScope scope,
Class<Psi> requiredClass,
@NotNull Processor<? super Psi> processor) {
return processElements(indexKey, key, project, scope, null, requiredClass, processor);
@@ -238,7 +247,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
@NotNull final Project project,
@Nullable final GlobalSearchScope scope,
@Nullable IdFilter idFilter,
- final Class<Psi> requiredClass,
+ @NotNull final Class<Psi> requiredClass,
@NotNull final Processor<? super Psi> processor) {
final FileBasedIndexImpl fileBasedIndex = (FileBasedIndexImpl)FileBasedIndex.getInstance();
fileBasedIndex.ensureUpToDate(StubUpdatingIndex.INDEX_ID, project, scope);
@@ -315,7 +324,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
return processAllKeys(indexKey, processor, GlobalSearchScope.allScope(project), null);
}
- public <K> boolean processAllKeys(@NotNull StubIndexKey<K, ?> indexKey, Processor<K> processor, GlobalSearchScope scope, @Nullable IdFilter idFilter) {
+ public <K> boolean processAllKeys(@NotNull StubIndexKey<K, ?> indexKey, @NotNull Processor<K> processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) {
FileBasedIndex.getInstance().ensureUpToDate(StubUpdatingIndex.INDEX_ID, scope.getProject(), scope);
diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/RefactoringQuickListPopupAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/RefactoringQuickListPopupAction.java
index aea982678b9d..159279570cf2 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/actions/RefactoringQuickListPopupAction.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/actions/RefactoringQuickListPopupAction.java
@@ -26,6 +26,10 @@ import org.jetbrains.annotations.Nullable;
public class RefactoringQuickListPopupAction extends QuickSwitchSchemeAction {
+ public RefactoringQuickListPopupAction() {
+ setInjectedContext(true);
+ }
+
@Override
protected void fillActions(@Nullable final Project project,
@NotNull final DefaultActionGroup group,
@@ -64,6 +68,7 @@ public class RefactoringQuickListPopupAction extends QuickSwitchSchemeAction {
child instanceof CopyElementAction) {
final Presentation presentation = new Presentation();
final AnActionEvent event = new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, presentation, actionManager, 0);
+ event.setInjectedContext(child.isInInjectedContext());
child.update(event);
if (presentation.isEnabled() && presentation.isVisible()) {
destinationGroup.add(child);
diff --git a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java
index e761e9a3f2f3..81a2885c2022 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/introduce/inplace/AbstractInplaceIntroducer.java
@@ -45,6 +45,8 @@ import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.RefactoringActionHandler;
+import com.intellij.refactoring.listeners.RefactoringEventData;
+import com.intellij.refactoring.listeners.RefactoringEventListener;
import com.intellij.refactoring.rename.inplace.InplaceRefactoring;
import com.intellij.ui.DottedBorder;
import com.intellij.util.ui.PositionTracker;
@@ -537,6 +539,13 @@ public abstract class AbstractInplaceIntroducer<V extends PsiNameIdentifierOwner
CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
@Override
public void run() {
+ final String refactoringId = getRefactoringId();
+ if (refactoringId != null) {
+ final RefactoringEventData beforeData = new RefactoringEventData();
+ beforeData.addElements(new PsiElement[] {getLocalVariable(), getExpr()});
+ myProject.getMessageBus()
+ .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringStarted(refactoringId, beforeData);
+ }
performIntroduce();
}
}, getCommandName(), getCommandName());
@@ -567,9 +576,20 @@ public abstract class AbstractInplaceIntroducer<V extends PsiNameIdentifierOwner
}
if (success) {
performPostIntroduceTasks();
+ final String refactoringId = getRefactoringId();
+ if (refactoringId != null) {
+ final RefactoringEventData afterData = new RefactoringEventData();
+ afterData.addElement(getVariable());
+ myProject.getMessageBus()
+ .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringDone(refactoringId, afterData);
+ }
}
}
+ protected String getRefactoringId() {
+ return null;
+ }
+
@Override
protected boolean startsOnTheSameElement(RefactoringActionHandler handler, PsiElement element) {
return super.startsOnTheSameElement(handler, element) || getLocalVariable() == element;
diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java
index db30a105865a..aa4f696df179 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java
@@ -773,32 +773,31 @@ public abstract class InplaceRefactoring {
if (ApplicationManager.getApplication().isHeadlessEnvironment()) return;
final BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createDialogBalloonBuilder(component, null).setSmallVariant(true);
myBalloon = balloonBuilder.createBalloon();
- final Editor topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(myEditor);
Disposer.register(myProject, myBalloon);
Disposer.register(myBalloon, new Disposable() {
@Override
public void dispose() {
releaseIfNotRestart();
- topLevelEditor.putUserData(PopupFactoryImpl.ANCHOR_POPUP_POSITION, null);
+ myEditor.putUserData(PopupFactoryImpl.ANCHOR_POPUP_POSITION, null);
}
});
- topLevelEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
+ myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
final JBPopupFactory popupFactory = JBPopupFactory.getInstance();
- myBalloon.show(new PositionTracker<Balloon>(topLevelEditor.getContentComponent()) {
+ myBalloon.show(new PositionTracker<Balloon>(myEditor.getContentComponent()) {
@Override
public RelativePoint recalculateLocation(Balloon object) {
- if (myTarget != null && !popupFactory.isBestPopupLocationVisible(topLevelEditor)) {
+ if (myTarget != null && !popupFactory.isBestPopupLocationVisible(myEditor)) {
return myTarget;
}
if (myCaretRangeMarker != null && myCaretRangeMarker.isValid()) {
- topLevelEditor.putUserData(PopupFactoryImpl.ANCHOR_POPUP_POSITION,
- topLevelEditor.offsetToVisualPosition(myCaretRangeMarker.getStartOffset()));
+ myEditor.putUserData(PopupFactoryImpl.ANCHOR_POPUP_POSITION,
+ myEditor.offsetToVisualPosition(myCaretRangeMarker.getStartOffset()));
}
- final RelativePoint target = popupFactory.guessBestPopupLocation(topLevelEditor);
+ final RelativePoint target = popupFactory.guessBestPopupLocation(myEditor);
final Point screenPoint = target.getScreenPoint();
int y = screenPoint.y;
- if (target.getPoint().getY() > topLevelEditor.getLineHeight() + myBalloon.getPreferredSize().getHeight()) {
- y -= topLevelEditor.getLineHeight();
+ if (target.getPoint().getY() > myEditor.getLineHeight() + myBalloon.getPreferredSize().getHeight()) {
+ y -= myEditor.getLineHeight();
}
myTarget = new RelativePoint(new Point(screenPoint.x, y));
return myTarget;
diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java
index bd3c52aac910..5e5907c83a07 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java
@@ -177,6 +177,11 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer {
return false;
}
+ @Override
+ protected String getRefactoringId() {
+ return null;
+ }
+
private void appendAdditionalElement(Collection<Pair<PsiElement, TextRange>> stringUsages,
PsiNamedElement variable,
PsiElement element) {
diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java
index 376561535a1e..6fa0ed27d8c8 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java
@@ -38,6 +38,8 @@ import com.intellij.psi.util.PsiUtilCore;
import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.listeners.RefactoringElementListener;
+import com.intellij.refactoring.listeners.RefactoringEventData;
+import com.intellij.refactoring.listeners.RefactoringEventListener;
import com.intellij.refactoring.rename.*;
import com.intellij.refactoring.rename.naming.AutomaticRenamer;
import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory;
@@ -137,6 +139,10 @@ public class VariableInplaceRenamer extends InplaceRefactoring {
protected boolean shouldCreateSnapshot() {
return true;
}
+
+ protected String getRefactoringId() {
+ return "refactoring.rename";
+ }
@Override
protected void beforeTemplateStart() {
@@ -204,11 +210,18 @@ public class VariableInplaceRenamer extends InplaceRefactoring {
protected void performRefactoringRename(final String newName,
final StartMarkAction markAction) {
+ final String refactoringId = getRefactoringId();
try {
+ PsiNamedElement elementToRename = getVariable();
+ if (refactoringId != null) {
+ final RefactoringEventData beforeData = new RefactoringEventData();
+ beforeData.addElement(elementToRename);
+ myProject.getMessageBus()
+ .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringStarted(refactoringId, beforeData);
+ }
if (!isIdentifier(newName, myLanguage)) {
return;
}
- PsiNamedElement elementToRename = getVariable();
if (elementToRename != null) {
new WriteCommandAction(myProject, getCommandName()) {
@Override
@@ -278,6 +291,14 @@ public class VariableInplaceRenamer extends InplaceRefactoring {
}
}
finally {
+
+ if (refactoringId != null) {
+ final RefactoringEventData afterData = new RefactoringEventData();
+ afterData.addElement(getVariable());
+ myProject.getMessageBus()
+ .syncPublisher(RefactoringEventListener.REFACTORING_EVENT_TOPIC).refactoringDone(refactoringId, afterData);
+ }
+
try {
((EditorImpl)InjectedLanguageUtil.getTopLevelEditor(myEditor)).stopDumbLater();
}
diff --git a/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceOnErrorAction.java b/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceOnErrorAction.java
index e1de663c9418..d3385e88b4b1 100644
--- a/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceOnErrorAction.java
+++ b/platform/lang-impl/src/com/intellij/unscramble/AnalyzeStacktraceOnErrorAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * 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.
@@ -19,26 +19,28 @@ package com.intellij.unscramble;
import com.intellij.diagnostic.IdeErrorsDialog;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.Project;
/**
* @author spleaner
*/
public class AnalyzeStacktraceOnErrorAction extends AnAction {
+ @Override
+ public void update(AnActionEvent e) {
+ Project project = e.getProject();
+ String message = getMessage(e);
+ e.getPresentation().setEnabledAndVisible(project != null && message != null);
+ }
@Override
public void actionPerformed(AnActionEvent e) {
- final DataContext dataContext = e.getDataContext();
-
- final Project project = CommonDataKeys.PROJECT.getData(dataContext);
- if (project == null) return;
+ Project project = e.getProject();
+ String message = getMessage(e);
+ if (project == null || message == null) return;
+ AnalyzeStacktraceUtil.addConsole(project, null, "<Stacktrace>", message);
+ }
- final String message = IdeErrorsDialog.CURRENT_TRACE_KEY.getData(dataContext);
- if (message != null) {
- AnalyzeStacktraceUtil.addConsole(project, null, "<Stacktrace>", message);
- }
+ private static String getMessage(AnActionEvent e) {
+ return IdeErrorsDialog.CURRENT_TRACE_KEY.getData(e.getDataContext());
}
} \ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ContentHashesSupport.java b/platform/lang-impl/src/com/intellij/util/indexing/ContentHashesSupport.java
index d20d01dc4e03..34f80dae5cc9 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/ContentHashesSupport.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/ContentHashesSupport.java
@@ -21,6 +21,7 @@ import com.intellij.openapi.vfs.newvfs.persistent.ContentHashesUtil;
import com.intellij.openapi.vfs.newvfs.persistent.FlushingDaemon;
import com.intellij.util.io.IOUtil;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
@@ -63,19 +64,19 @@ class ContentHashesSupport {
}
static void flushContentHashes() {
- if (ourHashesWithFileType.isDirty()) ourHashesWithFileType.force();
+ if (ourHashesWithFileType != null && ourHashesWithFileType.isDirty()) ourHashesWithFileType.force();
}
- static int calcContentHashIdWithFileType(@NotNull byte[] bytes, @NotNull FileType fileType) throws IOException {
- return enumerateHash(calcContentHashWithFileType(bytes, fileType));
+ static int calcContentHashIdWithFileType(@NotNull byte[] bytes, @Nullable Charset charset, @NotNull FileType fileType) throws IOException {
+ return enumerateHash(calcContentHashWithFileType(bytes, charset, fileType));
}
static int enumerateHash(@NotNull byte[] digest) throws IOException {
return ourHashesWithFileType.enumerate(digest);
}
- static byte[] calcContentHashWithFileType(@NotNull byte[] bytes, @NotNull FileType fileType) throws IOException {
+ static byte[] calcContentHashWithFileType(@NotNull byte[] bytes, @Nullable Charset charset, @NotNull FileType fileType) throws IOException {
MessageDigest messageDigest = ContentHashesUtil.HASHER_CACHE.getValue();
Charset defaultCharset = Charset.defaultCharset();
@@ -83,6 +84,8 @@ class ContentHashesSupport {
messageDigest.update((byte)0);
messageDigest.update(String.valueOf(bytes.length).getBytes(defaultCharset));
messageDigest.update((byte)0);
+ messageDigest.update((charset != null ? charset.displayName():"null_charset").getBytes(defaultCharset));
+ messageDigest.update((byte)0);
messageDigest.update(bytes, 0, bytes.length);
return messageDigest.digest();
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/DebugAssertions.java b/platform/lang-impl/src/com/intellij/util/indexing/DebugAssertions.java
index 0b7650aace4f..6c866ad2283f 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/DebugAssertions.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/DebugAssertions.java
@@ -19,6 +19,8 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.SystemProperties;
+import java.util.Formatter;
+
public class DebugAssertions {
private static final Logger LOG = Logger.getInstance(DebugAssertions.class);
@@ -29,7 +31,7 @@ public class DebugAssertions {
public static final boolean EXTRA_SANITY_CHECKS = SystemProperties.getBooleanProperty(
"intellij.idea.indices.debug.extra.sanity",
- DEBUG && ApplicationManager.getApplication().isInternal()
+ true
);
public static void assertTrue(boolean value) {
@@ -37,4 +39,14 @@ public class DebugAssertions {
LOG.assertTrue(false);
}
}
+
+ public static void assertTrue(boolean value, String message, Object ... args) {
+ if (!value) {
+ error(message, args);
+ }
+ }
+
+ public static void error(String message, Object ... args) {
+ LOG.error(new Formatter().format(message, args));
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java
index c81f7c485876..5242ee3b70cf 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java
@@ -380,9 +380,9 @@ public class FileBasedIndexImpl extends FileBasedIndex {
LOG.info("Version has changed for index " + name + ". The index will be rebuilt.");
}
if (extension.hasSnapshotMapping() && (isCurrentVersionCorrupted || versionChanged)) {
- safeDelete(IndexInfrastructure.getPersistentIndexRootDir(name));
+ FileUtil.delete(IndexInfrastructure.getPersistentIndexRootDir(name));
}
- safeDelete(IndexInfrastructure.getIndexRootDir(name));
+ FileUtil.delete(IndexInfrastructure.getIndexRootDir(name));
IndexingStamp.rewriteVersion(versionFile, version);
}
@@ -458,22 +458,16 @@ public class FileBasedIndexImpl extends FileBasedIndex {
catch (Exception ignored) {
}
- safeDelete(IndexInfrastructure.getIndexRootDir(name));
+ FileUtil.delete(IndexInfrastructure.getIndexRootDir(name));
if (extension.hasSnapshotMapping() && (!contentHashesEnumeratorOk || instantiatedStorage)) {
- safeDelete(IndexInfrastructure.getPersistentIndexRootDir(name)); // todo there is possibility of corruption of storage and content hashes
+ FileUtil.delete(IndexInfrastructure.getPersistentIndexRootDir(name));
}
IndexingStamp.rewriteVersion(versionFile, version);
}
}
}
- private static boolean safeDelete(File dir) {
- File directory = FileUtil.findSequentNonexistentFile(dir.getParentFile(), dir.getName(), "");
- boolean success = dir.renameTo(directory);
- return FileUtil.delete(success ? directory:dir);
- }
-
private static void saveRegisteredIndices(@NotNull Collection<ID<?, ?>> ids) {
final File file = getRegisteredIndicesFile();
try {
@@ -1206,6 +1200,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
@Nullable
public static Throwable getCauseToRebuildIndex(@NotNull RuntimeException e) {
+ if (e instanceof IndexOutOfBoundsException) return e; // something wrong with direct byte buffer
Throwable cause = e.getCause();
if (cause instanceof StorageException || cause instanceof IOException ||
cause instanceof IllegalArgumentException) return cause;
@@ -1568,7 +1563,7 @@ public class FileBasedIndexImpl extends FileBasedIndex {
indicesToDrop.remove(key.toString());
}
for (String s : indicesToDrop) {
- safeDelete(IndexInfrastructure.getIndexRootDir(ID.create(s)));
+ FileUtil.delete(IndexInfrastructure.getIndexRootDir(ID.create(s)));
}
}
@@ -1664,21 +1659,26 @@ public class FileBasedIndexImpl extends FileBasedIndex {
}
byte[] currentBytes;
- byte[] hash;
try {
currentBytes = content.getBytes();
- if (fileType.isBinary() || !IdIndex.ourSnapshotMappingsEnabled) {
- hash = null;
- } else {
- hash = ContentHashesSupport
- .calcContentHashWithFileType(currentBytes, SubstitutedFileType.substituteFileType(file, fileType, project));
- }
}
catch (IOException e) {
currentBytes = ArrayUtil.EMPTY_BYTE_ARRAY;
- hash = null;
}
- fc = new FileContentImpl(file, currentBytes, hash);
+ fc = new FileContentImpl(file, currentBytes);
+
+ if (!fileType.isBinary() && IdIndex.ourSnapshotMappingsEnabled) {
+ try {
+ byte[] hash = ContentHashesSupport.calcContentHashWithFileType(
+ currentBytes,
+ fc.getCharset(),
+ SubstitutedFileType.substituteFileType(file, fileType, project)
+ );
+ fc.setHash(hash);
+ } catch (IOException e) {
+ LOG.error(e);
+ }
+ }
psiFile = content.getUserData(IndexingDataKeys.PSI_FILE);
initFileContent(fc, project, psiFile);
@@ -1909,21 +1909,26 @@ public class FileBasedIndexImpl extends FileBasedIndex {
@Override
public void beforePropertyChange(@NotNull final VirtualFilePropertyEvent event) {
- if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) {
- // indexes may depend on file name
- final VirtualFile file = event.getFile();
+ String propertyName = event.getPropertyName();
+ if (propertyName.equals(VirtualFile.PROP_NAME)) {
+ // indexes may depend on file name
// name change may lead to filetype change so the file might become not indexable
// in general case have to 'unindex' the file and index it again if needed after the name has been changed
- invalidateIndices(file, false);
+ invalidateIndices(event.getFile(), false);
+ } else if (propertyName.equals(VirtualFile.PROP_ENCODING)) {
+ invalidateIndices(event.getFile(), true);
}
}
@Override
public void propertyChanged(@NotNull final VirtualFilePropertyEvent event) {
- if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) {
+ String propertyName = event.getPropertyName();
+ if (propertyName.equals(VirtualFile.PROP_NAME)) {
// indexes may depend on file name
markDirty(event, false);
+ } else if (propertyName.equals(VirtualFile.PROP_ENCODING)) {
+ markDirty(event, true);
}
}
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java
index 7bea700016c8..6bdd55b1d343 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/IndexingStamp.java
@@ -59,7 +59,7 @@ public class IndexingStamp {
private static final long UNINDEXED_STAMP = -1L; // we don't store trivial "absent" state
private static final long INDEX_DATA_OUTDATED_STAMP = -2L;
- private static final int VERSION = 11;
+ private static final int VERSION = 12;
private static final ConcurrentHashMap<ID<?, ?>, Long> ourIndexIdToCreationStamp = new ConcurrentHashMap<ID<?, ?>, Long>();
private static volatile long ourLastStamp; // ensure any file index stamp increases
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java
index 3ad505baf207..ebb7911e82be 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java
@@ -22,18 +22,16 @@ import com.intellij.openapi.util.*;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.util.io.ByteSequence;
import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.util.Processor;
-import com.intellij.util.SmartList;
-import com.intellij.util.SystemProperties;
+import com.intellij.util.*;
import com.intellij.util.io.*;
+import com.intellij.util.io.DataOutputStream;
import gnu.trove.THashMap;
import gnu.trove.TObjectObjectProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.io.DataInputStream;
-import java.io.File;
-import java.io.IOException;
+import java.io.*;
+import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -56,6 +54,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
private PersistentHashMap<Integer, Collection<Key>> myInputsIndex;
private PersistentHashMap<Integer, ByteSequence> myContents;
private PersistentHashMap<Integer, Integer> myInputsSnapshotMapping;
+ private PersistentHashMap<Integer, String> myIndexingTrace;
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
@@ -127,6 +126,10 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
cleanMapping(myInputsSnapshotMapping);
myInputsSnapshotMapping = createInputSnapshotMapping();
}
+ if (myIndexingTrace != null) {
+ cleanMapping(myIndexingTrace);
+ myIndexingTrace = createIndexingTrace();
+ }
if (myContents != null) {
cleanMapping(myContents);
myContents = createContentsIndex();
@@ -161,6 +164,31 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
}
}
+ private PersistentHashMap<Integer, String> createIndexingTrace() throws IOException {
+ assert myIndexId != null;
+ final File mapFile = new File(IndexInfrastructure.getIndexRootDir(myIndexId), "indextrace");
+ try {
+ return new PersistentHashMap<Integer, String>(mapFile, EnumeratorIntegerDescriptor.INSTANCE,
+ new DataExternalizer<String>() {
+ @Override
+ public void save(@NotNull DataOutput out, String value) throws IOException {
+ out.write((byte[])CompressionUtil.compressCharSequence(value, Charset.defaultCharset()));
+ }
+
+ @Override
+ public String read(@NotNull DataInput in) throws IOException {
+ byte[] b = new byte[((InputStream)in).available()];
+ in.readFully(b);
+ return (String)CompressionUtil.uncompressCharSequence(b, Charset.defaultCharset());
+ }
+ }, 4096);
+ }
+ catch (IOException ex) {
+ IOUtil.deleteAllFilesStartingWith(mapFile);
+ throw ex;
+ }
+ }
+
private static void cleanMapping(@NotNull PersistentHashMap<?, ?> index) {
final File baseFile = index.getBaseFile();
try {
@@ -178,6 +206,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
getReadLock().lock();
doForce(myInputsIndex);
doForce(myInputsSnapshotMapping);
+ doForce(myIndexingTrace);
doForce(myContents);
myStorage.flush();
}
@@ -216,6 +245,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
finally {
doClose(myInputsIndex);
doClose(myInputsSnapshotMapping);
+ doClose(myIndexingTrace);
doClose(myContents);
}
}
@@ -283,6 +313,9 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
myInputsSnapshotMapping = createInputSnapshotMapping();
}
myInputsIndex = createInputsIndex();
+ if (DebugAssertions.EXTRA_SANITY_CHECKS && myIndexId != null) {
+ myIndexingTrace = createIndexingTrace();
+ }
}
@Nullable
@@ -318,7 +351,8 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
if (myContents != null && weProcessPhysicalContent && content != null) {
try {
- hashId = getHashOfContent((FileContent)content);
+ FileContent fileContent = (FileContent)content;
+ hashId = getHashOfContent(fileContent);
if (doReadSavedPersistentData) {
if (!myContents.isBusyReading()) { // avoid blocking read, we can calculate index value
ByteSequence bytes = myContents.get(hashId);
@@ -326,7 +360,19 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
data = deserializeSavedPersistentData(bytes);
havePersistentData = true;
if (DebugAssertions.EXTRA_SANITY_CHECKS) {
- DebugAssertions.assertTrue(myIndexer.map(content).equals(data));
+ Map<Key, Value> contentData = myIndexer.map(content);
+ boolean sameValueForSavedIndexedResultAndCurrentOne = contentData.equals(data);
+ if (!sameValueForSavedIndexedResultAndCurrentOne) {
+ DebugAssertions.error(
+ "Unexpected difference in indexing of %s by index %s, file type %s, charset %s\ndiff %s\nprevious indexed info %s",
+ fileContent.getFile(),
+ myIndexId,
+ fileContent.getFileType(),
+ ((FileContentImpl)fileContent).getCharset(),
+ buildDiff(data, contentData),
+ myIndexingTrace.get(hashId)
+ );
+ }
}
}
} else {
@@ -344,16 +390,27 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
if (data == null) data = content != null ? myIndexer.map(content) : Collections.<Key, Value>emptyMap();
if (hashId != null && !havePersistentData) {
- savePersistentData(data, hashId, skippedReadingPersistentDataButMayHaveIt);
+ boolean saved = savePersistentData(data, hashId, skippedReadingPersistentDataButMayHaveIt);
+ if (DebugAssertions.EXTRA_SANITY_CHECKS) {
+ if (saved) {
+
+ FileContent fileContent = (FileContent)content;
+ try {
+ myIndexingTrace.put(hashId, ((FileContentImpl)fileContent).getCharset() + "," + fileContent.getFileType()+"," + fileContent.getFile().getPath() + "," +
+ ExceptionUtil.getThrowableText(new Throwable()));
+ } catch (IOException ex) {
+ LOG.error(ex);
+ }
+ }
+ }
}
ProgressManager.checkCanceled();
final NotNullComputable<Collection<Key>> oldKeysGetter;
final int savedInputId;
- if (myHasSnapshotMapping && weProcessPhysicalContent) {
+ if (myHasSnapshotMapping) {
try {
-
- oldKeysGetter = new NotNullComputable<Collection<Key>>() {
+ final NotNullComputable<Collection<Key>> keysForGivenInputId = new NotNullComputable<Collection<Key>>() {
@NotNull
@Override
public Collection<Key> compute() {
@@ -369,15 +426,38 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
}
return currentKeys;
- } catch (IOException e) {
+ }
+ catch (IOException e) {
throw new RuntimeException(e);
}
}
};
- if (content instanceof FileContent) {
- savedInputId = getHashOfContent((FileContent)content);
+ if (weProcessPhysicalContent) {
+ if (content instanceof FileContent) {
+ savedInputId = getHashOfContent((FileContent)content);
+ }
+ else {
+ savedInputId = NULL_MAPPING;
+ }
+ oldKeysGetter = keysForGivenInputId;
} else {
+ oldKeysGetter = new NotNullComputable<Collection<Key>>() {
+ @NotNull
+ @Override
+ public Collection<Key> compute() {
+ try {
+ Collection<Key> oldKeys = myInputsIndex.get(inputId);
+ if (oldKeys == null) {
+ return keysForGivenInputId.compute();
+ }
+ return oldKeys;
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
savedInputId = NULL_MAPPING;
}
} catch (IOException ex) {
@@ -429,6 +509,41 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
};
}
+ private StringBuilder buildDiff(Map<Key, Value> data, Map<Key, Value> contentData) {
+ StringBuilder moreInfo = new StringBuilder();
+ if (contentData.size() != data.size()) {
+ moreInfo.append("Indexer has different number of elements, previously ").append(data.size()).append(" after ")
+ .append(contentData.size()).append("\n");
+ } else {
+ moreInfo.append("total ").append(contentData.size()).append(" entries\n");
+ }
+
+ for(Map.Entry<Key, Value> keyValueEntry:contentData.entrySet()) {
+ if (!data.containsKey(keyValueEntry.getKey())) {
+ moreInfo.append("Previous data doesn't contain:").append(keyValueEntry.getKey()).append( " with value ").append(keyValueEntry.getValue()).append("\n");
+ }
+ else {
+ Value value = data.get(keyValueEntry.getKey());
+ if (!Comparing.equal(keyValueEntry.getValue(), value)) {
+ moreInfo.append("Previous data has different value for key:").append(keyValueEntry.getKey()).append( ", new value ").append(keyValueEntry.getValue()).append( ", oldValue:").append(value).append("\n");
+ }
+ }
+ }
+
+ for(Map.Entry<Key, Value> keyValueEntry:data.entrySet()) {
+ if (!contentData.containsKey(keyValueEntry.getKey())) {
+ moreInfo.append("New data doesn't contain:").append(keyValueEntry.getKey()).append( " with value ").append(keyValueEntry.getValue()).append("\n");
+ }
+ else {
+ Value value = contentData.get(keyValueEntry.getKey());
+ if (!Comparing.equal(keyValueEntry.getValue(), value)) {
+ moreInfo.append("New data has different value for key:").append(keyValueEntry.getKey()).append( " new value ").append(value).append( ", oldValue:").append(keyValueEntry.getValue()).append("\n");
+ }
+ }
+ }
+ return moreInfo;
+ }
+
private Map<Key, Value> deserializeSavedPersistentData(ByteSequence bytes) throws IOException {
DataInputStream stream = new DataInputStream(new UnsyncByteArrayInputStream(bytes.getBytes(), bytes.getOffset(), bytes.getLength()));
int pairs = DataInputOutputUtil.readINT(stream);
@@ -447,8 +562,9 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
if (previouslyCalculatedContentHashId == null) {
byte[] hash = content instanceof FileContentImpl ? ((FileContentImpl)content).getHash():null;
if (hash == null) {
+ Charset charset = content instanceof FileContentImpl ? ((FileContentImpl)content).getCharset() : null;
previouslyCalculatedContentHashId = ContentHashesSupport
- .calcContentHashIdWithFileType(content.getContent(), content.getFileType());
+ .calcContentHashIdWithFileType(content.getContent(), charset, content.getFileType());
} else {
previouslyCalculatedContentHashId = ContentHashesSupport.enumerateHash(hash);
}
@@ -459,9 +575,9 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
private static final ThreadLocalCachedByteArray ourSpareByteArray = new ThreadLocalCachedByteArray();
- private void savePersistentData(Map<Key, Value> data, int id, boolean delayedReading) {
+ private boolean savePersistentData(Map<Key, Value> data, int id, boolean delayedReading) {
try {
- if (delayedReading && myContents.containsMapping(id)) return;
+ if (delayedReading && myContents.containsMapping(id)) return false;
BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(ourSpareByteArray.getBuffer(4 * data.size()));
DataOutputStream stream = new DataOutputStream(out);
int size = data.size();
@@ -496,6 +612,7 @@ public class MapReduceIndex<Key, Value, Input> implements UpdatableIndex<Key,Val
} catch (IOException ex) {
throw new RuntimeException(ex);
}
+ return true;
}
private static final com.intellij.openapi.util.Key<Integer> ourSavedContentHashIdKey = com.intellij.openapi.util.Key.create("saved.content.hash.id");
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java
index 77c5b50581ea..103f7d5fb587 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java
@@ -255,8 +255,9 @@ public class ChangeBufferingList implements Cloneable {
if (intContainer == null && removals == 0) {
ValueContainer.IntIterator iterator = new ChangesIterator(changes, length);
if (DEBUG) {
- iterator = SortedFileIdSetIterator.getTransientIterator(iterator);
- DebugAssertions.assertTrue(iterator.size() == length);
+ ValueContainer.IntIterator iteratorSurelyWithoutDupes = SortedFileIdSetIterator.getTransientIterator(iterator);
+ DebugAssertions.assertTrue(iteratorSurelyWithoutDupes.size() == length);
+ iterator = iterator.createCopyInInitialState();
}
return iterator;
}