Merge branch 'master' of git.labs.intellij.net:idea/community

This commit is contained in:
irengrig
2011-01-25 18:49:58 +03:00
91 changed files with 1705 additions and 454 deletions
+1 -1
View File
@@ -1 +1 @@
102.SNAPSHOT
104.SNAPSHOT
+1 -1
View File
@@ -64,7 +64,7 @@ def wire_build_date(String buildNumber) {
target('default': 'The default target') {
depends(compile)
layoutAll(
buildNumber: "IC-102.SNAPSHOT",
buildNumber: "IC-104.SNAPSHOT",
version: "IdeaX",
system_selector: "IntelliJIdeaCE10",
jdk_req: "1.6*",
@@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
@@ -72,11 +73,23 @@ public class AddTypeArgumentsFix extends MethodArgumentFix {
final PsiElementFactory factory = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory();
PsiMethodCallExpression copy = (PsiMethodCallExpression)expression.copy();
final PsiReferenceParameterList parameterList = copy.getMethodExpression().getParameterList();
final PsiReferenceExpression methodExpression = copy.getMethodExpression();
final PsiReferenceParameterList parameterList = methodExpression.getParameterList();
LOG.assertTrue(parameterList != null);
for (PsiType mapping : mappings) {
parameterList.add(factory.createTypeElement(mapping));
}
if (methodExpression.getQualifierExpression() == null) {
final PsiExpression qualifierExpression;
final PsiClass containingClass = method.getContainingClass();
LOG.assertTrue(containingClass != null);
if (method.hasModifierProperty(PsiModifier.STATIC)) {
qualifierExpression = factory.createReferenceExpression(containingClass);
} else {
qualifierExpression = RefactoringUtil.createThisExpression(method.getManager(), null);
}
methodExpression.setQualifierExpression(qualifierExpression);
}
return copy;
}
@@ -71,7 +71,7 @@ public class ConvertReturnStatementsVisitor implements ReturnStatementsVisitor {
final String value = generateValue(returnStatement);
latestReplaced = (PsiReturnStatement) myFactory.createStatementFromText("return " + value+";", returnStatement.getParent());
returnStatement.replace(latestReplaced);
latestReplaced = (PsiReturnStatement)returnStatement.replace(latestReplaced);
}
return latestReplaced;
@@ -71,6 +71,10 @@ public class PlainEnterProcessor implements EnterProcessor {
else if (element instanceof PsiDoWhileStatement) {
body = ((PsiDoWhileStatement)element).getBody();
}
else if (element instanceof PsiMethod) {
PsiCodeBlock methodBody = ((PsiMethod)element).getBody();
if (methodBody != null) return methodBody;
}
return body instanceof PsiBlockStatement ? ((PsiBlockStatement)body).getCodeBlock() : null;
}
@@ -215,7 +215,8 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett
" x--;\n" +
" } while (x > 10) \n" +
" }\n" +
" public static void test() { \n" +
" public static void test() \n" +
" throws Exception { \n" +
" foo.foo().bar(\"arg1\", \n" +
" \"arg2\"); \n" +
" } \n" +
@@ -58,14 +58,15 @@ public class ClassLiteralGetter extends CompletionProvider<JavaSmartCompletionPa
return;
}
addClassLiteralLookupElement(classParameter, result, parameters.getPosition());
PsiFile file = parameters.getPosition().getContainingFile();
addClassLiteralLookupElement(classParameter, result, file);
if (addInheritors) {
addInheritorClassLiterals(parameters.getPosition(), shortNameCondition, classParameter, result);
addInheritorClassLiterals(file, shortNameCondition, classParameter, result);
}
}
private static void addInheritorClassLiterals(PsiElement context,
private static void addInheritorClassLiterals(PsiFile context,
Condition<String> shortNameCondition,
final PsiType classParameter,
CompletionResultSet result) {
@@ -79,7 +80,7 @@ public class ClassLiteralGetter extends CompletionProvider<JavaSmartCompletionPa
}
}
private static void addClassLiteralLookupElement(@Nullable final PsiType type, final CompletionResultSet resultSet, final PsiElement context) {
private static void addClassLiteralLookupElement(@Nullable final PsiType type, final CompletionResultSet resultSet, final PsiFile context) {
if (type instanceof PsiClassType &&
PsiUtil.resolveClassInType(type) != null &&
!((PsiClassType)type).hasParameters() &&
@@ -823,6 +823,7 @@ public abstract class AbstractJavaBlock extends AbstractBlock implements JavaBlo
if (role == ChildRole.TYPE_PARAMETER_LIST) return defaultAlignment;
if (role == ChildRole.TYPE) return defaultAlignment;
if (role == ChildRole.NAME) return defaultAlignment;
if (role == ChildRole.THROWS_LIST && mySettings.ALIGN_THROWS_KEYWORD) return defaultAlignment;
return null;
}
@@ -78,10 +78,13 @@ public class InlineUtil {
final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)expr).getMethodExpression();
final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
if (qualifierExpression == null) {
if (((PsiMethod)resolved).getModifierList().hasModifierProperty(PsiModifier.STATIC)) {
methodExpression.setQualifierExpression(elementFactory.createReferenceExpression(thisClass));
final PsiMethod method = (PsiMethod)resolved;
final PsiClass containingClass = method.getContainingClass();
LOG.assertTrue(containingClass != null);
if (method.getModifierList().hasModifierProperty(PsiModifier.STATIC)) {
methodExpression.setQualifierExpression(elementFactory.createReferenceExpression(containingClass));
} else {
methodExpression.setQualifierExpression(createThisExpression(manager, thisClass, refParent));
methodExpression.setQualifierExpression(createThisExpression(manager, containingClass, refParent));
}
}
}
@@ -0,0 +1,5 @@
class Foo {
@Test
public void testValueOf(<caret>)
}
@@ -0,0 +1,8 @@
class Foo {
@Test
public void testValueOf()
{
<caret>
}
}
@@ -0,0 +1,7 @@
// "Add explicit type arguments" "true"
import java.util.*;
class Test {
<T> List<T> f() { return new ArrayList<T>(); }
void g(List<Integer> a) {}
void someMethod() { g(this.<Integer>f()); }
}
@@ -0,0 +1,7 @@
// "Add explicit type arguments" "true"
import java.util.*;
class Test {
static <T> List<T> f() { return new ArrayList<T>(); }
void g(List<Integer> a) {}
void someMethod() { g(Test.<Integer>f()); }
}
@@ -0,0 +1,7 @@
// "Add explicit type arguments" "true"
import java.util.*;
class Test {
<T> List<T> f() { return new ArrayList<T>(); }
void g(List<Integer> a) {}
void someMethod() { g(f<caret>()); }
}
@@ -0,0 +1,7 @@
// "Add explicit type arguments" "true"
import java.util.*;
class Test {
static <T> List<T> f() { return new ArrayList<T>(); }
void g(List<Integer> a) {}
void someMethod() { g(<caret>f()); }
}
@@ -0,0 +1,23 @@
import java.util.ArrayList;
import java.util.List;
import static Statics._emptyList;
public class Statics {
public static <T> List<T> _emptyList() {
return new ArrayList<T>();
}
}
class Foo {
public static void main(String[] args) {
List<String> v1 = _emptyList();
doSomething(v<caret>1);
}
public static void doSomething(List<String> list) {
}
}
@@ -0,0 +1,22 @@
import java.util.ArrayList;
import java.util.List;
import static Statics._emptyList;
public class Statics {
public static <T> List<T> _emptyList() {
return new ArrayList<T>();
}
}
class Foo {
public static void main(String[] args) {
doSomething(Statics.<String>_emptyList());
}
public static void doSomething(List<String> list) {
}
}
@@ -184,7 +184,15 @@ public class CompleteStatementTest extends EditorActionTestCase {
public void testIDEADEV40479() throws Exception { doTest(); }
public void testIDEADEV13019() throws Exception {
public void testIDEADEV13019() throws Exception {
doTestBracesNextLineStyle();
}
public void testIDEA25139() throws Exception {
doTestBracesNextLineStyle();
}
private void doTestBracesNextLineStyle() throws Exception {
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject());
settings.BRACE_STYLE = CodeStyleSettings.NEXT_LINE;
settings.METHOD_BRACE_STYLE = CodeStyleSettings.NEXT_LINE;
@@ -251,4 +251,26 @@ public class JavaFormatterAlignmentTest extends AbstractJavaFormatterTest {
"}"
);
}
public void testAlignThrowsKeyword() throws Exception {
// Inspired by IDEA-63820
getSettings().ALIGN_THROWS_KEYWORD = true;
doClassTest(
"public void test()\n" +
" throws Exception {}",
"public void test()\n" +
"throws Exception {\n" +
"}"
);
getSettings().ALIGN_THROWS_KEYWORD = false;
doClassTest(
"public void test()\n" +
" throws Exception {}",
"public void test()\n" +
" throws Exception {\n" +
"}"
);
}
}
@@ -123,6 +123,10 @@ public class InlineLocalTest extends LightCodeInsightTestCase {
doTest(true);
}
public void testStaticImported() throws Exception {
doTest(true);
}
private void doTest(final boolean inlineDef, String conflictMessage) throws Exception {
try {
doTest(inlineDef);
@@ -56,7 +56,7 @@ public class LibrariesDownloadAssistant {
LOG.error(e);
}
catch (IOException e) {
LOG.error(e);
// no route to host, unknown host, etc.
}
}
@@ -299,6 +299,7 @@ public class CommonCodeStyleSettings {
public boolean ALIGN_MULTILINE_ASSIGNMENT = false;
public boolean ALIGN_MULTILINE_TERNARY_OPERATION = false;
public boolean ALIGN_MULTILINE_THROWS_LIST = false;
public boolean ALIGN_THROWS_KEYWORD = false;
public boolean ALIGN_MULTILINE_EXTENDS_LIST = false;
public boolean ALIGN_MULTILINE_METHOD_BRACKETS = false;
@@ -49,6 +49,7 @@ public class WrappingAndBracesPanel extends OptionTableWithPreviewPanel {
addOption("THROWS_LIST_WRAP", WRAPPING_THROWS_LIST, WRAP_OPTIONS, WRAP_VALUES);
addOption("ALIGN_MULTILINE_THROWS_LIST", ApplicationBundle.message("wrapping.align.when.multiline"), WRAPPING_THROWS_LIST);
addOption("ALIGN_THROWS_KEYWORD", ApplicationBundle.message("wrapping.align.throws.keyword"), WRAPPING_THROWS_LIST);
addOption("THROWS_KEYWORD_WRAP", WRAPPING_THROWS_KEYWORD, WRAP_OPTIONS_FOR_SINGLETON, WRAP_VALUES_FOR_SINGLETON);
addOption("METHOD_PARAMETERS_WRAP", WRAPPING_METHOD_PARAMETERS, WRAP_OPTIONS, WRAP_VALUES);
@@ -24,6 +24,8 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.UnknownFileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
@@ -33,6 +35,8 @@ import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
@@ -70,12 +74,22 @@ public class FileReferenceQuickFixProvider {
return Collections.emptyList();
}
PsiElement element = reference.getElement();
Module module = element != null ? ModuleUtil.findModuleForPsiElement(element) : null;
for (PsiFileSystemItem defaultContext : defaultContexts) {
if (defaultContext != null) {
final VirtualFile virtualFile = defaultContext.getVirtualFile();
if (virtualFile != null && defaultContext.isDirectory() && virtualFile.isInLocalFileSystem()) {
context = defaultContext;
break;
if (context == null) {
context = defaultContext;
}
else if (module != null && module == getModuleForContext(defaultContext)) {
// fixes IDEA-64156
// todo: fix it on PsiFileReferenceHelper level in 10.X
context = defaultContext;
break;
}
}
}
}
@@ -134,4 +148,10 @@ public class FileReferenceQuickFixProvider {
return Arrays.asList(action);
}
@Nullable
private static Module getModuleForContext(@NotNull PsiFileSystemItem context) {
VirtualFile file = context.getVirtualFile();
return file != null ? ModuleUtil.findModuleForFile(file, context.getProject()) : null;
}
}
@@ -55,6 +55,8 @@ public abstract class LookupManager {
public abstract Lookup showLookup(Editor editor, @NotNull LookupElement[] items, String prefix, @NotNull LookupArranger arranger);
public abstract void hideActiveLookup();
@Nullable
public abstract Lookup getActiveLookup();
@NonNls public static final String PROP_ACTIVE_LOOKUP = "activeLookup";
@@ -543,6 +543,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
final PsiFile file = getPsiFile();
if (file != null && !WriteCommandAction.ensureFilesWritable(myProject, Arrays.asList(file))) {
fireItemSelected(null, completionChar);
return;
}
@@ -19,7 +19,6 @@ package com.intellij.codeInsight.lookup.impl.actions;
import com.intellij.codeInsight.completion.CodeCompletionFeatures;
import com.intellij.codeInsight.completion.CompletionProcess;
import com.intellij.codeInsight.completion.CompletionService;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.lookup.impl.LookupImpl;
@@ -31,6 +30,7 @@ import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.actionSystem.EditorAction;
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
@@ -74,9 +74,10 @@ public class ChooseItemReplaceAction extends EditorAction {
final Editor editor = lookup.getEditor();
PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument());
final int offset = editor.getCaretModel().getOffset();
final String prefix = CompletionUtil.findJavaIdentifierPrefix(file, offset);
final TemplateImpl template = LiveTemplateCompletionContributor.findApplicableTemplate(file, offset, prefix);
final int end = editor.getCaretModel().getOffset();
final int start = lookup.getLookupStart();
final String prefix = editor.getDocument().getText(TextRange.create(start, end));
final TemplateImpl template = LiveTemplateCompletionContributor.findApplicableTemplate(file, end, prefix);
return template != null && shortcutChar == TemplateSettings.getInstance().getShortcutChar(template);
}
@@ -96,7 +96,7 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom
return handlers.toArray(new ProcessHandler[handlers.size()]);
}
public void compileAndRun(final Runnable startRunnable, final RunProfile configuration, final RunProfileState state, @Nullable final Runnable onCancelRunnable) {
public void compileAndRun(final Runnable startRunnable, final RunProfile configuration, final @Nullable RunProfileState state, @Nullable final Runnable onCancelRunnable) {
if (configuration instanceof RunConfiguration) {
final RunConfiguration runConfiguration = (RunConfiguration)configuration;
final RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(myProject);
@@ -112,7 +112,7 @@ public class ExecutionManagerImpl extends ExecutionManager implements ProjectCom
if (!activeProviders.isEmpty()) {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
ConfigurationPerRunnerSettings configurationSettings = state.getConfigurationSettings();
ConfigurationPerRunnerSettings configurationSettings = state != null ? state.getConfigurationSettings() : null;
DataContext projectContext = SimpleDataContext.getProjectContext(myProject);
final DataContext dataContext = configurationSettings != null ? SimpleDataContext
@@ -57,6 +57,7 @@ import com.intellij.ui.components.labels.LinkListener;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.text.BadLocationException;
@@ -106,10 +107,14 @@ class FindDialog extends DialogWrapper {
private JRadioButton myRbCustomScope;
private ScopeChooserCombo myScopeCombo;
private LivePreviewController myLivePreviewController;
public FindDialog(Project project, FindModel model, Runnable myOkHandler){
super(project, true);
myProject = project;
myModel = model;
this.myOkHandler = myOkHandler;
if (myModel.isReplaceState()){
@@ -133,6 +138,7 @@ class FindDialog extends DialogWrapper {
setOKButtonIcon(IconLoader.getIcon("/actions/find.png"));
init();
initByModel();
myLivePreviewController = new LivePreviewController(this, new LivePreview(myProject), getContentPane());
}
@Override
@@ -141,6 +147,9 @@ class FindDialog extends DialogWrapper {
e.getKey().removeDocumentListener(e.getValue());
}
myComboBoxListeners.clear();
if (myLivePreviewController != null) {
myLivePreviewController.cleanUp();
}
super.dispose();
}
@@ -274,6 +283,22 @@ class FindDialog extends DialogWrapper {
validateFindButton();
}
public FindModel getModel() {
return myModel;
}
@Nullable
public FindModel getCurrentModel() {
FindModel validateModel = (FindModel)myModel.clone();
applyTo(validateModel, false);
if (getValidationInfo(validateModel) == null) {
return validateModel;
}
return null;
}
private static int getCaretPosition(JComboBox comboBox) {
Component editorComponent = comboBox.getEditor().getEditorComponent();
if (editorComponent instanceof JTextField){
@@ -293,7 +318,6 @@ class FindDialog extends DialogWrapper {
private void validateFindButton() {
final String toFind = getStringToFind();
if (toFind == null || toFind.length() == 0){
setOKStatus(false);
return;
@@ -416,76 +440,130 @@ class FindDialog extends DialogWrapper {
private void doOKAction(boolean findAll) {
FindModel validateModel = (FindModel)myModel.clone();
applyTo(validateModel);
validateModel.setFindAll(findAll);
if (validateModel.getDirectoryName() != null) {
PsiDirectory directory = FindInProjectUtil.getPsiDirectory(validateModel, myProject);
if (directory == null) {
applyTo(validateModel, findAll);
ValidationInfo validationInfo = getValidationInfo(validateModel);
if (validationInfo == null) {
myModel.copyFrom(validateModel);
updateFindSettings();
super.doOKAction();
myOkHandler.run();
} else {
String message = validationInfo.message;
if (message != null) {
Messages.showMessageDialog(
myProject,
FindBundle.message("find.directory.not.found.error", validateModel.getDirectoryName()),
message,
CommonBundle.getErrorTitle(),
Messages.getErrorIcon()
);
return;
}
}
}
if (validateModel.isRegularExpressions()) {
String toFind = validateModel.getStringToFind();
try {
Pattern pattern = Pattern.compile(toFind, validateModel.isCaseSensitive() ? Pattern.MULTILINE : Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
if (pattern.matcher("").matches() && !toFind.endsWith("$") && !toFind.startsWith("^")) {
throw new PatternSyntaxException(FindBundle.message("find.empty.match.regular.expression.error"),toFind, -1);
}
}
catch(PatternSyntaxException e){
Messages.showMessageDialog(
myProject,
FindBundle.message("find.invalid.regular.expression.error", toFind, e.getDescription()),
CommonBundle.getErrorTitle(),
Messages.getErrorIcon()
);
return;
}
private void updateFindSettings() {
FindSettings findSettings = FindSettings.getInstance();
findSettings.setCaseSensitive(myModel.isCaseSensitive());
if (myModel.isReplaceState()) {
findSettings.setPreserveCase(myModel.isPreserveCase());
}
validateModel.setFileFilter( null );
FindSettings.getInstance().setFileMask(null);
findSettings.setWholeWordsOnly(myModel.isWholeWordsOnly());
findSettings.setInStringLiteralsOnly(myModel.isInStringLiteralsOnly());
findSettings.setInCommentsOnly(myModel.isInCommentsOnly());
if (useFileFilter!=null && useFileFilter.isSelected() &&
myFileFilter.getSelectedItem()!=null
) {
final String mask = (String)myFileFilter.getSelectedItem();
findSettings.setRegularExpressions(myModel.isRegularExpressions());
if (!myModel.isMultipleFiles()){
findSettings.setForward(myModel.isForward());
findSettings.setFromCursor(myModel.isFromCursor());
if (mask.length() > 0) {
try {
FindInProjectUtil.createFileMaskRegExp(mask); // verify that the regexp compiles
validateModel.setFileFilter(mask);
FindSettings.getInstance().setFileMask(mask);
}
catch (PatternSyntaxException ex) {
Messages.showMessageDialog(myProject, FindBundle.message("find.filter.invalid.file.mask.error", myFileFilter.getSelectedItem()),
CommonBundle.getErrorTitle(), Messages.getErrorIcon());
return;
}
findSettings.setGlobal(myModel.isGlobal());
} else{
String directoryName = myModel.getDirectoryName();
if (directoryName != null && !directoryName.isEmpty()) {
findSettings.setWithSubdirectories(myModel.isWithSubdirectories());
}
else {
Messages.showMessageDialog(myProject, FindBundle.message("find.filter.empty.file.mask.error"), CommonBundle.getErrorTitle(),
Messages.getErrorIcon());
return;
else if (myRbModule.isSelected()) {
}
else if (myRbCustomScope.isSelected()) {
SearchScope selectedScope = myScopeCombo.getSelectedScope();
String customScopeName = selectedScope == null ? null : selectedScope.getDisplayName();
findSettings.setCustomScope(customScopeName);
}
}
if (myCbToSkipResultsWhenOneUsage != null){
FindSettings.getInstance().setSkipResultsWithOneUsage(
findSettings.setSkipResultsWithOneUsage(
isSkipResultsWhenOneUsage()
);
}
myModel.copyFrom(validateModel);
super.doOKAction();
myOkHandler.run();
findSettings.setFileMask(myModel.getFileFilter());
}
@Override
protected boolean postponeValidation() {
return true;
}
private ValidationInfo getValidationInfo(FindModel model) {
if (myRbDirectory != null && myRbDirectory.isEnabled() && myRbDirectory.isSelected()) {
PsiDirectory directory = FindInProjectUtil.getPsiDirectory(model, myProject);
if (directory == null) {
return new ValidationInfo(FindBundle.message("find.directory.not.found.error", getDirectory()), myDirectoryComboBox);
}
}
String toFind = (String)myInputComboBox.getSelectedItem();
if (toFind != null && toFind.isEmpty()) {
return new ValidationInfo("String to find is empty", myInputComboBox);
}
if (myCbRegularExpressions != null && myCbRegularExpressions.isEnabled()) {
try {
boolean isCaseSensitive = myCbCaseSensitive != null && myCbCaseSensitive.isEnabled();
Pattern pattern =
Pattern.compile(toFind, isCaseSensitive ? Pattern.MULTILINE : Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
if (pattern.matcher("").matches() && !toFind.endsWith("$") && !toFind.startsWith("^")) {
return new ValidationInfo(FindBundle.message("find.empty.match.regular.expression.error"), myInputComboBox);
}
}
catch (PatternSyntaxException e) {
return new ValidationInfo(FindBundle.message("find.invalid.regular.expression.error", toFind, e.getDescription()), myInputComboBox);
}
}
final String mask = myFileFilter == null ? null : (String)myFileFilter.getSelectedItem();
if (mask != null) {
if (mask.length() == 0) {
return new ValidationInfo(FindBundle.message("find.filter.empty.file.mask.error"), myFileFilter);
}
else {
try {
FindInProjectUtil.createFileMaskRegExp(mask); // verify that the regexp compiles
}
catch (PatternSyntaxException ex) {
return new ValidationInfo(FindBundle.message("find.filter.invalid.file.mask.error", mask), myFileFilter);
}
}
}
return null;
}
@Override
protected ValidationInfo doValidate() {
FindModel validateModel = (FindModel)myModel.clone();
applyTo(validateModel, false);
ValidationInfo result = getValidationInfo(validateModel);
setOKStatus(result == null);
return result;
}
public void doHelpAction() {
@@ -768,7 +846,7 @@ class FindDialog extends DialogWrapper {
public void consume(final VirtualFile[] files) {
if (files.length != 0) {
myDirectoryComboBox.setSelectedItem(files[0].getPresentableUrl());
validateFindButton();
//validateFindButton();
}
}
});
@@ -845,10 +923,12 @@ class FindDialog extends DialogWrapper {
}
private String getStringToFind() {
return (String)myInputComboBox.getEditor().getItem();
String string = (String)myInputComboBox.getEditor().getItem();
return string == null ? "" : string;
}
private String getStringToReplace() {
return (String)myReplaceComboBox.getEditor().getItem();
String item = (String)myReplaceComboBox.getEditor().getItem();
return item == null ? "" : item;
}
private String getDirectory() {
@@ -886,27 +966,26 @@ class FindDialog extends DialogWrapper {
}
}
private void applyTo(FindModel model) {
FindSettings findSettings = FindSettings.getInstance();
private void applyTo(FindModel model, boolean findAll) {
model.setCaseSensitive(myCbCaseSensitive.isSelected());
findSettings.setCaseSensitive(myCbCaseSensitive.isSelected());
if (model.isReplaceState()) {
model.setPreserveCase(myCbPreserveCase.isSelected());
findSettings.setPreserveCase(myCbPreserveCase.isSelected());
}
model.setWholeWordsOnly(myCbWholeWordsOnly.isSelected());
findSettings.setWholeWordsOnly(myCbWholeWordsOnly.isSelected());
model.setInStringLiteralsOnly(myCbInStringLiteralsOnly.isSelected());
findSettings.setInStringLiteralsOnly(myCbInStringLiteralsOnly.isSelected());
model.setInCommentsOnly(myCbInCommentsOnly.isSelected());
findSettings.setInCommentsOnly(myCbInCommentsOnly.isSelected());
model.setRegularExpressions(myCbRegularExpressions.isSelected());
findSettings.setRegularExpressions(myCbRegularExpressions.isSelected());
model.setStringToFind(getStringToFind());
String stringToFind = getStringToFind();
if (stringToFind.length() > 0) {
model.setStringToFind(stringToFind);
}
if (model.isReplaceState()){
model.setPromptOnReplace(true);
@@ -920,11 +999,8 @@ class FindDialog extends DialogWrapper {
if (!model.isMultipleFiles()){
model.setForward(myRbForward.isSelected());
findSettings.setForward(myRbForward.isSelected());
model.setFromCursor(myRbFromCursor.isSelected());
findSettings.setFromCursor(myRbFromCursor.isSelected());
model.setGlobal(myRbGlobal.isSelected());
findSettings.setGlobal(myRbGlobal.isSelected());
}
else{
if (myCbToOpenInNewTab != null){
@@ -942,7 +1018,6 @@ class FindDialog extends DialogWrapper {
String directory = getDirectory();
model.setDirectoryName(directory == null ? "" : directory);
model.setWithSubdirectories(myCbWithSubdirectories.isSelected());
findSettings.setWithSubdirectories(myCbWithSubdirectories.isSelected());
}
else if (myRbModule.isSelected()) {
model.setModuleName((String)myModuleComboBox.getSelectedItem());
@@ -953,9 +1028,17 @@ class FindDialog extends DialogWrapper {
model.setCustomScopeName(customScopeName);
model.setCustomScope(selectedScope == null ? null : selectedScope);
model.setCustomScope(true);
findSettings.setCustomScope(customScopeName);
}
}
model.setFindAll(findAll);
String mask = null;
if (useFileFilter!=null && useFileFilter.isSelected()) {
mask = (String)myFileFilter.getSelectedItem();
}
model.setFileFilter(mask);
}
@@ -1061,7 +1144,7 @@ class FindDialog extends DialogWrapper {
setStringsToComboBox(FindSettings.getInstance().getRecentReplaceStrings(), myReplaceComboBox, myModel.getStringToReplace());
}
updateControls();
validateFindButton();
}
}
@@ -0,0 +1,27 @@
package com.intellij.find.impl;
import com.intellij.openapi.util.TextRange;
import java.util.ArrayList;
import java.util.Collection;
public class LiveOccurrence {
private TextRange myPrimaryRange;
private Collection<TextRange> mySecondaryRanges = new ArrayList<TextRange>();
public TextRange getPrimaryRange() {
return myPrimaryRange;
}
public Collection<TextRange> getSecondaryRanges() {
return mySecondaryRanges;
}
public void setPrimaryRange(TextRange primaryRange) {
this.myPrimaryRange = primaryRange;
}
public void setSecondaryRanges(Collection<TextRange> secondaryRanges) {
this.mySecondaryRanges = secondaryRanges;
}
}
@@ -0,0 +1,421 @@
package com.intellij.find.impl;
import com.intellij.codeInsight.highlighting.HighlightManager;
import com.intellij.ide.IdeTooltipManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.VisualPosition;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.VisibleAreaEvent;
import com.intellij.openapi.editor.event.VisibleAreaListener;
import com.intellij.openapi.editor.markup.CustomHighlighterRenderer;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.BalloonBuilder;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Alarm;
import com.intellij.util.containers.HashSet;
import com.intellij.util.ui.PositionTracker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
public class LivePreview extends DocumentAdapter {
private final Collection<RangeHighlighter> myHighlighters = new HashSet<RangeHighlighter>();
private RangeHighlighter myCursorHighlighter;
private final List<VisibleAreaListener> myVisibleAreaListenersToRemove = new ArrayList<VisibleAreaListener>();
public interface Delegate {
@NotNull
List<LiveOccurrence> performSearchInBackgroundInReadAction(Editor editor);
@Nullable
String getReplacementPreviewText(Editor editor, LiveOccurrence liveOccurrence);
}
private static final int USER_ACTIVITY_TRIGGERING_DELAY = 300;
private static final TextAttributes OTHER_TARGETS_ATTRIBUTES = new TextAttributes(Color.BLACK, Color.GREEN, null, null, 0);
private static final TextAttributes MAIN_TARGET_ATTRIBUTES = new TextAttributes(Color.BLACK, Color.YELLOW, null, null, 0);
private final Alarm myLivePreviewAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
private final Project myProject;
private Editor myEditor;
private Delegate myDelegate;
private LiveOccurrence myCursor;
private List<LiveOccurrence> mySearchResults;
private Balloon myReplacementBalloon;
public LivePreview(Project project) {
this.myProject = project;
updateEditorReference();
}
public Delegate getDelegate() {
return myDelegate;
}
public void setDelegate(Delegate delegate) {
this.myDelegate = delegate;
}
@Nullable
public Editor updateEditorReference() {
if (myProject == null) return null;
FileEditorManagerEx instanceEx = FileEditorManagerEx.getInstanceEx(myProject);
if (instanceEx != null) {
VirtualFile currentFile = instanceEx.getCurrentFile();
if (currentFile != null) {
FileEditor[] editors = instanceEx.getEditors(currentFile);
if (editors.length > 0) {
FileEditor fileEditor = editors[0];
boolean focusedFound = false;
for (FileEditor e : editors) {
if (e instanceof TextEditor && ((TextEditor)e).getEditor().getContentComponent().hasFocus()) {
fileEditor = e;
focusedFound = true;
}
}
boolean needToUpdate = true;
if (!focusedFound) {
for (FileEditor e : editors) {
if (e instanceof TextEditor && ((TextEditor)e).getEditor() == myEditor) {
needToUpdate = false;
}
}
}
if (needToUpdate && fileEditor instanceof TextEditor) {
Editor editor1 = ((TextEditor) fileEditor).getEditor();
if (editor1 != myEditor) {
cleanUp();
}
if (myEditor != null) {
myEditor.getDocument().removeDocumentListener(this);
}
myEditor = editor1;
myEditor.getDocument().addDocumentListener(this);
}
} else {
myEditor = null;
}
} else {
myEditor = null;
}
}
return myEditor;
}
@Override
public void documentChanged(DocumentEvent e) {
update();
}
public void update() {
myLivePreviewAlarm.cancelAllRequests();
if (updateEditorReference() != null) {
myLivePreviewAlarm.addRequest(new Runnable() {
@Override
public void run() {
updateInBackground();
}
}, USER_ACTIVITY_TRIGGERING_DELAY);
}
}
public void cleanUp() {
if (myReplacementBalloon != null) {
myReplacementBalloon.hide();
}
if (myEditor != null) {
for (VisibleAreaListener visibleAreaListener : myVisibleAreaListenersToRemove) {
myEditor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener);
}
myVisibleAreaListenersToRemove.clear();
for (RangeHighlighter h : myHighlighters) {
HighlightManager.getInstance(myProject).removeSegmentHighlighter(myEditor, h);
}
if (myCursorHighlighter != null) {
HighlightManager.getInstance(myProject).removeSegmentHighlighter(myEditor, myCursorHighlighter);
myCursorHighlighter = null;
}
}
}
private void updateInBackground() {
if (myDelegate == null) return;
final TextRange oldCursorRange = myCursor != null ? myCursor.getPrimaryRange() : null;
mySearchResults = performSearchInBackground();
Collections.sort(mySearchResults, new Comparator<LiveOccurrence>() {
@Override
public int compare(LiveOccurrence liveOccurrence, LiveOccurrence liveOccurence1) {
return liveOccurrence.getPrimaryRange().getStartOffset() - liveOccurence1.getPrimaryRange().getStartOffset();
}
});
if (mySearchResults != null) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
cleanUp();
highlightUsages(oldCursorRange);
}
});
}
}
private List<LiveOccurrence> performSearchInBackground() {
final AtomicReference<List<LiveOccurrence>> occurrences = new AtomicReference<List<LiveOccurrence>>();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
occurrences.set(myDelegate.performSearchInBackgroundInReadAction(myEditor));
}
});
return occurrences.get();
}
private void highlightUsages(TextRange oldCursorRange) {
if (myEditor == null) return;
LiveOccurrence firstVisibleOccurrence = null;
LiveOccurrence firstOccurrence = null;
int offset = Integer.MAX_VALUE;
for (LiveOccurrence o : mySearchResults) {
if (insideVisibleArea(myEditor, o.getPrimaryRange())) {
if (firstVisibleOccurrence == null || o.getPrimaryRange().getStartOffset() < firstVisibleOccurrence.getPrimaryRange().getStartOffset()) {
firstVisibleOccurrence = o;
}
}
if (o.getPrimaryRange().getStartOffset() < offset) {
offset = o.getPrimaryRange().getStartOffset();
firstOccurrence = o;
}
for (TextRange textRange : o.getSecondaryRanges()) {
highlightRange(textRange, OTHER_TARGETS_ATTRIBUTES, myHighlighters);
}
highlightRange(o.getPrimaryRange(), MAIN_TARGET_ATTRIBUTES, myHighlighters);
}
if (!tryToRepairOldCursor(oldCursorRange)) {
setCursor(firstVisibleOccurrence != null ? firstVisibleOccurrence : firstOccurrence);
}
}
private boolean tryToRepairOldCursor(TextRange oldCursorRange) {
if (oldCursorRange == null) return false;
LiveOccurrence mayBeOldCursor = null;
for (LiveOccurrence searchResult : mySearchResults) {
if (searchResult.getPrimaryRange().intersects(oldCursorRange)) {
mayBeOldCursor = searchResult;
break;
}
}
if (mayBeOldCursor != null && insideVisibleArea(myEditor, mayBeOldCursor.getPrimaryRange())) {
setCursor(mayBeOldCursor);
return true;
}
return false;
}
@Nullable
private LiveOccurrence prevOccurrence(LiveOccurrence o) {
if (mySearchResults == null) return null;
for (int i = 0; i < mySearchResults.size(); ++i) {
if (o == mySearchResults.get(i)) {
if (i > 0) {
return mySearchResults.get(i-1);
}
}
}
return null;
}
@Nullable
private LiveOccurrence nextOccurrence(LiveOccurrence o) {
if (mySearchResults == null) return null;
boolean found = false;
for (LiveOccurrence occurrence : mySearchResults) {
if (found) {
return occurrence;
}
if (o == occurrence) {
found = true;
}
}
return null;
}
public void prevOccurrence() {
LiveOccurrence prev = prevOccurrence(myCursor);
if (prev == null && !mySearchResults.isEmpty()) {
prev = mySearchResults.get(mySearchResults.size()-1);
}
moveCursorTo(prev);
}
public void nextOccurrence() {
LiveOccurrence next = nextOccurrence(myCursor);
if (next == null && !mySearchResults.isEmpty()) {
next = mySearchResults.get(0);
}
moveCursorTo(next);
}
public void moveCursorTo(LiveOccurrence next) {
if (next != null) {
setCursor(next);
} else {
showReplacementPreview();
}
}
private void setCursor(LiveOccurrence liveOccurrence) {
hideBalloon();
myCursor = liveOccurrence;
if (myCursorHighlighter != null) {
HighlightManager.getInstance(myProject).removeSegmentHighlighter(myEditor, myCursorHighlighter);
myCursorHighlighter = null;
}
if (myCursor != null) {
ArrayList<RangeHighlighter> dummy = new ArrayList<RangeHighlighter>();
highlightRange(myCursor.getPrimaryRange(), new TextAttributes(null, null, null, null, 0), dummy);
if (!dummy.isEmpty()) {
myCursorHighlighter = dummy.get(0);
myCursorHighlighter.setCustomRenderer(new CustomHighlighterRenderer() {
@Override
public void paint(Editor editor, RangeHighlighter highlighter, Graphics g) {
Graphics2D g2d = (Graphics2D)g;
VisualPosition startVp = editor.offsetToVisualPosition(highlighter.getStartOffset());
VisualPosition endVp = editor.offsetToVisualPosition(highlighter.getEndOffset());
Point start = editor.visualPositionToXY(startVp);
Point end = editor.visualPositionToXY(endVp);
g2d.setColor(Color.YELLOW);
Point startP = new Point(start.x-5, start.y-5);
int lineHeight = editor.getLineHeight();
Point endP = new Point(start.x-5, end.y+ lineHeight +10);
g2d.setPaint(new GradientPaint(startP, Color.YELLOW, endP, new Color(255, 200, 0)));
g2d.fillRoundRect(startP.x, startP.y,
end.x - start.x+10, lineHeight +10, 10, 10);
g2d.setColor(Color.GRAY);
g2d.drawRoundRect(start.x - 5, start.y - 5,
end.x - start.x + 10, lineHeight + 10, 10, 10);
}
});
}
if (!insideVisibleArea(myEditor, myCursor.getPrimaryRange())) {
myEditor.getScrollingModel().scrollTo(myEditor.offsetToLogicalPosition(myCursor.getPrimaryRange().getStartOffset()),
ScrollType.CENTER);
myEditor.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
@Override
public void run() {
showReplacementPreview();
}
});
} else {
showReplacementPreview();
}
}
}
private void showReplacementPreview() {
hideBalloon();
if (myDelegate != null && myCursor != null) {
String replacementPreviewText = myDelegate.getReplacementPreviewText(myEditor, myCursor);
if (replacementPreviewText != null) {
JLabel balloonContent = new JLabel(replacementPreviewText);
balloonContent.setForeground(Color.WHITE);
BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createBalloonBuilder(balloonContent);
balloonBuilder.setFadeoutTime(0);
balloonBuilder.setFillColor(IdeTooltipManager.GRAPHITE_COLOR);
balloonBuilder.setAnimationCycle(0);
balloonBuilder.setHideOnClickOutside(false);
balloonBuilder.setHideOnKeyOutside(false);
balloonBuilder.setHideOnAction(false);
myReplacementBalloon = balloonBuilder.createBalloon();
final int startOffset = myCursor.getPrimaryRange().getStartOffset();
final int endOffset = myCursor.getPrimaryRange().getEndOffset();
myReplacementBalloon.show(new PositionTracker<Balloon>(myEditor.getContentComponent()) {
@Override
public RelativePoint recalculateLocation(final Balloon object) {
Point startPoint = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(startOffset));
Point endPoint = myEditor.visualPositionToXY(myEditor.offsetToVisualPosition(endOffset));
Point point = new Point((startPoint.x + endPoint.x)/2, startPoint.y);
if (!insideVisibleArea(myEditor, myCursor.getPrimaryRange())) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
object.hide();
}
});
VisibleAreaListener visibleAreaListener = new VisibleAreaListener() {
@Override
public void visibleAreaChanged(VisibleAreaEvent e) {
if (insideVisibleArea(myEditor, myCursor.getPrimaryRange())) {
showReplacementPreview();
final VisibleAreaListener visibleAreaListener = this;
myEditor.getScrollingModel().removeVisibleAreaListener(visibleAreaListener);
myVisibleAreaListenersToRemove.remove(visibleAreaListener);
}
}
};
myEditor.getScrollingModel().addVisibleAreaListener(visibleAreaListener);
myVisibleAreaListenersToRemove.add(visibleAreaListener);
}
return new RelativePoint(myEditor.getContentComponent(), point);
}
}, Balloon.Position.above);
}
}
}
private void hideBalloon() {
if (myReplacementBalloon != null) {
myReplacementBalloon.hide();
myReplacementBalloon = null;
}
}
private void highlightRange(TextRange textRange, TextAttributes attributes, Collection<RangeHighlighter> highlighters) {
HighlightManager highlightManager = HighlightManager.getInstance(myProject);
if (highlightManager != null) {
highlightManager.addRangeHighlight(myEditor,
textRange.getStartOffset(), textRange.getEndOffset(),
attributes, true, highlighters);
}
}
private static boolean insideVisibleArea(Editor e, TextRange r) {
Rectangle visibleArea = e.getScrollingModel().getVisibleArea();
Point point = e.logicalPositionToXY(e.offsetToLogicalPosition(r.getStartOffset()));
return visibleArea.contains(point);
}
}
@@ -0,0 +1,138 @@
package com.intellij.find.impl;
import com.intellij.find.FindManager;
import com.intellij.find.FindModel;
import com.intellij.find.FindResult;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.UserActivityListener;
import com.intellij.ui.UserActivityWatcher;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class LivePreviewController implements LivePreview.Delegate, UserActivityListener {
private static final String EMPTY_STRING_DISPLAY_TEXT = "<Empty string>";
private final FindDialog myFindDialog;
private final LivePreview myLivePreview;
private final UserActivityWatcher myWatcher = new MomentoUserActivityWatcher();
private int myMatchesLimit = 100;
public LivePreviewController(FindDialog findDialog, LivePreview livePreview, Component toWatch) {
myFindDialog = findDialog;
myLivePreview = livePreview;
myLivePreview.setDelegate(this);
myWatcher.register(toWatch);
myWatcher.addUserActivityListener(this);
myFindDialog.getWindow().addWindowFocusListener(new WindowFocusListener() {
@Override
public void windowGainedFocus(WindowEvent windowEvent) {
myLivePreview.update();
}
@Override
public void windowLostFocus(WindowEvent windowEvent) {
}
});
JComponent contentPane = (JComponent)findDialog.getContentPane();
new AnAction() {
@Override
public void actionPerformed(AnActionEvent e) {
myLivePreview.nextOccurrence();
}
}.registerCustomShortcutSet(KeyEvent.VK_F3, 0, contentPane);
new AnAction() {
@Override
public void actionPerformed(AnActionEvent e) {
myLivePreview.prevOccurrence();
}
}.registerCustomShortcutSet(KeyEvent.VK_F3, KeyEvent.SHIFT_MASK, contentPane);
}
public void cleanUp() {
myWatcher.removeUserActivityListener(this);
myLivePreview.cleanUp();
}
public void setMatchesLimit(int matchesLimit) {
myMatchesLimit = matchesLimit;
}
public int getMatchesLimit() {
return myMatchesLimit;
}
@NotNull
@Override
public List<LiveOccurrence> performSearchInBackgroundInReadAction(Editor editor) {
ArrayList<LiveOccurrence> occurrences = new ArrayList<LiveOccurrence>();
FindModel currentModel = myFindDialog.getCurrentModel();
if (currentModel != null) {
int offset = 0;
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(editor.getDocument());
ArrayList<FindResult> results = new ArrayList<FindResult>();
while (true) {
FindManager findManager = FindManager.getInstance(editor.getProject());
FindResult result = findManager.findString(editor.getDocument().getCharsSequence(), offset, currentModel, virtualFile);
if (!result.isStringFound()) break;
int newOffset = result.getEndOffset();
if (offset == newOffset) break;
offset = newOffset;
results.add(result);
if (results.size() > myMatchesLimit) break;
}
if (results.size() < myMatchesLimit) {
findResultsToOccurrences(results, occurrences);
}
}
return occurrences;
}
@Override
public String getReplacementPreviewText(Editor editor, LiveOccurrence liveOccurrence) {
String foundString = editor.getDocument().getText(liveOccurrence.getPrimaryRange());
String documentText = editor.getDocument().getText();
FindModel currentModel = myFindDialog.getCurrentModel();
String stringToReplace = null;
if (currentModel != null) {
if (currentModel.isReplaceState()) {
FindManager findManager = FindManager.getInstance(editor.getProject());
stringToReplace = findManager.getStringToReplace(foundString, currentModel,
liveOccurrence.getPrimaryRange().getStartOffset(), documentText);
if (stringToReplace != null && stringToReplace.isEmpty()) {
stringToReplace = EMPTY_STRING_DISPLAY_TEXT;
}
}
}
return stringToReplace;
}
private static void findResultsToOccurrences(ArrayList<FindResult> results, Collection<LiveOccurrence> occurrences) {
for (FindResult r : results) {
LiveOccurrence occurrence = new LiveOccurrence();
occurrence.setPrimaryRange(r);
occurrences.add(occurrence);
}
}
@Override
public void stateChanged() {
myLivePreview.update();
}
}
@@ -0,0 +1,31 @@
package com.intellij.find.impl;
import com.intellij.ui.UserActivityWatcher;
import java.awt.*;
import java.util.HashSet;
import java.util.Set;
public class MomentoUserActivityWatcher extends UserActivityWatcher {
Set<Component> components = new HashSet<Component>();
@Override
protected void processComponent(Component parentComponent) {
if (!components.contains(parentComponent)) {
super.processComponent(parentComponent);
components.add(parentComponent);
}
}
@Override
protected void unprocessComponent(Component component) {
components.remove(component);
super.unprocessComponent(component);
}
public boolean isWatched(Component c) {
return components.contains(c);
}
}
@@ -109,7 +109,9 @@ public abstract class BaseProjectTreeBuilder extends AbstractTreeBuilder {
}
protected final void expandNodeChildren(final DefaultMutableTreeNode node) {
Object element = ((NodeDescriptor)node.getUserObject()).getElement();
final NodeDescriptor userObject = (NodeDescriptor)node.getUserObject();
if (userObject == null) return;
Object element = userObject.getElement();
VirtualFile virtualFile = getFileToRefresh(element);
super.expandNodeChildren(node);
if (virtualFile != null) {
@@ -375,6 +375,24 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
myLibraries.clear();
myLibraries.putAll(myOldLibraries);
}
@Override
public Set<VirtualFile> getSourceFiles() {
Set<VirtualFile> sourceFiles = new HashSet<VirtualFile>();
for (ScriptingLibraryTable.LibraryModel libModel : myLibraries.values()) {
sourceFiles.addAll(libModel.getSourceFiles());
}
return sourceFiles;
}
@Override
public Set<VirtualFile> getCompactFiles() {
Set<VirtualFile> compactFiles = new HashSet<VirtualFile>();
for (ScriptingLibraryTable.LibraryModel libModel : myLibraries.values()) {
compactFiles.addAll(libModel.getCompactFiles());
}
return compactFiles;
}
}
/**
@@ -400,6 +418,21 @@ public class ScriptingLibraryMappings extends LanguagePerFileMappings<ScriptingL
}
return isApplicable(libFile, srcFile.getParent());
}
public Set<VirtualFile> getLibraryFilesFor(VirtualFile srcFile) {
Set<VirtualFile> libFiles = new HashSet<VirtualFile>();
collectLibraryFilesFor(srcFile, libFiles);
return libFiles;
}
private void collectLibraryFilesFor(VirtualFile file, Set<VirtualFile> libFiles) {
if (file == null) return;
ScriptingLibraryTable.LibraryModel libraryModel = getMapping(file);
if (libraryModel != null) {
libFiles.addAll(libraryModel.getCompactFiles());
libFiles.addAll(libraryModel.getSourceFiles());
}
collectLibraryFilesFor(file.getParent(), libFiles);
}
}
@@ -44,6 +44,7 @@ import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
public class EditLibraryDialog extends DialogWrapper {
@@ -290,11 +291,11 @@ public class EditLibraryDialog extends DialogWrapper {
fireTableDataChanged();
}
public void setFiles(VirtualFile[] sourceFiles, VirtualFile[] compactFiles) {
public void setFiles(Set<VirtualFile> sourceFiles, Set<VirtualFile> compactFiles) {
myFiles.clear();
myFiles.addAll(Arrays.asList(sourceFiles));
myFiles.addAll(Arrays.asList(compactFiles));
myCompactFiles.addAll(Arrays.asList(compactFiles));
myFiles.addAll(sourceFiles);
myFiles.addAll(compactFiles);
myCompactFiles.addAll(compactFiles);
}
public void setFileType(VirtualFile file, boolean isCompact) {
@@ -30,7 +30,7 @@ public class ScriptingLibrariesScope extends GlobalSearchScope {
private GlobalSearchScope myBaseScope;
private ScriptingIndexableSetContributor myContributor;
private Set<VirtualFile> myLibraryFiles;
protected Set<VirtualFile> myLibraryFiles;
public ScriptingLibrariesScope(GlobalSearchScope baseScope, Class<? extends IndexableSetContributor> providerClass) {
super(baseScope.getProject());
@@ -38,21 +38,16 @@ public class ScriptingLibrariesScope extends GlobalSearchScope {
IndexableSetContributor contributor = IndexableSetContributor.EP_NAME.findExtension(providerClass);
if (contributor instanceof ScriptingIndexableSetContributor) {
myContributor = (ScriptingIndexableSetContributor)contributor;
updateLibraryFiles();
setLibraryFiles();
}
}
public void updateLibraryFiles() {
public void setLibraryFiles() {
myLibraryFiles = myContributor.getLibraryFiles(myBaseScope.getProject());
}
public boolean contains(VirtualFile file) {
return myBaseScope.contains(file) | contributorContains(file);
}
private boolean contributorContains(VirtualFile file) {
if (myContributor == null) return false;
return myLibraryFiles.contains(file);
return myBaseScope.contains(file) | (myLibraryFiles == null ? false : myLibraryFiles.contains(file));
}
@Override
@@ -79,7 +79,7 @@ public class ScriptingLibraryTable {
if (myCompactFilesCache == null) {
myCompactFilesCache = new HashSet<VirtualFile>();
for (LibraryModel libraryModel : myLibraryModels) {
myCompactFilesCache.addAll(Arrays.asList(libraryModel.getCompactFiles()));
myCompactFilesCache.addAll(libraryModel.getCompactFiles());
}
}
return myCompactFilesCache.contains(file);
@@ -149,8 +149,8 @@ public class ScriptingLibraryTable {
public static class LibraryModel {
private String myName;
private ArrayList<VirtualFile> mySourceFiles = new ArrayList<VirtualFile>();
private ArrayList<VirtualFile> myCompactFiles = new ArrayList<VirtualFile>();
private Set<VirtualFile> mySourceFiles = new HashSet<VirtualFile>();
private Set<VirtualFile> myCompactFiles = new HashSet<VirtualFile>();
private ArrayList<String> myDocUrls = new ArrayList<String>();
public LibraryModel(String name, VirtualFile[] sourceFiles, VirtualFile[] compactFiles, String[] docUrls) {
@@ -183,12 +183,12 @@ public class ScriptingLibraryTable {
myDocUrls.addAll(Arrays.asList(docUrls));
}
public VirtualFile[] getSourceFiles() {
return mySourceFiles.toArray(new VirtualFile[mySourceFiles.size()]);
public Set<VirtualFile> getSourceFiles() {
return mySourceFiles;
}
public VirtualFile[] getCompactFiles() {
return myCompactFiles.toArray(new VirtualFile[myCompactFiles.size()]);
public Set<VirtualFile> getCompactFiles() {
return myCompactFiles;
}
public String[] getDocUrls() {
@@ -196,7 +196,7 @@ public class ScriptingLibraryTable {
}
@NotNull
public VirtualFile[] getFiles(OrderRootType rootType) {
public Set<VirtualFile> getFiles(OrderRootType rootType) {
if (rootType == COMPACT_ROOT_TYPE) {
return getCompactFiles();
}
@@ -929,9 +929,8 @@ public class SingleInspectionProfilePanel extends JPanel {
if (myShareProfile != (mySelectedProfile.getProfileManager() == myProjectProfileManager)) return true;
if (!Comparing.strEqual(myInitialProfile, mySelectedProfile.getName())) return true;
if (descriptorsAreChanged()) {
return setSelectedProfileModified(true);
return true;
}
setSelectedProfileModified(false);
return false;
}
@@ -35,14 +35,19 @@ public class DefaultPomTargetDescriptionProvider extends PomDescriptionProvider
if (element instanceof PsiElement) return null;
if (location == UsageViewTypeLocation.INSTANCE) {
return TypeNameManager.getTypeName(element.getClass());
return getTypeName(element);
}
if (location == UsageViewNodeTextLocation.INSTANCE) {
return TypeNameManager.getTypeName(element.getClass()) + " " + StringUtil.notNullize(element instanceof PomNamedTarget ? ((PomNamedTarget)element).getName() : null, "''");
return getTypeName(element) + " " + StringUtil.notNullize(element instanceof PomNamedTarget ? ((PomNamedTarget)element).getName() : null, "''");
}
if (location instanceof HighlightUsagesDescriptionLocation) {
return TypeNameManager.getTypeName(element.getClass());
return getTypeName(element);
}
return null;
}
private static String getTypeName(PomTarget element) {
final String s = TypeNameManager._getTypeName(element.getClass());
return s == null ? "Element" : s;
}
}
@@ -99,10 +99,6 @@ public class PsiElementRenameHandler implements RenameHandler {
if (element == null) return "";
if (!(element instanceof PsiFile) && CollectHighlightsUtil.isOutsideSourceRootJavaFile(element.getContainingFile())) return "";
if (!element.isWritable()) {
return RefactoringBundle.getCannotRefactorMessage("This element cannot be renamed.");
}
boolean hasRenameProcessor = RenamePsiElementProcessor.forElement(element) != RenamePsiElementProcessor.DEFAULT;
boolean hasWritableMetaData = element instanceof PsiMetaOwner && ((PsiMetaOwner)element).getMetaData() instanceof PsiWritableMetaData;
@@ -110,9 +106,15 @@ public class PsiElementRenameHandler implements RenameHandler {
return RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("error.wrong.caret.position.symbol.to.rename"));
}
if (!PsiManager.getInstance(project).isInProject(element) && element.isPhysical()) {
return RefactoringBundle
.getCannotRefactorMessage(RefactoringBundle.message("error.out.of.project.element", UsageViewUtil.getType(element)));
if (!PsiManager.getInstance(project).isInProject(element)) {
if (element.isPhysical()) {
return RefactoringBundle
.getCannotRefactorMessage(RefactoringBundle.message("error.out.of.project.element", UsageViewUtil.getType(element)));
}
if (!element.isWritable()) {
return RefactoringBundle.getCannotRefactorMessage("This element cannot be renamed.");
}
}
if (InjectedLanguageUtil.isInInjectedLanguagePrefixSuffix(element)) {
@@ -760,11 +760,11 @@ public class PluginManager {
ourBuildNumber = BuildNumber.fromString(new String(FileUtil.loadFileText(buildTxtFile)).trim());
}
else {
ourBuildNumber = BuildNumber.fromString("102.SNAPSHOT");
ourBuildNumber = BuildNumber.fromString("104.SNAPSHOT");
}
}
catch (IOException e) {
ourBuildNumber = BuildNumber.fromString("102.SNAPSHOT");
ourBuildNumber = BuildNumber.fromString("104.SNAPSHOT");
}
}
}
@@ -49,19 +49,36 @@ public interface Notifications {
}
public static void notify(@NotNull final Notification notification, @NotNull final NotificationDisplayType defaultDisplayType, @Nullable final Project project) {
if (project != null && !project.isInitialized()) {
StartupManager.getInstance(project).runWhenProjectIsInitialized(new Runnable() {
public void run() {
project.getMessageBus().syncPublisher(TOPIC).notify(notification, defaultDisplayType);
}
});
if (project != null && !project.isDisposed()) {
if (!project.isInitialized()) {
StartupManager.getInstance(project).runWhenProjectIsInitialized(new Runnable() {
public void run() {
project.getMessageBus().syncPublisher(TOPIC).notify(notification, defaultDisplayType);
}
});
}
else {
if (EventQueue.isDispatchThread()) {
project.getMessageBus().syncPublisher(TOPIC).notify(notification, defaultDisplayType);
}
else {
//noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
public void run() {
project.getMessageBus().syncPublisher(TOPIC).notify(notification, defaultDisplayType);
}
});
}
}
return;
}
FrameStateManager.getInstance().getApplicationActive().doWhenDone(new Runnable() {
@Override
public void run() {
final MessageBus bus = project == null ? ApplicationManager.getApplication().getMessageBus() : (project.isDisposed() ? null : project.getMessageBus());
final MessageBus bus =
project == null ? ApplicationManager.getApplication().getMessageBus() : (project.isDisposed() ? null : project.getMessageBus());
if (bus != null) {
if (EventQueue.isDispatchThread()) {
bus.syncPublisher(TOPIC).notify(notification, defaultDisplayType);
@@ -69,4 +69,8 @@ public interface BalloonBuilder {
@NotNull
BalloonBuilder setPositionChangeYShift(int positionChangeYShift);
boolean isHideOnAction();
BalloonBuilder setHideOnAction(boolean hideOnAction);
}
@@ -1,34 +0,0 @@
/*
* Copyright 2000-2011 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;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.ui.EditorCustomization;
import org.jetbrains.annotations.NotNull;
/**
* Basic super class for {@link EditorCustomization editor customizations} that don't consider un-applying feature.
*
* @author Denis Zhdanov
* @since 1/14/11 12:52 PM
*/
public abstract class AbstractUnappliableEditorCustomization implements EditorCustomization {
@Override
public void removeCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
// Do nothing
}
}
@@ -53,6 +53,7 @@ import java.awt.event.MouseEvent;
public class IdeTooltipManager implements ApplicationComponent, AWTEventListener {
public static final Color GRAPHITE_COLOR = new Color(100, 100, 100, 230);
private RegistryValue myIsEnabled;
private Component myCurrentComponent;
@@ -304,7 +305,7 @@ public class IdeTooltipManager implements ApplicationComponent, AWTEventListener
}
public Color getTextBackground(boolean awtTooltip) {
return useGraphite(awtTooltip) ? new Color(100, 100, 100, 230) : UIUtil.getToolTipBackground();
return useGraphite(awtTooltip) ? GRAPHITE_COLOR : UIUtil.getToolTipBackground();
}
public String getUlImg(boolean awtTooltip) {
@@ -98,6 +98,11 @@ public class PasswordSafePromptDialog extends DialogWrapper {
return myRoot;
}
@Override
public JComponent getPreferredFocusedComponent() {
return myPasswordPasswordField;
}
/**
* Ask password possibly asking password database first. The method could be invoked from any thread. If UI needs to be shown,
* the method invokes {@link com.intellij.util.ui.UIUtil#invokeAndWaitIfNeeded(Runnable)}
@@ -165,9 +165,9 @@ public class EditorActionUtil {
if (isCamel) {
if (firstIsIdentifierPart && secondIsIdentifierPart &&
(Character.isLowerCase(prev) && Character.isUpperCase(current) ||
(isLowerCaseOrDigit(prev) && Character.isUpperCase(current) ||
prev == '_' && current != '_' ||
Character.isUpperCase(prev) && Character.isUpperCase(current) && Character.isLowerCase(next))) {
Character.isUpperCase(prev) && Character.isUpperCase(current) && isLowerCaseOrDigit(next))) {
return true;
}
}
@@ -175,6 +175,10 @@ public class EditorActionUtil {
return (Character.isWhitespace(prev) || firstIsIdentifierPart) &&
!Character.isWhitespace(current) && !secondIsIdentifierPart;
}
private static boolean isLowerCaseOrDigit(char c) {
return Character.isLowerCase(c) || Character.isDigit(c);
}
public static boolean isWordEnd(CharSequence text, int offset, boolean isCamel) {
char prev = offset > 0 ? text.charAt(offset - 1) : 0;
@@ -111,6 +111,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
public void moveToVisualPosition(@NotNull VisualPosition pos) {
assertIsDispatchThread();
validateCallContext();
myDesiredX = -1;
int column = pos.column;
int line = pos.line;
@@ -213,7 +214,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener,
int newLineNumber = visualCaret.line + lineShift;
int newColumnNumber = visualCaret.column + columnShift;
if (desiredX >= 0) {
newColumnNumber = myEditor.xyToVisualPosition(new Point(desiredX, newLineNumber * myEditor.getLineHeight())).column;
newColumnNumber = myEditor.xyToVisualPosition(new Point(desiredX, Math.max(0, newLineNumber) * myEditor.getLineHeight())).column;
}
Document document = myEditor.getDocument();
@@ -1015,7 +1015,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
charWidth = EditorUtil.charWidth(c, fontType, this);
}
if (charWidth <= 0) {
if (charWidth < 0) {
charWidth = spaceSize;
}
@@ -311,7 +311,13 @@ public class SelectionModelImpl implements SelectionModel, PrioritizedDocumentLi
FoldRegion endFold = foldingModel.getCollapsedRegionAtOffset(endOffset);
if (endFold != null) {
endOffset = endFold.getEndOffset();
VisualPosition visualFoldStart = myEditor.offsetToVisualPosition(endFold.getStartOffset());
// All visual positions that lay at collapsed fold region placeholder are mapped to the same offset. Hence, there are
// at least two distinct situations - selection end is located inside collapsed fold region placeholder and just before it.
// We want to expand selection to the fold region end at the former case and keep selection as-is at the latest one.
if (visualFoldStart.column < endPosition.column) {
endOffset = endFold.getEndOffset();
}
}
int oldSelectionStart;
@@ -583,6 +589,20 @@ public class SelectionModelImpl implements SelectionModel, PrioritizedDocumentLi
if (marker != null) {
int startOffset = marker.getStartOffset();
int endOffset = marker.getEndOffset();
if (caretOffset != startOffset && caretOffset != endOffset) {
// Try to check if current selection is tweaked by fold region.
FoldingModelEx foldingModel = myEditor.getFoldingModel();
FoldRegion foldRegion = foldingModel.getCollapsedRegionAtOffset(caretOffset);
if (foldRegion != null) {
if (foldRegion.getStartOffset() == startOffset) {
return endOffset;
}
else if (foldRegion.getEndOffset() == endOffset) {
return startOffset;
}
}
}
if (caretOffset == endOffset) {
return startOffset;
}
@@ -51,6 +51,7 @@ import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.*;
import java.util.List;
@@ -535,6 +536,7 @@ public abstract class FileTextFieldImpl implements FileLookup, Disposable, FileT
if (currentDiff == diff) {
toPreselect = each;
toPreselectFixed = true;
break;
}
}
@@ -597,7 +599,10 @@ public abstract class FileTextFieldImpl implements FileLookup, Disposable, FileT
if (typed == null) return null;
LookupFile lastFound = myFinder.find(typed);
if (lastFound == null) return null;
if (lastFound.exists()) return lastFound;
if (lastFound.exists()) {
if (typed.charAt(typed.length() - 1) != File.separatorChar) return lastFound.getParent();
return lastFound;
}
final String[] splits = myFinder.normalize(typed).split(myFileSpitRegExp);
StringBuffer fullPath = new StringBuffer();
@@ -17,7 +17,7 @@
<text value="Project &amp;name:"/>
</properties>
</component>
<component id="89536" class="javax.swing.JLabel">
<component id="89536" class="javax.swing.JLabel" binding="myLocationLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
@@ -49,6 +49,7 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
private JPanel myRootPane;
private JComboBox myProjectTypeComboBox;
private JPanel myProjectTypePanel;
private JLabel myLocationLabel;
private String myBaseDir;
private boolean myModifyingLocation = false;
private boolean myModifyingProjectName = false;
@@ -60,6 +61,8 @@ public class NewDirectoryProjectDialog extends DialogWrapper {
setTitle("Create New Project");
init();
myLocationLabel.setLabelFor(myLocationField.getChildComponent());
myBaseDir = getBaseDir();
File projectName = FileUtil.findSequentNonexistentFile(new File(myBaseDir), "untitled", "");
myLocationField.setText(projectName.toString());
@@ -0,0 +1,77 @@
/*
* Copyright 2000-2011 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.ui;
import com.intellij.openapi.editor.ex.EditorEx;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Set;
/**
* Base super class for {@link EditorCustomization editor customizations} that provide the following:
* <pre>
* <ul>
* <li>
* Don't process {@link #addCustomization(EditorEx, Feature)} and {@link #removeCustomization(EditorEx, Feature)} if given feature
* is not supported by the current customization (supported features are defined at constructor);
* </li>
* </ul>
* </pre>
*
* @author Denis Zhdanov
* @since 1/24/11 3:56 PM
*/
public abstract class AbstractEditorCustomization implements EditorCustomization {
private final Set<Feature> myFeatures = EnumSet.noneOf(Feature.class);
protected AbstractEditorCustomization(@NotNull Feature... features) {
myFeatures.addAll(Arrays.asList(features));
}
@Override
public Set<Feature> getSupportedFeatures() {
return myFeatures;
}
@Override
public void addCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
if (!myFeatures.contains(feature)) {
return;
}
doProcessCustomization(editor, feature, true);
}
@Override
public void removeCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
if (!myFeatures.contains(feature)) {
return;
}
doProcessCustomization(editor, feature, false);
}
/**
* Template method for sub-classes to process target feature applying/removal and being sure that given feature
* is supported by the current customization.
*
* @param editor target editor to apply the given feature
* @param feature target feature to apply to the given editor
* @param apply flag the identifies if given feature should be applied/removed from the given editor
*/
protected abstract void doProcessCustomization(@NotNull EditorEx editor, @NotNull Feature feature, boolean apply);
}
@@ -18,29 +18,20 @@ package com.intellij.ui;
import com.intellij.openapi.editor.ex.EditorEx;
import org.jetbrains.annotations.NotNull;
import java.util.EnumSet;
import java.util.Set;
/**
* {@link EditorCustomization} for {@link EditorCustomization.Feature#ADDITIONAL_PAGE_AT_BOTTOM}.
*
* @author Denis Zhdanov
* @since 1/21/11 4:06 PM
*/
public class AdditionalPageAtBottomEditorCustomization implements EditorCustomization {
public class AdditionalPageAtBottomEditorCustomization extends AbstractEditorCustomization {
@Override
public Set<Feature> getSupportedFeatures() {
return EnumSet.of(Feature.ADDITIONAL_PAGE_AT_BOTTOM);
public AdditionalPageAtBottomEditorCustomization() {
super(Feature.ADDITIONAL_PAGE_AT_BOTTOM);
}
@Override
public void addCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
editor.getSettings().setAdditionalPageAtBottom(true);
}
@Override
public void removeCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
editor.getSettings().setAdditionalPageAtBottom(false);
protected void doProcessCustomization(@NotNull EditorEx editor, @NotNull Feature feature, boolean apply) {
editor.getSettings().setAdditionalPageAtBottom(apply);
}
}
@@ -197,6 +197,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi
private final JComponent myContent;
private final boolean myHideOnMouse;
private final boolean myHideOnKey;
private boolean myHideOnAction;
private final boolean myEnableCloseButton;
private final Icon myCloseButton = IconLoader.getIcon("/general/balloonClose.png");
@@ -205,6 +206,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi
Color fillColor,
boolean hideOnMouse,
boolean hideOnKey,
boolean hideOnAction,
boolean showPointer,
boolean enableCloseButton,
long fadeoutTime,
@@ -220,6 +222,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi
myContent = content;
myHideOnMouse = hideOnMouse;
myHideOnKey = hideOnKey;
myHideOnAction = hideOnAction;
myShowPointer = showPointer;
myEnableCloseButton = enableCloseButton;
myHideOnFrameResize = hideOnFrameResize;
@@ -380,6 +383,14 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi
Toolkit.getDefaultToolkit().addAWTEventListener(myAwtActivityListener, MouseEvent.MOUSE_EVENT_MASK |
MouseEvent.MOUSE_MOTION_EVENT_MASK |
KeyEvent.KEY_EVENT_MASK);
ActionManager.getInstance().addAnActionListener(new AnActionListener.Adapter() {
@Override
public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
if (myHideOnAction) {
hide();
}
}
}, this);
}
private Rectangle getRecForPosition(Position position, boolean adjust) {
@@ -462,13 +473,13 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi
}
myAnimator = new Animator("Balloon", 10, myAnimationCycle, false, 0, 1, forward) {
public void paintNow(final float frame, final float totalFrames, final float cycle) {
if (myComp.getParent() == null) return;
if (myComp == null || myComp.getParent() == null) return;
myComp.setAlpha(frame / totalFrames);
}
@Override
protected void paintCycleEnd() {
if (myComp.getParent() == null) return;
if (myComp == null || myComp.getParent() == null) return;
if (isForward()) {
myComp.clear();
@@ -1230,7 +1241,7 @@ public class BalloonImpl implements Disposable, Balloon, LightweightWindow, Posi
//pane.setBorder(new LineBorder(Color.blue));
balloon.set(new BalloonImpl(new JLabel("FUCK"), Color.black, MessageType.ERROR.getPopupBackground(), true, true, true, true, 0, true, null, false, 500, 5, 0, 0));
balloon.set(new BalloonImpl(new JLabel("FUCK"), Color.black, MessageType.ERROR.getPopupBackground(), true, true, true, true, true, 0, true, null, false, 500, 5, 0, 0));
balloon.get().setShowPointer(true);
if (e.isShiftDown()) {
@@ -18,29 +18,19 @@ package com.intellij.ui;
import com.intellij.openapi.editor.ex.EditorEx;
import org.jetbrains.annotations.NotNull;
import java.util.EnumSet;
import java.util.Set;
/**
* @author irengrig
* Date: 12/6/10
* Time: 10:18 AM
*/
public class HorizontalScrollBarEditorCustomization implements EditorCustomization {
public Set<Feature> getSupportedFeatures() {
return EnumSet.of(Feature.HORIZONTAL_SCROLLBAR);
}
public class HorizontalScrollBarEditorCustomization extends AbstractEditorCustomization {
public void addCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
if (Feature.HORIZONTAL_SCROLLBAR.equals(feature)) {
editor.setHorizontalScrollbarVisible(true);
}
public HorizontalScrollBarEditorCustomization() {
super(Feature.HORIZONTAL_SCROLLBAR);
}
@Override
public void removeCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
if (Feature.HORIZONTAL_SCROLLBAR.equals(feature)) {
editor.setHorizontalScrollbarVisible(false);
}
protected void doProcessCustomization(@NotNull EditorEx editor, @NotNull Feature feature, boolean apply) {
editor.setHorizontalScrollbarVisible(apply);
}
}
@@ -15,24 +15,20 @@
*/
package com.intellij.ui;
import com.intellij.AbstractUnappliableEditorCustomization;
import com.intellij.openapi.editor.ex.EditorEx;
import org.jetbrains.annotations.NotNull;
import java.util.EnumSet;
import java.util.Set;
/**
* @author Kirill Likhodedov
*/
public class OneLineEditorCustomization extends AbstractUnappliableEditorCustomization {
public Set<Feature> getSupportedFeatures() {
return EnumSet.of(Feature.ONE_LINE);
public class OneLineEditorCustomization extends AbstractEditorCustomization {
public OneLineEditorCustomization() {
super(Feature.ONE_LINE);
}
public void addCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
if (Feature.ONE_LINE.equals(feature)) {
editor.setOneLineMode(true);
}
@Override
protected void doProcessCustomization(@NotNull EditorEx editor, @NotNull Feature feature, boolean apply) {
editor.setOneLineMode(apply);
}
}
@@ -15,13 +15,9 @@
*/
package com.intellij.ui;
import com.intellij.AbstractUnappliableEditorCustomization;
import com.intellij.openapi.editor.ex.EditorEx;
import org.jetbrains.annotations.NotNull;
import java.util.EnumSet;
import java.util.Set;
/**
* Editor customization that can make target editor soft wraps-aware.
* <p/>
@@ -30,15 +26,14 @@ import java.util.Set;
* @author Denis Zhdanov
* @since Aug 20, 2010 4:54:48 PM
*/
public class SoftWrapsEditorCustomization extends AbstractUnappliableEditorCustomization {
public class SoftWrapsEditorCustomization extends AbstractEditorCustomization {
@Override
public Set<Feature> getSupportedFeatures() {
return EnumSet.of(Feature.SOFT_WRAP);
public SoftWrapsEditorCustomization() {
super(Feature.SOFT_WRAP);
}
@Override
public void addCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
editor.getSettings().setUseSoftWraps(true);
protected void doProcessCustomization(@NotNull EditorEx editor, @NotNull Feature feature, boolean apply) {
editor.getSettings().setUseSoftWraps(apply);
}
}
@@ -46,11 +46,23 @@ public class BalloonPopupBuilderImpl implements BalloonBuilder {
private int myCalloutShift;
private int myPositionChangeXShift;
private int myPositionChangeYShift;
private boolean myHideOnAction = true;
public BalloonPopupBuilderImpl(@NotNull final JComponent content) {
myContent = content;
}
@Override
public boolean isHideOnAction() {
return myHideOnAction;
}
@Override
public BalloonBuilder setHideOnAction(boolean hideOnAction) {
myHideOnAction = hideOnAction;
return this;
}
@NotNull
public BalloonBuilder setPreferredPosition(final Balloon.Position position) {
myPrefferedPosition = position;
@@ -122,7 +134,7 @@ public class BalloonPopupBuilderImpl implements BalloonBuilder {
@NotNull
public Balloon createBalloon() {
return new BalloonImpl(myContent, myBorder, myFill, myHideOnMouseOutside, myHideOnKeyOutside, myShowCalllout, myCloseButtonEnabled, myFadeoutTime, myHideOnFrameResize, myClickHandler, myCloseOnClick, myAnimationCycle,
return new BalloonImpl(myContent, myBorder, myFill, myHideOnMouseOutside, myHideOnKeyOutside, myHideOnAction, myShowCalllout, myCloseButtonEnabled, myFadeoutTime, myHideOnFrameResize, myClickHandler, myCloseOnClick, myAnimationCycle,
myCalloutShift, myPositionChangeXShift, myPositionChangeYShift);
}
@@ -145,4 +157,4 @@ public class BalloonPopupBuilderImpl implements BalloonBuilder {
myCalloutShift = length;
return this;
}
}
}
@@ -180,6 +180,7 @@ wrapping.extends.implements.list=Extends/implements list
wrapping.extends.implements.keyword=Extends/implements keyword
wrapping.throws.list=Throws list
wrapping.throws.keyword=Throws keyword
wrapping.align.throws.keyword=Align 'throws' to method start
wrapping.ternary.operation=Ternary operation
wrapping.assignment.variables.groups=Fields/variables groups
wrapping.assignment.statement=Assignment statement
@@ -182,7 +182,10 @@
<keyboard-shortcut first-keystroke="control N"/>
<keyboard-shortcut first-keystroke="control ENTER"/>
</action>
<action id="ActivateProjectToolWindow">
<action id="NewElementSamePlace">
<keyboard-shortcut first-keystroke="control alt N"/>
</action>
<action id="ActivateProjectToolWindow">
<keyboard-shortcut first-keystroke="meta 1"/>
</action>
<action id="ActivateCommanderToolWindow">
@@ -209,6 +209,9 @@
<keyboard-shortcut first-keystroke="control N"/>
<keyboard-shortcut first-keystroke="control ENTER"/>
</action>
<action id="NewElementSamePlace">
<keyboard-shortcut first-keystroke="control alt N"/>
</action>
<action id="Generate">
<keyboard-shortcut first-keystroke="control N"/>
<keyboard-shortcut first-keystroke="control ENTER"/>
@@ -492,6 +492,14 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest
doAction(IdeActions.ACTION_EDITOR_PASTE);
}
protected static void moveCaretToPreviousWordWithSelection() {
doAction("EditorPreviousWordWithSelection");
}
protected static void moveCaretToNextWordWithSelection() {
doAction("EditorNextWordWithSelection");
}
protected static void lineComment() {
new CommentByLineCommentHandler().invoke(getProject(), getEditor(), getFile());
}
@@ -26,7 +26,7 @@ public class BuildNumber implements Comparable<BuildNumber> {
private final int myBaselineVersion;
private final int myBuildNumber;
private static final String BUILD_NUMBER = "__BUILD_NUMBER__";
private static final int TOP_BASELINE_VERSION = 102;
private static final int TOP_BASELINE_VERSION = 104;
public BuildNumber(String productCode, int baselineVersion, int buildNumber) {
myProductCode = productCode;
@@ -26,9 +26,18 @@ public class FormBuilder {
private int line = 0;
private final JPanel panel;
private boolean vertical;
/**
* @param vertical labels will be placed on their own rows
*/
public FormBuilder(final boolean vertical) {
this.vertical = vertical;
panel = new JPanel(new GridBagLayout());
}
public FormBuilder() {
panel = new JPanel(new GridBagLayout());
this(false);
}
public FormBuilder addLabeledComponent(String labelText, JComponent component) {
@@ -38,24 +47,49 @@ public class FormBuilder {
GridBagConstraints c = new GridBagConstraints();
int verticalInset = line > 0 ? 10 : 0;
c.gridx = 0;
c.gridy = line;
c.weightx = 0;
c.anchor = GridBagConstraints.EAST;
c.insets = new Insets(verticalInset, 0, 0, 5);
panel.add(label, c);
if (vertical) {
c.gridwidth = 1;
c.gridx = 1;
c.gridy = line;
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.WEST;
c.weightx = 1;
c.insets = new Insets(verticalInset, 0, 0, 0);
panel.add(component, c);
c.gridx = 0;
c.gridy = line;
c.weightx = 1.0;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(verticalInset, 0, 0, 5);
line++;
panel.add(label, c);
c.gridx = 0;
c.gridy = line + 1;
c.weightx = 1.0;
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.WEST;
c.insets = new Insets(0, 0, 0, 5);
panel.add(component, c);
line += 2;
}
else {
c.gridx = 0;
c.gridy = line;
c.weightx = 0;
c.anchor = GridBagConstraints.EAST;
c.insets = new Insets(verticalInset, 0, 0, 5);
panel.add(label, c);
c.gridx = 1;
c.gridy = line;
c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.WEST;
c.weightx = 1;
c.insets = new Insets(verticalInset, 0, 0, 0);
panel.add(component, c);
line++;
}
return this;
}
@@ -21,7 +21,6 @@ import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.xdebugger.breakpoints.XBreakpointManager;
import org.jetbrains.annotations.NotNull;
@@ -71,4 +70,14 @@ public abstract class XDebuggerManager {
@NotNull
public abstract XDebugSession startSessionAndShowTab(@NotNull String sessionName, @Nullable RunContentDescriptor contentToReuse,
@NotNull XDebugProcessStarter starter) throws ExecutionException;
/**
* Start a new debugging session and open 'Debug' tool window
* @param sessionName title of 'Debug' tool window
* @param showToolWindowOnSuspendOnly if {@code true} 'Debug' tool window won't be shown until debug process is suspended on a breakpoint
*/
@NotNull
public abstract XDebugSession startSessionAndShowTab(@NotNull String sessionName, @Nullable RunContentDescriptor contentToReuse,
boolean showToolWindowOnSuspendOnly,
@NotNull XDebugProcessStarter starter) throws ExecutionException;
}
@@ -15,7 +15,9 @@
*/
package com.intellij.xdebugger.impl;
import com.intellij.execution.ExecutionManager;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.filters.HyperlinkInfo;
import com.intellij.execution.filters.OpenFileHyperlinkInfo;
import com.intellij.execution.process.ProcessHandler;
@@ -74,27 +76,30 @@ public class XDebugSessionImpl implements XDebugSession {
private MyDependentBreakpointListener myDependentBreakpointListener;
private String mySessionName;
private XDebugSessionTab mySessionTab;
private XDebugSessionData mySessionData;
private final EventDispatcher<XDebugSessionListener> myDispatcher = EventDispatcher.create(XDebugSessionListener.class);
private Project myProject;
private @Nullable ExecutionEnvironment myEnvironment;
private ProgramRunner myRunner;
private boolean myStopped;
private boolean myPauseActionSupported;
private boolean myShowTabOnSuspend;
public XDebugSessionImpl(final @NotNull ExecutionEnvironment env,
final @NotNull ProgramRunner runner,
XDebuggerManagerImpl debuggerManager) {
this(env, runner, debuggerManager, env.getRunProfile().getName());
this(env, runner, debuggerManager, env.getRunProfile().getName(), false);
}
public XDebugSessionImpl(final @Nullable ExecutionEnvironment env,
final @Nullable ProgramRunner runner,
XDebuggerManagerImpl debuggerManager,
final @NotNull String sessionName) {
final @NotNull String sessionName, final boolean showTabOnSuspend) {
myEnvironment = env;
myRunner = runner;
mySessionName = sessionName;
myDebuggerManager = debuggerManager;
myShowTabOnSuspend = showTabOnSuspend;
myProject = debuggerManager.getProject();
ValueLookupManager.getInstance(myProject).startListening();
}
@@ -106,16 +111,27 @@ public class XDebugSessionImpl implements XDebugSession {
@NotNull
public RunContentDescriptor getRunContentDescriptor() {
LOG.assertTrue(mySessionTab != null, "Call init() first!");
assertSessionTabInitialized();
return mySessionTab.getRunContentDescriptor();
}
private void assertSessionTabInitialized() {
if (myShowTabOnSuspend) {
LOG.error("Debug tool window isn't shown yet because debug process isn't suspended");
}
else {
LOG.assertTrue(mySessionTab != null, "Debug tool window not initialized yet!");
}
}
public void setPauseActionSupported(final boolean isSupported) {
myPauseActionSupported = isSupported;
}
public void rebuildViews() {
mySessionTab.rebuildViews();
if (!myShowTabOnSuspend) {
mySessionTab.rebuildViews();
}
}
@Nullable
@@ -162,6 +178,7 @@ public class XDebugSessionImpl implements XDebugSession {
public XDebugSessionTab init(final XDebugProcess process, @NotNull final XDebugSessionData sessionData) {
LOG.assertTrue(myDebugProcess == null);
myDebugProcess = process;
mySessionData = sessionData;
XBreakpointManagerImpl breakpointManager = myDebuggerManager.getBreakpointManager();
XDependentBreakpointManager dependentBreakpointManager = breakpointManager.getDependentBreakpointManager();
@@ -173,8 +190,9 @@ public class XDebugSessionImpl implements XDebugSession {
myDependentBreakpointListener = new MyDependentBreakpointListener();
dependentBreakpointManager.addListener(myDependentBreakpointListener);
initSessionTab(sessionData);
process.sessionInitialized();
if (!myShowTabOnSuspend) {
initSessionTab();
}
return mySessionTab;
}
@@ -183,13 +201,14 @@ public class XDebugSessionImpl implements XDebugSession {
return mySessionTab;
}
private void initSessionTab(@NotNull XDebugSessionData sessionData) {
private void initSessionTab() {
mySessionTab = new XDebugSessionTab(myProject, mySessionName);
if (myEnvironment != null) {
mySessionTab.setEnvironment(myEnvironment);
}
Disposer.register(myProject, mySessionTab);
mySessionTab.attachToSession(this, myRunner, myEnvironment, sessionData);
mySessionTab.attachToSession(this, myRunner, myEnvironment, mySessionData);
myDebugProcess.sessionInitialized();
}
private void disableSlaveBreakpoints(final XDependentBreakpointManager dependentBreakpointManager) {
@@ -205,6 +224,15 @@ public class XDebugSessionImpl implements XDebugSession {
}
}
public void showSessionTab() {
RunContentDescriptor descriptor = getRunContentDescriptor();
ExecutionManager.getInstance(getProject()).getContentManager().showRunContent(DefaultDebugExecutor.getDebugExecutorInstance(), descriptor);
ProcessHandler handler = descriptor.getProcessHandler();
if (handler != null) {
handler.startNotify();
}
}
private static <B extends XBreakpoint<?>> XBreakpointType<?, ?> getBreakpointTypeClass(final XBreakpointHandler<B> handler) {
return XDebuggerUtil.getInstance().findBreakpointType(handler.getBreakpointTypeClass());
}
@@ -483,9 +511,10 @@ public class XDebugSessionImpl implements XDebugSession {
}
private void printMessage(final String message, final String hyperLinkText, @Nullable final HyperlinkInfo info) {
assertSessionTabInitialized();
DebuggerUIUtil.invokeOnEventDispatch(new Runnable() {
public void run() {
final ConsoleView consoleView = getConsoleView();
final ConsoleView consoleView = (ConsoleView)mySessionTab.getConsole();
consoleView.print(message, ConsoleViewContentType.SYSTEM_OUTPUT);
if (info != null) {
consoleView.printHyperlink(hyperLinkText, info);
@@ -498,10 +527,6 @@ public class XDebugSessionImpl implements XDebugSession {
});
}
private ConsoleView getConsoleView() {
return (ConsoleView)mySessionTab.getConsole();
}
public void positionReached(@NotNull final XSuspendContext suspendContext) {
enableBreakpoints();
mySuspendContext = suspendContext;
@@ -515,6 +540,11 @@ public class XDebugSessionImpl implements XDebugSession {
}
UIUtil.invokeLaterIfNeeded(new Runnable() {
public void run() {
if (myShowTabOnSuspend) {
myShowTabOnSuspend = false;
initSessionTab();
showSessionTab();
}
mySessionTab.toFront();
}
});
@@ -16,7 +16,6 @@
package com.intellij.xdebugger.impl;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionManager;
import com.intellij.execution.Executor;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.process.ProcessHandler;
@@ -150,18 +149,24 @@ public class XDebuggerManagerImpl extends XDebuggerManager implements ProjectCom
@NotNull
public XDebugSession startSessionAndShowTab(@NotNull String sessionName, @Nullable RunContentDescriptor contentToReuse,
@NotNull XDebugProcessStarter starter) throws ExecutionException {
XDebugSession session = startSession(contentToReuse, starter, new XDebugSessionImpl(null, null, this, sessionName));
RunContentDescriptor descriptor = session.getRunContentDescriptor();
ExecutionManager.getInstance(myProject).getContentManager().showRunContent(DefaultDebugExecutor.getDebugExecutorInstance(), descriptor);
ProcessHandler handler = descriptor.getProcessHandler();
if (handler != null) {
handler.startNotify();
@NotNull XDebugProcessStarter starter) throws ExecutionException {
return startSessionAndShowTab(sessionName, contentToReuse, false, starter);
}
@NotNull
@Override
public XDebugSession startSessionAndShowTab(@NotNull String sessionName, @Nullable RunContentDescriptor contentToReuse,
boolean showToolWindowOnSuspendOnly,
@NotNull XDebugProcessStarter starter) throws ExecutionException {
XDebugSessionImpl session = startSession(contentToReuse, starter, new XDebugSessionImpl(null, null, this, sessionName,
showToolWindowOnSuspendOnly));
if (!showToolWindowOnSuspendOnly) {
session.showSessionTab();
}
return session;
}
private XDebugSession startSession(final RunContentDescriptor contentToReuse, final XDebugProcessStarter processStarter,
private XDebugSessionImpl startSession(final RunContentDescriptor contentToReuse, final XDebugProcessStarter processStarter,
final XDebugSessionImpl session) throws ExecutionException {
XDebugProcess process = processStarter.start(session);
@@ -34,7 +34,7 @@
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Reset to defaults"/>
<text value="Reset paths to defaults"/>
</properties>
</component>
<hspacer id="8fb14">
@@ -17,6 +17,7 @@
package com.maddyhome.idea.copyright;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileEditorManager;
@@ -102,7 +103,7 @@ public class CopyrightManager extends AbstractProjectComponent implements JDOMEx
new UpdateCopyrightProcessor(myProject, module, file).run();
}
}
});
}, ModalityState.NON_MODAL);
}
}
}
@@ -24,6 +24,7 @@ import com.intellij.lang.documentation.CodeDocumentationProvider;
import com.intellij.lang.documentation.ExternalDocumentationProvider;
import com.intellij.lang.java.JavaDocumentationProvider;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.javadoc.PsiDocParamRef;
import com.intellij.psi.javadoc.PsiDocComment;
@@ -162,7 +163,8 @@ public class GroovyDocumentationProvider implements CodeDocumentationProvider, E
if (originalElement instanceof GrReferenceExpression) {
final PsiType inferredType = ((GrReferenceExpression)originalElement).getType();
if (inferredType != null) {
buffer.append("[inferred type] ").append(inferredType.getCanonicalText());
buffer.append("[inferred type] ");
appendTypeString(buffer, inferredType);
return;
}
}
@@ -256,7 +258,7 @@ public class GroovyDocumentationProvider implements CodeDocumentationProvider, E
private static void appendTypeString(StringBuffer buffer, PsiType type) {
if (type != null) {
buffer.append(type.getCanonicalText());
buffer.append(StringUtil.escapeXml(type.getCanonicalText()));
}
else {
buffer.append(GrModifier.DEF);
@@ -178,20 +178,6 @@ public abstract class ParserUtils {
marker.error(msg);
}
public static void waitNextRCurly(PsiBuilder builder) {
int i = 0;
PsiBuilder.Marker em = builder.mark();
while (!builder.eof() && !GroovyElementTypes.mRCURLY.equals(builder.getTokenType())) {
builder.advanceLexer();
i++;
}
if (i > 0) {
em.error(GroovyBundle.message("rcurly.expected"));
} else {
em.drop();
}
}
public static void advance(PsiBuilder builder, int count) {
for (int i = 0; i < count; i++) {
builder.getTokenText();
@@ -17,6 +17,7 @@ package org.jetbrains.plugins.groovy.lang.psi.dataFlow.types;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.Semilattice;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
@@ -72,7 +73,7 @@ public class TypesSemilattice implements Semilattice<Map<String, PsiType>> {
if (t1 != null || t2 != null) return false;
}
else {
if (!t1.equals(t2)) return false;
if (!TypeConversionUtil.erasure(t1).equals(TypeConversionUtil.erasure(t2))) return false;
}
}
return true;
@@ -12,6 +12,7 @@ import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
@@ -288,6 +289,15 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase {
public void testSOEInFieldDeclarations() {doTest();}
public void testVeryLongDfaWithComplexGenerics() {
IdeaTestUtil.assertTiming("", 10000, 1, new Runnable() {
@Override
public void run() {
doTest(new GroovyAssignabilityCheckInspection(), new UnusedDefInspection());
}
});
}
public void testWrongAnnotation() {doTest();}
public void testAmbiguousMethods() {
@@ -0,0 +1,25 @@
class TroubleCase {
private Foo<Bar> fooBar;
private Foo<Baz> fooBaz;
private void troubleMethod(boolean b) {
def <warning descr="Assignment is not used">icDao</warning> = (b?fooBaz:fooBar);
for(Object x: new ArrayList()) {
}
}
}
public interface Foo<FFIC> {}
public class Bar implements Cloneable, Zoo<Goo, Doo, Coo, Woo> {}
public interface Zoo<AR, FR, AM extends Hoo<AR>, FM extends Hoo<FR>> {}
public interface Hoo<R> {}
public class Baz implements Cloneable, Zoo<String,String,Too,Yoo> {}
public class Goo {}
public class Too implements Hoo<String> {}
public class Coo implements Serializable, Cloneable, Hoo<Goo> {}
public class Woo implements Serializable, Cloneable, Hoo<Doo> {}
public class Yoo implements Serializable, Cloneable, Hoo<String> {}
public class Doo {}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 857 B

+2 -2
View File
@@ -4,7 +4,7 @@
<description>Provides integration with Mercurial version control system. Supports Mercurial 1.3+.</description>
<category>VCS Integration</category>
<version>10.0</version>
<vendor email="victor.iacoban@gmail.com, willem.verstraeten@gmail.com" logo="/images/mercurial.png" url="http://www.bitbucket.org/willemv/hg4idea">Victor Iacoban and Willem Verstraeten</vendor>
<vendor email="victor.iacoban@gmail.com, willem.verstraeten@gmail.com" url="http://www.bitbucket.org/willemv/hg4idea">Victor Iacoban and Willem Verstraeten</vendor>
<depends>com.intellij.modules.vcs</depends>
<extensions defaultExtensionNs="com.intellij">
@@ -28,7 +28,7 @@
<add-to-group group-id="Vcs.Import"/>
</action>
<group id="hg4idea.file.menu" popup="true" icon="/images/mercurial.png" class="org.zmlx.hg4idea.action.HgMercurialMenu">
<group id="hg4idea.file.menu" popup="true" class="org.zmlx.hg4idea.action.HgMercurialMenu">
<reference ref="CheckinFiles"/>
<reference ref="ChangesView.AddUnversioned"/>
<reference ref="ChangesView.Rollback"/>
@@ -34,7 +34,7 @@ public class HgProjectConfigurable implements SearchableConfigurable {
}
public Icon getIcon() {
return HgVcs.MERCURIAL_ICON;
return null;
}
public String getHelpTopic() {
@@ -78,8 +78,6 @@ public class HgVcs extends AbstractVcs<CommittedChangeList> {
public static final Topic<HgUpdater> OUTGOING_TOPIC =
new Topic<HgUpdater>("hg4idea.outgoing", HgUpdater.class);
public static final Icon MERCURIAL_ICON = IconLoader.getIcon("/images/mercurial.png");
private static final Icon INCOMING_ICON = IconLoader.getIcon("/actions/moveDown.png");
private static final Icon OUTGOING_ICON = IconLoader.getIcon("/actions/moveUp.png");
@@ -22,7 +22,11 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcsUtil.VcsUtil;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.*;
import org.zmlx.hg4idea.HgExecutableValidator;
import org.zmlx.hg4idea.HgGlobalSettings;
import org.zmlx.hg4idea.HgUtil;
import org.zmlx.hg4idea.HgVcs;
import org.zmlx.hg4idea.HgVcsMessages;
import javax.swing.*;
import java.awt.*;
@@ -31,7 +35,9 @@ import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
@@ -155,15 +161,43 @@ public final class HgCommandService {
// logging to the Version Control console (without extensions and configs)
final String cmdString = String.format("%s %s %s", mySettings.isRunViaBash() ? "bash -c " + HgVcs.HG_EXECUTABLE_FILE_NAME : HgVcs.HG_EXECUTABLE_FILE_NAME, operation,
StringUtils.join(arguments, " "));
myVcs.showMessageInConsole(cmdString, ConsoleViewContentType.USER_INPUT.getAttributes());
StringUtils.join(maskAuthInfoFromUrl(arguments), " "));
myVcs.showMessageInConsole(cmdString, ConsoleViewContentType.NORMAL_OUTPUT.getAttributes());
LOG.info(cmdString);
if (!silent) {
myVcs.showMessageInConsole(result.getRawOutput(), ConsoleViewContentType.SYSTEM_OUTPUT.getAttributes());
LOG.info(result.getRawOutput());
}
myVcs.showMessageInConsole(result.getRawError(), ConsoleViewContentType.ERROR_OUTPUT.getAttributes());
LOG.info(result.getRawError());
return result;
}
/**
* Strips possible authentication information from arguments passed to the command line
* to prevent private information appear in the VCS console or logs.
* @param arguments command line arguments.
* @return command line arguments which don't contain authentication information.
*/
private static List<String> maskAuthInfoFromUrl(List<String> arguments) {
if (arguments == null || arguments.isEmpty()) {
return arguments;
}
final List<String> newArgs = new ArrayList<String>(arguments.size());
for (String arg : arguments) {
if (!arg.contains("@")) { // simple filter
newArgs.add(arg);
} else {
try {
final URI uri = new URI(arg); // parsing via URI methods, exception means it's not an URI
newArgs.add(uri.toString().replace(uri.getUserInfo(), "<username>:<password>"));
} catch (Throwable e) {
newArgs.add(arg);
}
}
}
return newArgs;
}
private void showError(Exception e) {
@@ -19,10 +19,12 @@ import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.CheckoutProvider;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -34,13 +36,21 @@ import org.zmlx.hg4idea.command.HgCloneCommand;
import org.zmlx.hg4idea.command.HgCommandResult;
import org.zmlx.hg4idea.ui.HgCloneDialog;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
/**
* Checkout provider for Mercurial
*/
public class HgCheckoutProvider implements CheckoutProvider {
private static final Logger LOG = Logger.getInstance(HgCheckoutProvider.class.getName());
public void doCheckout(@NotNull final Project project, @Nullable final Listener listener) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
@@ -62,30 +72,97 @@ public class HgCheckoutProvider implements CheckoutProvider {
final String sourceRepositoryURL = dialog.getSourceRepositoryURL();
new Task.Backgroundable(project, HgVcsMessages.message("hg4idea.clone.progress", sourceRepositoryURL), true) {
@Override public void run(@NotNull ProgressIndicator indicator) {
// clone
HgCloneCommand clone = new HgCloneCommand(project);
clone.setRepositoryURL(sourceRepositoryURL);
clone.setDirectory(targetDir);
final HgCommandResult myCloneResult = clone.execute();
if (myCloneResult == null) {
notifyError("Clone failed", "Clone failed due to unknown error", project);
} else if (myCloneResult.getExitValue() != 0) {
notifyError("Clone failed", "Clone from " + sourceRepositoryURL + " failed.<br/><br/>" + myCloneResult.getRawError(), project);
} else {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (listener != null) {
listener.directoryCheckedOut(new File(dialog.getParentDirectory(), dialog.getDirectoryName()));
listener.checkoutCompleted();
// handle result
try {
final HgCommandResult myCloneResult = clone.execute();
if (myCloneResult == null) {
notifyError("Clone failed", "Clone failed due to unknown error", project);
} else if (myCloneResult.getExitValue() != 0) {
notifyError("Clone failed", "Clone from " + sourceRepositoryURL + " failed.<br/><br/>" + myCloneResult.getRawError(), project);
} else {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (listener != null) {
listener.directoryCheckedOut(new File(dialog.getParentDirectory(), dialog.getDirectoryName()));
listener.checkoutCompleted();
}
}
}
});
});
}
} finally {
cleanupAuthDataFromHgrc(targetDir);
}
}
}.queue();
}
/**
* Removes authentication data from the parent URL of a just cloned repository.
* @param targetDir directory where the hg project was cloned into.
*/
private static void cleanupAuthDataFromHgrc(String targetDir) {
File hgrc = new File(new File(targetDir, ".hg"), "hgrc");
if (!hgrc.exists()) {
return;
}
for (int i = 0; i < 3; i++) { // 3 attempts in case of an IOException
BufferedReader reader = null;
PrintWriter writer = null;
try {
// writing correct info into a temporary file
final File tempFile = FileUtil.createTempFile("hgrc", "temp");
tempFile.deleteOnExit();
reader = new BufferedReader(new FileReader(hgrc));
writer = new PrintWriter(new FileWriter(tempFile));
String line;
while ((line = reader.readLine()) != null) {
String parseLine = line.trim();
if (parseLine.startsWith("default") && parseLine.contains("@")) { // looking for paths.default
int eqIdx = parseLine.indexOf('=');
parseLine = parseLine.substring(eqIdx+1).trim(); // getting value of paths.default
try {
final URI uri = new URI(parseLine);
final String urlWithoutAuthData = uri.toString().replace(uri.getUserInfo() + "@", "");
writer.println("default = " + urlWithoutAuthData);
} catch (Throwable t) { // not URI => no sensitive data
writer.println(line);
}
} else {
writer.println(line);
}
}
// substituting files
if (!tempFile.renameTo(hgrc)) { // this may fail in case of different FSs
FileUtil.copy(tempFile, hgrc);
tempFile.delete();
}
return;
} catch (IOException e) {
LOG.info(e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
continue;
}
}
if (writer != null) {
writer.close();
}
}
}
}
private static void notifyError(String title, String description, Project project) {
Notifications.Bus.notify(new Notification(HgVcs.NOTIFICATION_GROUP_ID, title, description, NotificationType.ERROR), project);
}
@@ -17,12 +17,15 @@ import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.update.*;
import com.intellij.openapi.vcs.update.SequentialUpdatesContext;
import com.intellij.openapi.vcs.update.UpdateEnvironment;
import com.intellij.openapi.vcs.update.UpdateSession;
import com.intellij.openapi.vcs.update.UpdateSessionAdapter;
import com.intellij.openapi.vcs.update.UpdatedFiles;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -102,7 +105,7 @@ public class HgUpdateEnvironment implements UpdateEnvironment {
}
public Icon getIcon() {
return IconLoader.getIcon("/images/mercurial.png");
return null;
}
public String getHelpTopic() {
@@ -12,7 +12,6 @@
// limitations under the License.
package org.zmlx.hg4idea.ui;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.wm.CustomStatusBarWidget;
import com.intellij.openapi.wm.StatusBar;
import org.apache.commons.lang.StringUtils;
@@ -25,10 +24,9 @@ import javax.swing.*;
import java.util.List;
public class HgCurrentBranchStatus extends JLabel implements CustomStatusBarWidget {
private static final Icon MERCURIAL_ICON = IconLoader.getIcon("/images/mercurial.png");
public HgCurrentBranchStatus() {
super(MERCURIAL_ICON, SwingConstants.TRAILING);
super("", SwingConstants.TRAILING);
setVisible(false);
}
@@ -31,12 +31,14 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.spellchecker.inspections.SpellCheckerInspectionToolProvider;
import com.intellij.ui.EditorCustomization;
import com.intellij.ui.AbstractEditorCustomization;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Makes current editor to have spell checking turned on all the time.
@@ -46,7 +48,7 @@ import java.util.*;
* @author Denis Zhdanov
* @since Aug 20, 2010 3:54:42 PM
*/
public class SpellCheckingEditorCustomization implements EditorCustomization {
public class SpellCheckingEditorCustomization extends AbstractEditorCustomization {
/**
* Holds custom inspection profile wrapper.
@@ -60,6 +62,10 @@ public class SpellCheckingEditorCustomization implements EditorCustomization {
@Nullable
private static final InspectionProfileWrapper INSPECTION_PROFILE_WRAPPER = initProvider();
public SpellCheckingEditorCustomization() {
super(Feature.SPELL_CHECK);
}
@SuppressWarnings("unchecked")
@Nullable
private static InspectionProfileWrapper initProvider() {
@@ -116,12 +122,7 @@ public class SpellCheckingEditorCustomization implements EditorCustomization {
}
@Override
public Set<Feature> getSupportedFeatures() {
return EnumSet.of(Feature.SPELL_CHECK);
}
@Override
public void addCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
protected void doProcessCustomization(@NotNull EditorEx editor, @NotNull Feature feature, boolean apply) {
if (INSPECTION_PROFILE_WRAPPER == null) {
return;
}
@@ -135,27 +136,16 @@ public class SpellCheckingEditorCustomization implements EditorCustomization {
if (file == null) {
return;
}
file.putUserData(InspectionProfileWrapper.KEY, INSPECTION_PROFILE_WRAPPER);
editor.putUserData(IntentionManager.SHOW_INTENTION_OPTIONS_KEY, false);
updateRepresentation(project, file);
}
@Override
public void removeCustomization(@NotNull EditorEx editor, @NotNull Feature feature) {
Project project = editor.getProject();
if (project == null) {
return;
if (apply) {
file.putUserData(InspectionProfileWrapper.KEY, INSPECTION_PROFILE_WRAPPER);
editor.putUserData(IntentionManager.SHOW_INTENTION_OPTIONS_KEY, false);
}
else {
file.putUserData(InspectionProfileWrapper.KEY, null);
}
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
if (file == null) {
return;
}
file.putUserData(InspectionProfileWrapper.KEY, null);
updateRepresentation(project, file);
}
private static void updateRepresentation(@NotNull Project project, @NotNull PsiFile file) {
// Update representation.
DaemonCodeAnalyzer analyzer = DaemonCodeAnalyzer.getInstance(project);
if (analyzer != null) {
analyzer.restart(file);
@@ -628,7 +628,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
if (value != VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY) {
final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project);
final Collection<VirtualFile> filesToProcess = promptAboutAddition(vcs, addedVFiles, value, vcsHelper);
if (filesToProcess != null) {
if (filesToProcess != null && !filesToProcess.isEmpty()) {
final List<VcsException> exceptions = new ArrayList<VcsException>();
runInBackground(project, "Adding files to Subversion",
createAdditionRunnable(project, vcs, copyFromMap, filesToProcess, exceptions));
@@ -758,7 +758,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
final AbstractVcsHelper vcsHelper = AbstractVcsHelper.getInstance(project);
Collection<FilePath> filesToProcess;
filesToProcess = promptAboutDeletion(deletedFiles, vcs, value, vcsHelper);
if (filesToProcess != null) {
if (filesToProcess != null && !filesToProcess.isEmpty()) {
List<VcsException> exceptions = new ArrayList<VcsException>();
runInBackground(project, "Deleting files from Subversion", createDeleteRunnable(project, vcs, filesToProcess, exceptions));
if (!exceptions.isEmpty()) {
@@ -845,6 +845,8 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
}
private void processMovedFiles(final Project project) {
if (myMovedFiles.isEmpty()) return;
final Runnable runnable = new Runnable() {
public void run() {
for (Iterator<MovedFileInfo> iterator = myMovedFiles.iterator(); iterator.hasNext();) {
@@ -33,8 +33,7 @@ import com.intellij.xml.util.XmlTagUtil;
/**
* @author ven
*/
public class XMLExternalAnnotator implements ExternalAnnotator, Validator.ValidationHost {
private AnnotationHolder myHolder;
public class XMLExternalAnnotator implements ExternalAnnotator {
public void annotate(PsiFile file, AnnotationHolder holder) {
if (!(file instanceof XmlFile)) return;
@@ -44,64 +43,68 @@ public class XMLExternalAnnotator implements ExternalAnnotator, Validator.Valida
XmlNSDescriptor nsDescriptor = rootTag == null ? null : rootTag.getNSDescriptor(rootTag.getNamespace(), false);
if (nsDescriptor instanceof Validator && !HtmlUtil.isHtml5Document(document)) {
myHolder = holder;
try {
//noinspection unchecked
((Validator<XmlDocument>)nsDescriptor).validate(document, this);
}
finally {
myHolder = null;
}
((Validator<XmlDocument>)nsDescriptor).validate(document, new MyHost(holder));
}
}
private static final ErrorType[] types = ErrorType.values();
public void addMessage(PsiElement context, String message, int type) {
addMessage(context, message, types[type]);
}
public void addMessage(final PsiElement context, final String message, final ErrorType type, final IntentionAction... fixes) {
if (message != null && message.length() > 0) {
if (context instanceof XmlTag) {
addMessagesForTag((XmlTag)context, message, type, fixes);
}
else {
if (type == Validator.ValidationHost.ErrorType.ERROR) {
appendFixes(myHolder.createErrorAnnotation(context, message), fixes);
} else {
appendFixes(myHolder.createWarningAnnotation(context, message), fixes);
}
}
}
}
private void addMessagesForTag(XmlTag tag, String message, ErrorType type, IntentionAction... actions) {
XmlToken childByRole = XmlTagUtil.getStartTagNameElement(tag);
addMessagesForTreeChild(childByRole, type, message, actions);
childByRole = XmlTagUtil.getEndTagNameElement(tag);
addMessagesForTreeChild(childByRole, type, message, actions);
}
private void addMessagesForTreeChild(final XmlToken childByRole, final ErrorType type, final String message, IntentionAction... actions) {
if (childByRole != null) {
Annotation annotation;
if (type == ErrorType.ERROR) {
annotation = myHolder.createErrorAnnotation(childByRole, message);
}
else {
annotation = myHolder.createWarningAnnotation(childByRole, message);
}
appendFixes(annotation, actions);
}
}
private static final Validator.ValidationHost.ErrorType[] types = Validator.ValidationHost.ErrorType.values();
private static void appendFixes(final Annotation annotation, final IntentionAction... actions) {
if (actions != null) {
for(IntentionAction action:actions) annotation.registerFix(action);
}
}
private static class MyHost implements Validator.ValidationHost {
private final AnnotationHolder myHolder;
public MyHost(AnnotationHolder holder) {
myHolder = holder;
}
public void addMessage(PsiElement context, String message, int type) {
addMessage(context, message, types[type]);
}
public void addMessage(final PsiElement context, final String message, final ErrorType type, final IntentionAction... fixes) {
if (message != null && message.length() > 0) {
if (context instanceof XmlTag) {
addMessagesForTag((XmlTag)context, message, type, fixes);
}
else {
if (type == Validator.ValidationHost.ErrorType.ERROR) {
appendFixes(myHolder.createErrorAnnotation(context, message), fixes);
} else {
appendFixes(myHolder.createWarningAnnotation(context, message), fixes);
}
}
}
}
private void addMessagesForTag(XmlTag tag, String message, ErrorType type, IntentionAction... actions) {
XmlToken childByRole = XmlTagUtil.getStartTagNameElement(tag);
addMessagesForTreeChild(childByRole, type, message, actions);
childByRole = XmlTagUtil.getEndTagNameElement(tag);
addMessagesForTreeChild(childByRole, type, message, actions);
}
private void addMessagesForTreeChild(final XmlToken childByRole, final ErrorType type, final String message, IntentionAction... actions) {
if (childByRole != null) {
Annotation annotation;
if (type == ErrorType.ERROR) {
annotation = myHolder.createErrorAnnotation(childByRole, message);
}
else {
annotation = myHolder.createWarningAnnotation(childByRole, message);
}
appendFixes(annotation, actions);
}
}
}
}
@@ -22,6 +22,8 @@ import com.intellij.psi.ResolveState;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceUtil;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.xml.*;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.util.HtmlUtil;
@@ -35,7 +37,7 @@ import java.util.List;
* @author Maxim.Mossienko
*/
public class ScriptSupportUtil {
private static final Key<XmlTag[]> CachedScriptTagsKey = Key.create("script tags");
private static final Key<CachedValue<XmlTag[]>> CachedScriptTagsKey = Key.create("script tags");
private static final ThreadLocal<String> ProcessingDeclarationsFlag = new ThreadLocal<String>();
private static final @NonNls String SCRIPT_TAG = "script";
@@ -46,61 +48,71 @@ public class ScriptSupportUtil {
element.putUserData(CachedScriptTagsKey,null);
}
public static boolean processDeclarations(XmlFile element, PsiScopeProcessor processor, ResolveState state, PsiElement lastParent, PsiElement place) {
XmlTag[] myCachedScriptTags = element.getUserData(CachedScriptTagsKey);
public static boolean processDeclarations(final XmlFile element,
PsiScopeProcessor processor,
ResolveState state,
PsiElement lastParent,
PsiElement place) {
CachedValue<XmlTag[]> myCachedScriptTags = element.getUserData(CachedScriptTagsKey);
if (myCachedScriptTags == null) {
final List<XmlTag> scriptTags = new ArrayList<XmlTag>();
final XmlDocument document = HtmlUtil.getRealXmlDocument(element.getDocument());
myCachedScriptTags = element.getManager().getCachedValuesManager().createCachedValue(new CachedValueProvider<XmlTag[]>() {
@Override
public Result<XmlTag[]> compute() {
final List<XmlTag> scriptTags = new ArrayList<XmlTag>();
final XmlDocument document = HtmlUtil.getRealXmlDocument(element.getDocument());
if (document != null) {
XmlUtil.processXmlElements(document,
new PsiElementProcessor() {
public boolean execute(final PsiElement element) {
if (element instanceof XmlTag) {
final XmlTag tag = (XmlTag)element;
if (document != null) {
PsiElementProcessor psiElementProcessor = new PsiElementProcessor() {
public boolean execute(final PsiElement element) {
if (element instanceof XmlTag) {
final XmlTag tag = (XmlTag)element;
if (SCRIPT_TAG.equalsIgnoreCase(tag.getName())) {
final XmlElementDescriptor descriptor = tag.getDescriptor();
if (descriptor != null && SCRIPT_TAG.equals(descriptor.getName())) {
scriptTags.add(tag);
if (SCRIPT_TAG.equalsIgnoreCase(tag.getName())) {
final XmlElementDescriptor descriptor = tag.getDescriptor();
if (descriptor != null && SCRIPT_TAG.equals(descriptor.getName())) {
scriptTags.add(tag);
}
}
}
return true;
}
}
return true;
};
XmlUtil.processXmlElements(document,psiElementProcessor, true);
}
}, true);
}
myCachedScriptTags = scriptTags.toArray(new XmlTag[scriptTags.size()]);
return new Result<XmlTag[]>(scriptTags.toArray(new XmlTag[scriptTags.size()]), element);
}
}, false);
element.putUserData(CachedScriptTagsKey, myCachedScriptTags);
}
if (ProcessingDeclarationsFlag.get() != null) return true;
try {
ProcessingDeclarationsFlag.set("");
for (XmlTag tag : myCachedScriptTags) {
for (XmlTag tag : myCachedScriptTags.getValue()) {
final XmlTagChild[] children = tag.getValue().getChildren();
for (XmlTagChild child : children) {
if (!child.processDeclarations(processor, state, null, place)) return false;
}
if(tag.getAttributeValue("src") != null) {
if (tag.getAttributeValue("src") != null) {
final XmlAttribute attribute = tag.getAttribute("src", null);
if (attribute != null) {
final PsiFile psiFile = FileReferenceUtil.findFile(attribute.getValueElement());
if (psiFile != null && psiFile.isValid()) {
if(!psiFile.processDeclarations(processor, state, null, place))
if (!psiFile.processDeclarations(processor, state, null, place)) {
return false;
}
}
}
}
}
} finally {
}
finally {
ProcessingDeclarationsFlag.set(null);
}
@@ -66,16 +66,19 @@ public class XmlEntityRefImpl extends XmlElementImpl implements XmlEntityRef {
return cachedValue != null ? cachedValue.getValue():null;
}
public static void cacheParticularEntity(PsiFile file, final XmlEntityDecl decl) {
public static void cacheParticularEntity(PsiFile file, XmlEntityDecl decl) {
synchronized(PsiLock.LOCK) {
final Map<String, CachedValue<XmlEntityDecl>> cachingMap = getCachingMap(file);
final String name = decl.getName();
if (cachingMap.containsKey(name)) return;
final SmartPsiElementPointer declPointer = SmartPointerManager.getInstance(file.getProject()).createSmartPsiElementPointer(decl);
cachingMap.put(
name, CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<XmlEntityDecl>() {
public Result<XmlEntityDecl> compute() {
if (decl.isValid() && name.equals(decl.getName()))
return new Result<XmlEntityDecl>(decl,decl);
PsiElement declElement = declPointer.getElement();
if (declElement instanceof XmlEntityDecl && declElement.isValid() && name.equals(((XmlEntityDecl)declElement).getName()))
return new Result<XmlEntityDecl>((XmlEntityDecl)declElement, declElement);
cachingMap.put(name,null);
return new Result<XmlEntityDecl>(null,null);
}
@@ -122,29 +122,7 @@ class AnchorReference implements PsiReference, EmptyResolveMessageProvider {
if (file != null) {
CachedValue<Map<String, XmlTag>> value = file.getUserData(ourCachedIdsKey);
if (value == null) {
value = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<Map<String, XmlTag>>() {
public Result<Map<String, XmlTag>> compute() {
final Map<String,XmlTag> resultMap = new HashMap<String, XmlTag>();
XmlDocument document = HtmlUtil.getRealXmlDocument(file.getDocument());
final XmlTag rootTag = document != null ? document.getRootTag():null;
if (rootTag != null) {
processXmlElements(rootTag,
new PsiElementProcessor() {
public boolean execute(final PsiElement element) {
final String anchorValue = element instanceof XmlTag ? getAnchorValue((XmlTag)element):null;
if (anchorValue!=null) {
resultMap.put(anchorValue, (XmlTag)element);
}
return true;
}
}
);
}
return new Result<Map<String, XmlTag>>(resultMap, file);
}
}, false);
value = CachedValuesManager.getManager(file.getProject()).createCachedValue(new MapCachedValueProvider(file), false);
file.putUserData(ourCachedIdsKey, value);
}
@@ -239,4 +217,35 @@ class AnchorReference implements PsiReference, EmptyResolveMessageProvider {
XmlBundle.message("cannot.resolve.anchor", myAnchor) :
XmlBundle.message("cannot.resolve.anchor.in.file", myAnchor, xmlFile.getName());
}
// separate static class to avoid memory leak via this$0
private static class MapCachedValueProvider implements CachedValueProvider<Map<String, XmlTag>> {
private final XmlFile myFile;
public MapCachedValueProvider(XmlFile file) {
myFile = file;
}
public Result<Map<String, XmlTag>> compute() {
final Map<String,XmlTag> resultMap = new HashMap<String, XmlTag>();
XmlDocument document = HtmlUtil.getRealXmlDocument(myFile.getDocument());
final XmlTag rootTag = document != null ? document.getRootTag():null;
if (rootTag != null) {
processXmlElements(rootTag,
new PsiElementProcessor() {
public boolean execute(final PsiElement element) {
final String anchorValue = element instanceof XmlTag ? getAnchorValue((XmlTag)element):null;
if (anchorValue!=null) {
resultMap.put(anchorValue, (XmlTag)element);
}
return true;
}
}
);
}
return new Result<Map<String, XmlTag>>(resultMap, myFile);
}
}
}