diff --git a/bin/win/fsnotifier.exe b/bin/win/fsnotifier.exe index 0794f8cedaf2..7aa103c7f9a2 100644 Binary files a/bin/win/fsnotifier.exe and b/bin/win/fsnotifier.exe differ diff --git a/bin/win/vistalauncher.exe b/bin/win/vistalauncher.exe index 7a24123f268c..e58dcb531179 100644 Binary files a/bin/win/vistalauncher.exe and b/bin/win/vistalauncher.exe differ diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java b/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java index e1a28f705d66..edee6bb76c6a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java @@ -426,14 +426,4 @@ public class JVMNameUtil { } return ""; } - - public static PsiClass getTopLevelParentClass(PsiClass psiClass) { - PsiClass enclosing = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class, true); - while (enclosing != null) { - psiClass = enclosing; - enclosing = PsiTreeUtil.getParentOfType(enclosing, PsiClass.class, true); - } - return psiClass; - } - } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index d52466171885..8d4638c3fc09 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -85,7 +85,7 @@ public class PositionManagerImpl implements PositionManager { } if (PsiUtil.isLocalOrAnonymousClass(psiClass)) { - PsiClass parent = JVMNameUtil.getTopLevelParentClass(psiClass); + PsiClass parent = TopLevelParentClassProvider.getTopLevelParentClass(psiClass); if (parent == null) { return; @@ -244,7 +244,7 @@ public class PositionManagerImpl implements PositionManager { } if(PsiUtil.isLocalOrAnonymousClass(psiClass)) { - final PsiClass parentNonLocal = JVMNameUtil.getTopLevelParentClass(psiClass); + final PsiClass parentNonLocal = TopLevelParentClassProvider.getTopLevelParentClass(psiClass); if(parentNonLocal == null) { LOG.error("Local or anonymous class has no non-local parent"); return null; diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/TopLevelParentClassProvider.java b/java/debugger/openapi/src/com/intellij/debugger/engine/TopLevelParentClassProvider.java new file mode 100644 index 000000000000..782bf3452e2e --- /dev/null +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/TopLevelParentClassProvider.java @@ -0,0 +1,47 @@ +/* + * 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.debugger.engine; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.psi.PsiClass; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.Nullable; + +/** + * @author Max Medvedev + */ +public abstract class TopLevelParentClassProvider { + private static final ExtensionPointName EP_NAME = + ExtensionPointName.create("com.intellij.topLevelClassProvider"); + + public static PsiClass getTopLevelParentClass(PsiClass psiClass) { + for (TopLevelParentClassProvider provider : EP_NAME.getExtensions()) { + final PsiClass custom = provider.getCustomTopLevelParentClass(psiClass); + if (custom != null) return custom; + } + + PsiClass enclosing = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class, true); + while (enclosing != null) { + psiClass = enclosing; + enclosing = PsiTreeUtil.getParentOfType(enclosing, PsiClass.class, true); + } + return psiClass; + } + + @Nullable + protected abstract PsiClass getCustomTopLevelParentClass(PsiClass psiClass); + +} diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/scope/CompletionElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/scope/CompletionElement.java index 504ead34f034..5f95ae74e467 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/scope/CompletionElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/scope/CompletionElement.java @@ -16,7 +16,7 @@ package com.intellij.codeInsight.completion.scope; import com.intellij.psi.*; -import com.intellij.psi.util.PsiUtilCore; +import org.jetbrains.annotations.Nullable; /** * Created by IntelliJ IDEA. @@ -26,16 +26,12 @@ import com.intellij.psi.util.PsiUtilCore; * To change this template use Options | File Templates. */ public class CompletionElement{ - private final PsiType myQualifier; - private final PsiClass myQualifierClass; private final Object myElement; private final PsiSubstitutor mySubstitutor; - public CompletionElement(PsiType qualifier, Object element, PsiSubstitutor substitutor, final PsiClass qualifierClass){ + public CompletionElement(Object element, PsiSubstitutor substitutor) { myElement = element; - myQualifier = qualifier; mySubstitutor = substitutor; - myQualifierClass = qualifierClass; } public PsiSubstitutor getSubstitutor(){ @@ -46,34 +42,22 @@ public class CompletionElement{ return myElement; } - public Object getUniqueId(){ - final String name; + @Nullable + Object getUniqueId(){ if(myElement instanceof PsiClass){ - name = ((PsiClass)myElement).getQualifiedName(); + return ((PsiClass)myElement).getQualifiedName(); } - else if(myElement instanceof PsiPackage){ - name = ((PsiPackage)myElement).getQualifiedName(); + if(myElement instanceof PsiPackage){ + return ((PsiPackage)myElement).getQualifiedName(); } - else if(myElement instanceof PsiMethod){ + if(myElement instanceof PsiMethod){ return ((PsiMethod)myElement).getSignature(mySubstitutor); } - else if (myElement instanceof PsiField) { - final PsiField field = (PsiField)myElement; - final String s = field.getName(); - if (myQualifierClass != null || !field.hasModifierProperty(PsiModifier.STATIC)) return "#" + s; - return field.getContainingClass().getQualifiedName() + "#" + s; - } - else if(myElement instanceof PsiElement){ - name = PsiUtilCore.getName((PsiElement)myElement); - } - else{ - name = ""; + if (myElement instanceof PsiVariable) { + return "#" + ((PsiVariable)myElement).getName(); } - return name; + return null; } - public PsiType getQualifier(){ - return myQualifier; - } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java index df2dccdbe9d9..95c74648027a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java @@ -224,7 +224,7 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme } if (satisfies(element, state) && isAccessible(element)) { - CompletionElement element1 = new CompletionElement(myQualifierType, element, state.get(PsiSubstitutor.KEY), myQualifierClass); + CompletionElement element1 = new CompletionElement((PsiNamedElement)element, state.get(PsiSubstitutor.KEY)); if (myResultNames.add(element1.getUniqueId())) { myResults.add(element1); } @@ -257,7 +257,7 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme public void setCompletionElements(@NotNull Object[] elements) { for (Object element: elements) { - myResults.add(new CompletionElement(null, element, PsiSubstitutor.EMPTY, myQualifierClass)); + myResults.add(new CompletionElement(element, PsiSubstitutor.EMPTY)); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java index 2f55b0e977f6..1f6c01625a0d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/StringLiteralCopyPasteProcessor.java @@ -98,7 +98,7 @@ public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor { numberOfSymbolsToCopy = Math.min(escapedEndOffset, fileEndOffset) - Math.max(fileStartOffset, escapedStartOffset); if (numberOfSymbolsToCopy > 0) { textWasChanged = true; - buffer.append(unescapeStringCharacters(text.substring(givenTextStartOffset, givenTextStartOffset + numberOfSymbolsToCopy))); + buffer.append(unescape(text.substring(givenTextStartOffset, givenTextStartOffset + numberOfSymbolsToCopy), element)); givenTextStartOffset += numberOfSymbolsToCopy; } @@ -112,7 +112,12 @@ public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor { } return textWasChanged ? buffer.toString() : null; } - + + @NotNull + protected String unescape(String text, PsiElement token) { + return unescapeStringCharacters(text); + } + public String preprocessOnPaste(final Project project, final PsiFile file, final Editor editor, String text, final RawText rawText) { final Document document = editor.getDocument(); PsiDocumentManager.getInstance(project).commitDocument(document); @@ -139,9 +144,10 @@ public class StringLiteralCopyPasteProcessor implements CopyPastePreProcessor { @NonNls String breaker = getLineBreaker(token); final String[] lines = LineTokenizer.tokenize(text.toCharArray(), false, true); for (int i = 0; i < lines.length; i++) { - String line = lines[i]; - buffer.append(escapeCharCharacters(line, token, escapeSlashes)); - if (i != lines.length - 1) buffer.append(breaker); + buffer.append(escapeCharCharacters(lines[i], token, escapeSlashes)); + if (i != lines.length - 1 || "\n".equals(breaker) && text.endsWith("\n")) { + buffer.append(breaker); + } } text = buffer.toString(); } diff --git a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaElementSignatureProvider.java b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaElementSignatureProvider.java index b92c9796bb2d..3bbbba17c091 100644 --- a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaElementSignatureProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaElementSignatureProvider.java @@ -152,7 +152,12 @@ public class JavaElementSignatureProvider extends AbstractElementSignatureProvid return null; } - protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file, @NotNull PsiElement parent, @NotNull String type, @NotNull StringTokenizer tokenizer) { + protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file, + @NotNull PsiElement parent, + @NotNull String type, + @NotNull StringTokenizer tokenizer, + @Nullable StringBuilder processingInfoStorage) + { if (type.equals("imports")) { if (!(file instanceof PsiJavaFile)) return null; return ((PsiJavaFile)file).getImportList(); diff --git a/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java b/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java index ed577175a08c..5ac29a8c7231 100644 --- a/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java +++ b/java/java-impl/src/com/intellij/ide/util/SuperMethodWarningUtil.java @@ -16,12 +16,17 @@ package com.intellij.ide.util; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; +import com.intellij.psi.presentation.java.SymbolPresentationUtil; +import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.searches.DeepestSuperMethodsSearch; +import com.intellij.ui.components.JBList; import com.intellij.usageView.UsageViewUtil; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; @@ -102,4 +107,51 @@ public class SuperMethodWarningUtil { return null; } + + public static void checkSuperMethod(final PsiMethod method, + final String actionString, + final PsiElementProcessor processor, + final Editor editor) { + PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + processor.execute(method); + return; + } + + PsiMethod superMethod = method.findDeepestSuperMethod(); + if (superMethod == null) { + processor.execute(method); + return; + } + + final PsiClass containingClass = superMethod.getContainingClass(); + if (containingClass == null) { + processor.execute(method); + return; + } + + if (ApplicationManager.getApplication().isUnitTestMode()) { + processor.execute(superMethod); + return; + } + + final PsiMethod[] methods = new PsiMethod[]{superMethod, method}; + final String renameBase = actionString + " base method"; + final String renameCurrent = actionString + " only current method"; + final JBList list = new JBList(renameBase, renameCurrent); + JBPopupFactory.getInstance().createListPopupBuilder(list) + .setTitle(method.getName() + (containingClass.isInterface() && !aClass.isInterface() ? " implements" : " overrides") + " method of " + + SymbolPresentationUtil.getSymbolPresentableText(containingClass)) + .setMovable(false) + .setResizable(false) + .setRequestFocus(true) + .setItemChoosenCallback(new Runnable() { + public void run() { + final Object value = list.getSelectedValue(); + if (value instanceof String) { + processor.execute(methods[value.equals(renameBase) ? 0 : 1]); + } + } + }).createPopup().showInBestPositionFor(editor); + } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/lang/java/JavaRefactoringSupportProvider.java b/java/java-impl/src/com/intellij/lang/java/JavaRefactoringSupportProvider.java index 4ff4ec49cf6a..6d057ff4c795 100644 --- a/java/java-impl/src/com/intellij/lang/java/JavaRefactoringSupportProvider.java +++ b/java/java-impl/src/com/intellij/lang/java/JavaRefactoringSupportProvider.java @@ -65,9 +65,6 @@ public class JavaRefactoringSupportProvider extends RefactoringSupportProvider { @Override public boolean isMemberInplaceRenameAvailable(PsiElement elementToRename, PsiElement context) { - if (elementToRename instanceof PsiMethod && ((PsiMethod)elementToRename).findDeepestSuperMethods().length > 0) { - return false; - } return elementToRename instanceof PsiMember; } diff --git a/java/java-impl/src/com/intellij/psi/impl/light/LightField.java b/java/java-impl/src/com/intellij/psi/impl/light/LightField.java new file mode 100644 index 000000000000..e337f7ae7cd2 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/impl/light/LightField.java @@ -0,0 +1,150 @@ +/* + * 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.psi.impl.light; + +import com.intellij.lang.java.JavaLanguage; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.search.SearchScope; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class LightField extends LightElement implements PsiField { + private final PsiField myField; + private final PsiClass myContainingClass; + + public LightField(@NotNull final PsiManager manager, @NotNull final PsiField field, @NotNull final PsiClass containingClass) { + super(manager, JavaLanguage.INSTANCE); + myField = field; + myContainingClass = containingClass; + } + + @Override + public void setInitializer(@Nullable final PsiExpression initializer) throws IncorrectOperationException { + throw new IncorrectOperationException("Not supported"); + } + + @NotNull + @Override + public SearchScope getUseScope() { + return myField.getUseScope(); + } + + @Override + public String getName() { + return myField.getName(); + } + + @NotNull + @Override + public PsiIdentifier getNameIdentifier() { + return myField.getNameIdentifier(); + } + + @Override + public PsiDocComment getDocComment() { + return myField.getDocComment(); + } + + @Override + public boolean isDeprecated() { + return myField.isDeprecated(); + } + + @Override + public PsiClass getContainingClass() { + return myContainingClass; + } + + @NotNull + @Override + public PsiType getType() { + return myField.getType(); + } + + @Override + public PsiTypeElement getTypeElement() { + return myField.getTypeElement(); + } + + @Override + public PsiExpression getInitializer() { + return myField.getInitializer(); + } + + @Override + public boolean hasInitializer() { + return myField.hasInitializer(); + } + + @Override + public void normalizeDeclaration() throws IncorrectOperationException { + throw new IncorrectOperationException("Not supported"); + } + + @Override + public Object computeConstantValue() { + return myField.computeConstantValue(); + } + + @Override + public PsiElement setName(@NonNls @NotNull final String name) throws IncorrectOperationException { + throw new IncorrectOperationException("Not supported"); + } + + @Override + public PsiType getTypeNoResolve() { + return myField.getTypeNoResolve(); + } + + @Override + public PsiModifierList getModifierList() { + return myField.getModifierList(); + } + + @Override + public boolean hasModifierProperty(@Modifier @NonNls @NotNull final String name) { + return myField.hasModifierProperty(name); + } + + @Override + public String getText() { + return myField.getText(); + } + + @Override + public PsiElement copy() { + return new LightField(myManager, (PsiField)myField.copy(), myContainingClass); + } + + @Override + public TextRange getTextRange() { + return new TextRange(-1, -1); + } + + @Override + public boolean isValid() { + return myContainingClass.isValid(); + } + + @Override + public String toString() { + return "PsiField:" + getName(); + } +} diff --git a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java index 5b751432ed29..2868623dcbaf 100644 --- a/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/rename/RenameJavaMethodProcessor.java @@ -18,8 +18,10 @@ package com.intellij.refactoring.rename; import com.intellij.ide.util.SuperMethodWarningUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.Pass; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.MethodReferencesSearch; @@ -237,6 +239,25 @@ public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor { return SuperMethodWarningUtil.checkSuperMethod(psiMethod, RefactoringBundle.message("to.rename")); } + @Override + public void substituteElementToRename(@NotNull PsiElement element, + @NotNull Editor editor, + @NotNull final Pass renameCallback) { + PsiMethod psiMethod = (PsiMethod)element; + if (psiMethod.isConstructor()) { + super.substituteElementToRename(element, editor, renameCallback); + } + else { + SuperMethodWarningUtil.checkSuperMethod(psiMethod, "Rename", new PsiElementProcessor() { + @Override + public boolean execute(@NotNull PsiMethod method) { + renameCallback.pass(method); + return false; + } + }, editor); + } + } + private static void findSubmemberHidesMemberCollisions(final PsiMethod method, final String newName, final List result) { final PsiClass containingClass = method.getContainingClass(); if (containingClass == null) return; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/PsiMethodStub.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/PsiMethodStub.java index 67ae992346a4..1e1099e31e5f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/PsiMethodStub.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/PsiMethodStub.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -14,22 +14,23 @@ * limitations under the License. */ -/* - * @author max - */ package com.intellij.psi.impl.java.stubs; import com.intellij.psi.PsiMethod; import com.intellij.psi.impl.cache.TypeInfo; import com.intellij.psi.stubs.NamedStub; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +/** + * @author max + */ public interface PsiMethodStub extends NamedStub { boolean isConstructor(); boolean isVarArgs(); boolean isAnnotationMethod(); - String getDefaultValueText(); + @Nullable String getDefaultValueText(); @NotNull TypeInfo getReturnTypeText(boolean doResolve); boolean isDeprecated(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java index 35dd68955db4..81420296c9dd 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiMethodStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -174,8 +174,9 @@ public class PsiMethodStubImpl extends StubBase implements PsiMethodS builder.append(getName()).append(":").append(TypeInfo.createTypeText(getReturnTypeText(false))); - if (getDefaultValueText() != null) { - builder.append(" default=").append(getDefaultValueText()); + final String defaultValue = getDefaultValueText(); + if (defaultValue != null) { + builder.append(" default=").append(defaultValue); } builder.append("]"); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightMethod.java b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightMethod.java index bdd8d76a869a..8e997d680670 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/light/LightMethod.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/light/LightMethod.java @@ -41,10 +41,6 @@ public class LightMethod extends LightElement implements PsiMethod { private final PsiMethod myMethod; private final PsiClass myContainingClass; - public LightMethod(PsiMethod method, PsiClass containingClass) { - this(method.getManager(), method, containingClass); - } - public LightMethod(PsiManager manager, PsiMethod method, PsiClass containingClass) { super(manager, JavaLanguage.INSTANCE); myMethod = method; diff --git a/java/java-tests/testData/codeInsight/completion/normal/DoubleConstant.java b/java/java-tests/testData/codeInsight/completion/normal/DoubleConstant.java new file mode 100644 index 000000000000..3d2d9b3a9097 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/DoubleConstant.java @@ -0,0 +1,8 @@ +interface Intf { Intf FOO = null; } +interface Intf2 extends Intf { Intf2 FOO = null; } + +public class Bar implements Intf2 { + public static void fpp() { + F + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index fd93dffc789b..5dafd05d950b 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -494,6 +494,11 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { assertStringItems("boolean", "byte") } + public void testDoubleConstant() throws Throwable { + configure() + assertStringItems("FOO", "Float") + } + public void testNotOnlyKeywordsInsideSwitch() throws Throwable { doTest(); } diff --git a/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java b/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java index d0f0fa53bfe2..a9a3a83bc5a1 100644 --- a/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java +++ b/platform/core-api/src/com/intellij/psi/tree/IFileElementType.java @@ -31,6 +31,7 @@ public class IFileElementType extends ILazyParseableElementType { super(debugName, language); } + @Nullable @Override public ASTNode parseContents(final ASTNode chameleon) { final PsiElement psi = chameleon.getPsi(); diff --git a/platform/core-impl/src/com/intellij/openapi/editor/ex/DisposableIterator.java b/platform/core-impl/src/com/intellij/openapi/editor/ex/DisposableIterator.java new file mode 100644 index 000000000000..f9f1483d44a2 --- /dev/null +++ b/platform/core-impl/src/com/intellij/openapi/editor/ex/DisposableIterator.java @@ -0,0 +1,43 @@ +/* + * 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.openapi.editor.ex; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +public interface DisposableIterator extends Iterator { + void dispose(); + DisposableIterator EMPTY = new DisposableIterator() { + @Override + public void dispose() { + } + + @Override + public boolean hasNext() { + return false; + } + + @Override + public Object next() { + throw new NoSuchElementException(); + } + + @Override + public void remove() { + throw new IllegalAccessError(); + } + }; +} diff --git a/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java b/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java index 832be08c629b..ff22a4e003be 100644 --- a/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/editor/impl/IntervalTreeImpl.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.editor.impl; +import com.intellij.openapi.editor.ex.DisposableIterator; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.Trinity; import com.intellij.util.IncorrectOperationException; @@ -22,14 +23,12 @@ import com.intellij.util.Processor; import com.intellij.util.SmartList; import com.intellij.util.WalkingState; import com.intellij.util.concurrency.AtomicFieldUpdater; -import com.intellij.util.containers.ContainerUtil; import gnu.trove.TLongHashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.lang.ref.ReferenceQueue; import java.util.ConcurrentModificationException; -import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.concurrent.locks.Lock; @@ -495,15 +494,18 @@ public abstract class IntervalTreeImpl extends RedBla } @NotNull - Iterator overlappingIterator(final int startOffset, final int endOffset) { + DisposableIterator overlappingIterator(final int startOffset, final int endOffset) { final IntervalNode firstOverlap = findMinOverlappingWith(getRoot(), new TextRangeInterval(startOffset, endOffset), modCount, 0); if (firstOverlap == null) { - return ContainerUtil.emptyIterator(); + return DisposableIterator.EMPTY; } final int firstOverlapDelta = firstOverlap.computeDeltaUpToRoot(); final int firstOverlapStart = firstOverlap.intervalStart() + firstOverlapDelta; final int modCountBefore = modCount; - return new Iterator() { + + l.readLock().lock(); + + return new DisposableIterator() { private IntervalNode currentNode = firstOverlap; private int deltaUpToRootExclusive = firstOverlapDelta-firstOverlap.delta; private int indexInCurrentList = 0; @@ -513,39 +515,33 @@ public abstract class IntervalTreeImpl extends RedBla public boolean hasNext() { if (current != null) return true; if (currentNode == null) return false; - try { - l.readLock().lock(); - if (modCount != modCountBefore) throw new ConcurrentModificationException(); - while (indexInCurrentList != currentNode.intervals.size()) { - T t = currentNode.intervals.get(indexInCurrentList++).get(); - if (t != null) { - current = t; - return true; - } - } - indexInCurrentList = 0; - while (true) { - currentNode = nextNode(currentNode); - if (currentNode == null) { - return false; - } - if (overlaps(currentNode, startOffset, endOffset, deltaUpToRootExclusive)) { - assert currentNode.intervalStart() + deltaUpToRootExclusive + currentNode.delta >= firstOverlapStart; - indexInCurrentList = 0; - while (indexInCurrentList != currentNode.intervals.size()) { - T t = currentNode.intervals.get(indexInCurrentList++).get(); - if (t != null) { - current = t; - return true; - } - } - indexInCurrentList = 0; - } + if (modCount != modCountBefore) throw new ConcurrentModificationException(); + while (indexInCurrentList != currentNode.intervals.size()) { + T t = currentNode.intervals.get(indexInCurrentList++).get(); + if (t != null) { + current = t; + return true; } } - finally { - l.readLock().unlock(); + indexInCurrentList = 0; + while (true) { + currentNode = nextNode(currentNode); + if (currentNode == null) { + return false; + } + if (overlaps(currentNode, startOffset, endOffset, deltaUpToRootExclusive)) { + assert currentNode.intervalStart() + deltaUpToRootExclusive + currentNode.delta >= firstOverlapStart; + indexInCurrentList = 0; + while (indexInCurrentList != currentNode.intervals.size()) { + T t = currentNode.intervals.get(indexInCurrentList++).get(); + if (t != null) { + current = t; + return true; + } + } + indexInCurrentList = 0; + } } } @@ -562,6 +558,11 @@ public abstract class IntervalTreeImpl extends RedBla throw new IncorrectOperationException(); } + @Override + public void dispose() { + l.readLock().unlock(); + } + // next node in in-order traversal private IntervalNode nextNode(@NotNull IntervalNode root) { assert root.isValid(); diff --git a/platform/lang-api/src/com/intellij/execution/filters/Filter.java b/platform/lang-api/src/com/intellij/execution/filters/Filter.java index 83ef58fd741f..149f4487d5e5 100644 --- a/platform/lang-api/src/com/intellij/execution/filters/Filter.java +++ b/platform/lang-api/src/com/intellij/execution/filters/Filter.java @@ -23,6 +23,9 @@ import org.jetbrains.annotations.Nullable; * @version 1.0 */ public interface Filter { + + Filter[] EMPTY_ARRAY = new Filter[0]; + class Result{ public final int highlightStartOffset; public final int highlightEndOffset; diff --git a/platform/lang-api/src/com/intellij/ide/StandardTargetWeights.java b/platform/lang-api/src/com/intellij/ide/StandardTargetWeights.java index ca41ff18a1ef..5b5ee0d7138e 100644 --- a/platform/lang-api/src/com/intellij/ide/StandardTargetWeights.java +++ b/platform/lang-api/src/com/intellij/ide/StandardTargetWeights.java @@ -20,11 +20,11 @@ package com.intellij.ide; */ public interface StandardTargetWeights { float PROJECT_WEIGHT = 1; + float FAVORITES_WEIGHT = 1.01f; float PACKAGES_WEIGHT = 2; float J2EE_WEIGHT = 3; float STRUCTURE_WEIGHT = 4; float COMMANDER_WEIGHT = 5; - float FAVORITES_WEIGHT = 6; float SCOPE_WEIGHT = 6.5f; float NAV_BAR_WEIGHT = 8; float CHANGES_VIEW = 9; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java index e752cb59a49a..04fdb13567ea 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java @@ -474,8 +474,7 @@ public class CodeCompletionHandlerBase implements CodeInsightActionHandler { if (decision == AutoCompletionDecision.SHOW_LOOKUP) { CompletionServiceImpl.setCompletionPhase(new CompletionPhase.ItemsCalculated(indicator)); indicator.getLookup().setCalculating(false); - indicator.showLookup(); - if (isAutocompleteCommonPrefixOnInvocation() && items.length > 1) { + if (indicator.showLookup() && isAutocompleteCommonPrefixOnInvocation() && items.length > 1) { indicator.fillInCommonPrefix(false); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java index 96e49d55dc02..1d7a85c4c861 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -304,8 +304,8 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement return "Completion" + hashCode(); } - public void showLookup() { - updateLookup(); + public boolean showLookup() { + return updateLookup(); } public CompletionParameters getParameters() { @@ -320,14 +320,14 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement return myLookup; } - private void updateLookup() { + private boolean updateLookup() { ApplicationManager.getApplication().assertIsDispatchThread(); - if (isOutdated()) return; + if (isOutdated()) return false; boolean justShown = false; if (!myLookup.isShown() && shouldShowLookup()) { if (hideAutopopupIfMeaningless()) { - return; + return false; } if (StringUtil.isEmpty(myLookup.getAdvertisementText()) && !isAutopopupCompletion()) { @@ -338,7 +338,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement } if (!myLookup.showLookup()) { - return; + return false; } justShown = true; } @@ -347,6 +347,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement if (justShown) { myLookup.ensureSelectionVisible(); } + return true; } private boolean shouldShowLookup() { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EnterHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EnterHandler.java index 0a2d1a911aa6..af0a29796c3b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EnterHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/EnterHandler.java @@ -125,7 +125,6 @@ public class EnterHandler extends BaseEnterHandler { if (result == EnterHandlerDelegate.Result.Stop) return; if (result != EnterHandlerDelegate.Result.Continue) { - text = document.getCharsSequence(); if (result == EnterHandlerDelegate.Result.DefaultForceIndent) { forceIndent = true; } @@ -133,6 +132,7 @@ public class EnterHandler extends BaseEnterHandler { } } + text = document.getCharsSequence(); // update after changes done in preprocessEnter() caretOffset = caretOffsetRef.get().intValue(); boolean isFirstColumn = caretOffset == 0 || text.charAt(caretOffset - 1) == '\n'; final boolean insertSpace = diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java index 3664639fcb7a..e96aa03e9c21 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/BaseIndentEnterHandler.java @@ -32,7 +32,9 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; +import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; +import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; @@ -126,7 +128,9 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter { } protected String getSingleIndent(final PsiFile file) { - return StringUtil.repeatSymbol(' ', CodeStyleSettingsManager.getInstance().getCurrentSettings().getIndentSize(myLanguage.getAssociatedFileType())); + CodeStyleSettings currantSettings = CodeStyleSettingsManager.getSettings(file.getProject()); + CommonCodeStyleSettings.IndentOptions indentOptions = currantSettings.getIndentOptions(file.getFileType()); + return StringUtil.repeatSymbol(' ', indentOptions.INDENT_SIZE); } @Nullable diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/MoverWrapper.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/MoverWrapper.java index c0398a8d004f..8ed24949c8e2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/MoverWrapper.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/moveUpDown/MoverWrapper.java @@ -61,11 +61,7 @@ class MoverWrapper { String textToInsert2 = document.getCharsSequence().subSequence(start2, end2).toString(); if (!StringUtil.endsWithChar(textToInsert2,'\n')) textToInsert2 += '\n'; myInfo.range2 = document.createRangeMarker(start2, end2); - final int startOffset1 = myInfo.range1.getStartOffset(); - final int startOffset2 = myInfo.range2.getStartOffset(); - final int endOffset1 = myInfo.range1.getEndOffset(); - final int endOffset2 = myInfo.range2.getEndOffset(); - if (startOffset1 < startOffset2) { + if (myInfo.range1.getStartOffset() < myInfo.range2.getStartOffset()) { myInfo.range1.setGreedyToLeft(true); myInfo.range1.setGreedyToRight(false); myInfo.range2.setGreedyToLeft(true); @@ -110,13 +106,14 @@ class MoverWrapper { } } - document.insertString(startOffset1, textToInsert2); - - document.deleteString(startOffset1 +textToInsert2.length(), endOffset1); + document.insertString(myInfo.range1.getStartOffset(), textToInsert2); + document.deleteString(myInfo.range1.getStartOffset()+textToInsert2.length(), myInfo.range1.getEndOffset()); - document.insertString(startOffset2, textToInsert); - if (endOffset2 > startOffset1 + textToInsert.length()) { - document.deleteString(startOffset2 + textToInsert.length(), endOffset2); + document.insertString(myInfo.range2.getStartOffset(), textToInsert); + int s = myInfo.range2.getStartOffset() + textToInsert.length(); + int e = myInfo.range2.getEndOffset(); + if (e > s) { + document.deleteString(s, e); } final Project project = file.getProject(); @@ -138,10 +135,10 @@ class MoverWrapper { CodeFoldingManager.getInstance(project).allowFoldingOnCaretLine(editor); if (hasSelection) { - restoreSelection(editor, selectionStart, selectionEnd, start, startOffset2); + restoreSelection(editor, selectionStart, selectionEnd, start, myInfo.range2.getStartOffset()); } - caretModel.moveToOffset(startOffset2 + caretRelativePos); + caretModel.moveToOffset(myInfo.range2.getStartOffset() + caretRelativePos); if (myInfo.indentTarget) { indentLinesIn(editor, file, document, project, myInfo.range2); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/AbstractElementSignatureProvider.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/AbstractElementSignatureProvider.java index 4ffbdb14c132..3e67a2641213 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/AbstractElementSignatureProvider.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/AbstractElementSignatureProvider.java @@ -42,7 +42,9 @@ public abstract class AbstractElementSignatureProvider implements ElementSignatu if (semicolonIndex >= 0) { String parentSignature = signature.substring(semicolonIndex + 1); if (processingInfoStorage != null) { - processingInfoStorage.append(String.format("Restoring parent by signature '%s'...%n", parentSignature)); + processingInfoStorage.append(String.format( + "Provider '%s'. Restoring parent by signature '%s'...%n", getClass().getName(), parentSignature + )); } parent = restoreBySignature(file, parentSignature, processingInfoStorage); if (processingInfoStorage != null) { @@ -59,17 +61,19 @@ public abstract class AbstractElementSignatureProvider implements ElementSignatu String type = tokenizer.nextToken(); if (processingInfoStorage != null) { processingInfoStorage.append(String.format( - "Restoring target element by signature '%s'. Parent: %s, same as the given parent: %b%n", signature, parent, parent == file + "Provider '%s'. Restoring target element by signature '%s'. Parent: %s, same as the given parent: %b%n", + getClass().getName(), signature, parent, parent == file )); } - return restoreBySignatureTokens(file, parent, type, tokenizer); + return restoreBySignatureTokens(file, parent, type, tokenizer, processingInfoStorage); } @Nullable protected abstract PsiElement restoreBySignatureTokens(@NotNull PsiFile file, @NotNull PsiElement parent, @NotNull String type, - @NotNull StringTokenizer tokenizer); + @NotNull StringTokenizer tokenizer, + @Nullable StringBuilder processingInfoStorage); protected static int getChildIndex(T element, PsiElement parent, String name, Class hisClass) { PsiElement[] children = parent.getChildren(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/OffsetsElementSignatureProvider.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/OffsetsElementSignatureProvider.java index a930d1859c64..6cb1fba7da5a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/OffsetsElementSignatureProvider.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/OffsetsElementSignatureProvider.java @@ -19,6 +19,7 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.StringTokenizer; @@ -38,9 +39,16 @@ public class OffsetsElementSignatureProvider extends AbstractElementSignaturePro protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file, @NotNull PsiElement parent, @NotNull String type, - @NotNull StringTokenizer tokenizer) + @NotNull StringTokenizer tokenizer, + @Nullable StringBuilder processingInfoStorage) { if (!TYPE_MARKER.equals(type)) { + if (processingInfoStorage != null) { + processingInfoStorage.append(String.format( + "Stopping '%s' provider because given signature doesn't have expected type - can work with '%s' but got '%s'", + getClass().getName(), TYPE_MARKER, type + )); + } return null; } int start; @@ -52,15 +60,28 @@ public class OffsetsElementSignatureProvider extends AbstractElementSignaturePro catch (NumberFormatException e) { return null; } + if (processingInfoStorage != null) { + processingInfoStorage.append(String.format("Parsed target offsets - [%d; %d)", start, end)); + } + PsiElement element = file.findElementAt(start); + if (processingInfoStorage != null) { + processingInfoStorage.append(String.format("Found the following element at start offset - '%s'", element)); + } if (element == null) { return null; } TextRange range = element.getTextRange(); + if (processingInfoStorage != null) { + processingInfoStorage.append(String.format("Target element range is %s", range)); + } while (range != null && range.getStartOffset() == start && range.getEndOffset() < end) { element = element.getParent(); range = element.getTextRange(); + if (processingInfoStorage != null) { + processingInfoStorage.append(String.format("Expanding element to '%s' and range to '%s'", element, range)); + } } if (range == null || range.getStartOffset() != start || range.getEndOffset() != end) { return null; @@ -82,10 +103,17 @@ public class OffsetsElementSignatureProvider extends AbstractElementSignaturePro indexFromRoot++; } + if (processingInfoStorage != null) { + processingInfoStorage.append(String.format("Target element index is %d. Current index from root is %d", index, indexFromRoot)); + } + if (index > indexFromRoot) { int steps = index - indexFromRoot; PsiElement result = element; for (PsiElement e = result.getFirstChild(); steps > 0 && e != null && range.equals(e.getTextRange()); steps--, e = e.getFirstChild()) { + if (processingInfoStorage != null) { + processingInfoStorage.append(String.format("Clarifying target element to '%s', its range is %s", result, result.getTextRange())); + } result = e; } return result; @@ -95,15 +123,21 @@ public class OffsetsElementSignatureProvider extends AbstractElementSignaturePro PsiElement result = element; while (--steps >= 0) { result = result.getParent(); + if (processingInfoStorage != null) { + processingInfoStorage.append(String.format("Reducing target element to '%s', its range is %s", result, result.getTextRange())); + } } return result; } @Override public String getSignature(@NotNull PsiElement element) { + TextRange range = element.getTextRange(); + if (range.isEmpty()) { + return null; + } StringBuilder buffer = new StringBuilder(); buffer.append(TYPE_MARKER).append("#"); - TextRange range = element.getTextRange(); buffer.append(range.getStartOffset()); buffer.append(ELEMENT_TOKENS_SEPARATOR); buffer.append(range.getEndOffset()); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java index f70f5b2ac41d..c117e7eb3242 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/folding/impl/PsiNamesElementSignatureProvider.java @@ -19,6 +19,7 @@ import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; import java.util.StringTokenizer; /** @@ -41,9 +42,16 @@ public class PsiNamesElementSignatureProvider extends AbstractElementSignaturePr protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file, @NotNull PsiElement parent, @NotNull final String type, - @NotNull StringTokenizer tokenizer) + @NotNull StringTokenizer tokenizer, + @Nullable StringBuilder processingInfoStorage) { if (!TYPE_MARKER.equals(type)) { + if (processingInfoStorage != null) { + processingInfoStorage.append(String.format( + "Stopping '%s' provider because given signature doesn't have expected type - can work with '%s' but got '%s'", + getClass().getName(), TYPE_MARKER, type + )); + } return null; } String elementMarker = tokenizer.nextToken(); @@ -58,6 +66,12 @@ public class PsiNamesElementSignatureProvider extends AbstractElementSignaturePr result = child; } else { + if (processingInfoStorage != null) { + processingInfoStorage.append(String.format( + "Stopping '%s' provider because it has top level marker but more than one non white-space child: %s", + getClass().getName(), Arrays.toString(children) + )); + } // More than one top-level non-white space children. Can't match. return null; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java index 4ec86542218f..6ed8cd6df493 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java @@ -32,7 +32,9 @@ import com.intellij.lang.LangBundle; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.IdeActions; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; @@ -718,18 +720,19 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable } public void finishLookup(char completionChar, @Nullable final LookupElement item) { - doHide(false, true); if (item == null || item instanceof EmptyLookupItem || item.getObject() instanceof DeferredUserLookupValue && item.as(LookupItem.CLASS_CONDITION_KEY) != null && !((DeferredUserLookupValue)item.getObject()).handleUserSelection(item.as(LookupItem.CLASS_CONDITION_KEY), myProject)) { + doHide(false, true); fireItemSelected(null, completionChar); return; } final PsiFile file = getPsiFile(); if (file != null && !WriteCommandAction.ensureFilesWritable(myProject, Arrays.asList(file))) { + doHide(false, true); fireItemSelected(null, completionChar); return; } @@ -744,13 +747,21 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable if (!plainMatch) { FeatureUsageTracker.getInstance().triggerFeatureUsed(CodeCompletionFeatures.EDITING_COMPLETION_CAMEL_HUMPS); } - - ApplicationManager.getApplication().runWriteAction(new Runnable() { + + performGuardedChange(new Runnable() { public void run() { - insertLookupString(item, prefix); + AccessToken token = WriteAction.start(); + try { + insertLookupString(item, prefix); + } + finally { + token.finish(); + } } }); + doHide(false, true); + fireItemSelected(item, completionChar); } diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index da5a75381f49..2e3ce267e113 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -180,9 +180,6 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { myPanel.removeAll(); myPanel.add(myHistoryViewer.getComponent(), BorderLayout.CENTER); myFullEditor = fileManager.openTextEditor(new OpenFileDescriptor(getProject(), virtualFile, 0), true); - configureFullEditor(); - setConsoleFilePinned(fileManager); - myHistoryViewer.setHorizontalScrollbarVisible(true); myCurrentEditor = myFullEditor; } @@ -201,7 +198,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { public void setFullEditorActions(ActionGroup actionGroup) { myFullEditorActions = actionGroup; - configureFullEditor(); + configureFullEditor(myFullEditor); } public void setShowSeparatorLine(boolean showSeparatorLine) { @@ -539,6 +536,11 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { for (FileEditor fileEditor : source.getAllEditors(file)) { if (!(fileEditor instanceof TextEditor)) continue; final Editor editor = ((TextEditor)fileEditor).getEditor(); + // todo what if it is splitted? + myCurrentEditor = editor; + myFullEditor = editor; + configureFullEditor(editor); + setConsoleFilePinned((FileEditorManagerEx)source); EmptyAction.registerActionShortcuts(editor.getComponent(), myConsoleEditor.getComponent()); editor.getCaretModel().addCaretListener(new CaretListener() { public void caretPositionChanged(CaretEvent e) { @@ -595,20 +597,18 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { } editorManager.closeFile(file); myFullEditor = editorManager.openTextEditor(new OpenFileDescriptor(getProject(), newVFile, offset), focusEditor); - configureFullEditor(); - setConsoleFilePinned(editorManager); } } } - private void configureFullEditor() { - if (myFullEditor == null || myFullEditorActions == null) return; + private void configureFullEditor(final Editor editor) { + if (editor == null || myFullEditorActions == null) return; final JPanel header = new JPanel(new BorderLayout()); final ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, myFullEditorActions, true); - actionToolbar.setTargetComponent(myFullEditor.getContentComponent()); + actionToolbar.setTargetComponent(editor.getContentComponent()); header.add(actionToolbar.getComponent(), BorderLayout.EAST); - myFullEditor.setHeaderComponent(header); - myFullEditor.getSettings().setLineMarkerAreaShown(false); + editor.setHeaderComponent(header); + editor.getSettings().setLineMarkerAreaShown(false); } public void setInputText(final String query) { diff --git a/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java index 7619aaa1a45d..a105a0ba1f20 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java @@ -590,7 +590,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable { return true; } final boolean destroyProcess; - if (Boolean.TRUE.equals(processHandler.getUserData(ProcessHandler.SILENTLY_DESTROY_ON_CLOSE))) { + if (processHandler.isSilentlyDestroyOnClose() || Boolean.TRUE.equals(processHandler.getUserData(ProcessHandler.SILENTLY_DESTROY_ON_CLOSE))) { destroyProcess = true; } else { diff --git a/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java b/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java index 90e007945a3d..fbd6b1db7d5a 100644 --- a/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java +++ b/platform/lang-impl/src/com/intellij/ide/PsiCopyPasteManager.java @@ -220,7 +220,8 @@ public class PsiCopyPasteManager { if (myElements == null || myElements.length == 0) { return null; } - return myElements [0].getProject(); + final PsiElement element = myElements[0]; + return element.isValid() ? element.getProject() : null; } } diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeViewPanel.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeViewPanel.java index 5709b7b20026..9ebf5fd37f61 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeViewPanel.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesTreeViewPanel.java @@ -52,7 +52,11 @@ import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiUtilBase; import com.intellij.ui.*; -import com.intellij.util.*; +import com.intellij.ui.treeStructure.actions.CollapseAllAction; +import com.intellij.util.ArrayUtil; +import com.intellij.util.EditSourceOnDoubleClickHandler; +import com.intellij.util.EditSourceOnEnterKeyHandler; +import com.intellij.util.IconUtil; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NotNull; @@ -68,6 +72,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +/** + * @author anna + * @author Konstantin Bulenkov + */ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { private final FavoritesTreeStructure myFavoritesTreeStructure; private FavoritesViewTreeBuilder myBuilder; @@ -167,6 +175,7 @@ public class FavoritesTreeViewPanel extends JPanel implements DataProvider { return CustomShortcutSet.fromString("DELETE"); } }) + .addExtraAction(AnActionButton.fromAction(new CollapseAllAction(myTree))) .setLineBorder(0, 0, 0, 0) .createPanel(); panel.setBorder(IdeBorderFactory.createEmptyBorder(0)); diff --git a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesViewSelectInTarget.java b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesViewSelectInTarget.java index aeae7191306c..ed52ffd3afee 100644 --- a/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesViewSelectInTarget.java +++ b/platform/lang-impl/src/com/intellij/ide/favoritesTreeView/FavoritesViewSelectInTarget.java @@ -16,19 +16,26 @@ package com.intellij.ide.favoritesTreeView; -import com.intellij.ide.SelectInContext; import com.intellij.ide.SelectInManager; import com.intellij.ide.StandardTargetWeights; -import com.intellij.ide.impl.ProjectViewSelectInTarget; +import com.intellij.ide.impl.SelectInTargetPsiWrapper; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFileSystemItem; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowId; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtilBase; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** - * User: anna - * Date: Feb 25, 2005 + * @author anna + * @author Konstantin Bulenkov */ -public class FavoritesViewSelectInTarget extends ProjectViewSelectInTarget { +public class FavoritesViewSelectInTarget extends SelectInTargetPsiWrapper { public FavoritesViewSelectInTarget(final Project project) { super(project); } @@ -37,8 +44,68 @@ public class FavoritesViewSelectInTarget extends ProjectViewSelectInTarget { return SelectInManager.FAVORITES; } + @Override + public String getToolWindowId() { + return SelectInManager.FAVORITES; + } + + @Override + protected void select(Object selector, VirtualFile virtualFile, boolean requestFocus) { + select(myProject, selector, null, null, virtualFile, requestFocus); + } + + @Override + protected void select(PsiElement element, boolean requestFocus) { + PsiElement toSelect = null; + if (element instanceof PsiFile || element instanceof PsiDirectory) { + toSelect = element; + } + else { + final PsiFile containingFile = element.getContainingFile(); + if (containingFile == null) return; + final FileViewProvider viewProvider = containingFile.getViewProvider(); + toSelect = viewProvider.getPsi(viewProvider.getBaseLanguage()); + } + if (toSelect == null) return; + PsiElement originalElement = toSelect.getOriginalElement(); + final VirtualFile virtualFile = PsiUtilBase.getVirtualFile(originalElement); + select(originalElement, virtualFile, requestFocus); + } + + public static ActionCallback select(@NotNull Project project, + final Object toSelect, + @Nullable final String viewId, + @Nullable final String subviewId, + final VirtualFile virtualFile, + final boolean requestFocus) { + final ActionCallback result = new ActionCallback(); + + ToolWindowManager windowManager=ToolWindowManager.getInstance(project); + final ToolWindow favoritesToolWindow = windowManager.getToolWindow(ToolWindowId.FAVORITES_VIEW); + + if (favoritesToolWindow != null) { + final FavoritesTreeViewPanel panel = UIUtil.findComponentOfType(favoritesToolWindow.getComponent(), FavoritesTreeViewPanel.class); + + if (panel != null) { + final Runnable runnable = new Runnable() { + public void run() { + panel.selectElement(toSelect, virtualFile, requestFocus); + result.setDone(); + } + }; + + if (requestFocus) { + favoritesToolWindow.activate(runnable, false); + } else { + favoritesToolWindow.show(runnable); + } + } + } + + return result; + } + protected boolean canSelect(final PsiFileSystemItem file) { - if (!super.canSelect(file)) return false; return findSuitableFavoritesList(file.getVirtualFile(), myProject, null) != null; } @@ -63,9 +130,4 @@ public class FavoritesViewSelectInTarget extends ProjectViewSelectInTarget { protected boolean canWorkWithCustomObjects() { return false; } - - public boolean isSubIdSelectable(String subId, SelectInContext context) { - final FavoritesManager favoritesManager = FavoritesManager.getInstance(myProject); - return favoritesManager.contains(subId, context.getVirtualFile()); - } } diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AbstractNavBarUI.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AbstractNavBarUI.java index d50007b562ec..6cd6f71d0f89 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AbstractNavBarUI.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AbstractNavBarUI.java @@ -181,7 +181,7 @@ public abstract class AbstractNavBarUI implements NavBarUI { } protected Color getBackgroundColor() { - return new Color(0, 0, 0, 35); + return UIUtil.getSlightlyDarkerColor(UIUtil.getPanelBackground()); } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AquaNavBarUI.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AquaNavBarUI.java index 3c4f3ba88b3d..b49ce25eebac 100644 --- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AquaNavBarUI.java +++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AquaNavBarUI.java @@ -16,6 +16,7 @@ package com.intellij.ide.navigationToolbar.ui; import com.intellij.ide.navigationToolbar.NavBarItem; +import com.intellij.util.ui.SameColor; import com.intellij.util.ui.UIUtil; import java.awt.*; @@ -41,6 +42,6 @@ public class AquaNavBarUI extends AbstractNavBarUI { @Override protected Color getBackgroundColor() { - return new Color(0, 0, 0, 35); + return UIUtil.getSlightlyDarkerColor(new SameColor(200)); } } diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java index bf3eca1e8b6d..3ce6ebc02c86 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -371,7 +371,10 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec }); if (ok[0]) { - ((InjectedLanguageManagerImpl)InjectedLanguageManager.getInstance(myProject)).startRunInjectors(document, synchronously); + // otherwise changes maybe not synced to the document yet, and injectors will crash + if (!mySynchronizer.isDocumentAffectedByTransactions(document)) { + ((InjectedLanguageManagerImpl)InjectedLanguageManager.getInstance(myProject)).startRunInjectors(document, synchronously); + } // run after commit actions outside write action runAfterCommitActions(document); if (DebugUtil.DO_EXPENSIVE_CHECKS) { diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java index 3148befc6895..ce040f54e6b1 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenamePsiElementProcessor.java @@ -21,6 +21,7 @@ import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Pass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileSystemItem; @@ -161,6 +162,18 @@ public abstract class RenamePsiElementProcessor { return element; } + /** + * Substitutes element to be renamed and initiate rename procedure. Should be used in order to prevent modal dialogs to appear during inplace rename + * @param element the element on which refactoring was invoked + * @param editor the editor in which inplace refactoring was invoked + * @param renameCallback rename procedure which should be called on the chosen substitution + */ + public void substituteElementToRename(@NotNull final PsiElement element, @NotNull Editor editor, @NotNull Pass renameCallback) { + final PsiElement psiElement = substituteElementToRename(element, editor); + if (psiElement == null) return; + renameCallback.pass(psiElement); + } + public void findCollisions(final PsiElement element, final String newName, final Map allRenames, final List result) { } diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/CompletionContributorForInplaceRename.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/CompletionContributorForInplaceRename.java new file mode 100644 index 000000000000..1a6069b582a9 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/CompletionContributorForInplaceRename.java @@ -0,0 +1,41 @@ +/* + * 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.refactoring.rename.inplace; + +import com.intellij.codeInsight.completion.CompletionContributor; +import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.openapi.editor.Editor; + +/** + * User: anna + * Date: 11/22/11 + */ +public class CompletionContributorForInplaceRename extends CompletionContributor { + + @Override + public void fillCompletionVariants(CompletionParameters parameters, CompletionResultSet result) { + final Editor editor = parameters.getLookup().getEditor(); + final TemplateState state = TemplateManagerImpl.getTemplateState(editor); + if (state != null) { + if (editor.getUserData(VariableInplaceRenamer.INPLACE_RENAMER) != null) { + result.stopHere(); + } + } + } +} diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenameHandler.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenameHandler.java index 923abea7ef0f..3000a9961214 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenameHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenameHandler.java @@ -18,12 +18,15 @@ package com.intellij.refactoring.rename.inplace; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.lang.LanguageRefactoringSupport; import com.intellij.lang.refactoring.RefactoringSupportProvider; +import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.Pass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.rename.RenamePsiElementProcessor; import org.jetbrains.annotations.NotNull; /** @@ -45,9 +48,20 @@ public class MemberInplaceRenameHandler extends VariableInplaceRenameHandler { } @Override - protected VariableInplaceRenamer createRenamer(@NotNull PsiElement elementToRename, Editor editor) { + public VariableInplaceRenamer doRename(@NotNull final PsiElement elementToRename, final Editor editor, final DataContext dataContext) { if (elementToRename instanceof PsiNameIdentifierOwner) { - return new MemberInplaceRenamer((PsiNameIdentifierOwner)elementToRename, editor); + RenamePsiElementProcessor.forElement(elementToRename).substituteElementToRename(elementToRename, editor, new Pass() { + @Override + public void pass(PsiElement element) { + final MemberInplaceRenamer renamer = new MemberInplaceRenamer((PsiNameIdentifierOwner)elementToRename, element, editor); + boolean startedRename = renamer.performInplaceRename(); + if (!startedRename) { + performDialogRename(elementToRename, editor, dataContext); + } + } + }); + } else { + performDialogRename(elementToRename, editor, dataContext); } return null; } diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java index 353b9b581bab..2e0f6b5f83e8 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/MemberInplaceRenamer.java @@ -25,6 +25,7 @@ import com.intellij.openapi.command.impl.FinishMarkAction; import com.intellij.openapi.command.impl.StartMarkAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; @@ -34,6 +35,7 @@ import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.rename.RenameProcessor; import com.intellij.refactoring.rename.RenamePsiElementProcessor; @@ -53,10 +55,15 @@ import java.util.List; */ public class MemberInplaceRenamer extends VariableInplaceRenamer { protected final String myOldName; + private final PsiElement mySubstituted; + private RangeMarker mySubstitutedRange; - public MemberInplaceRenamer(@NotNull PsiNameIdentifierOwner elementToRename, Editor editor) { + public MemberInplaceRenamer(@NotNull PsiNameIdentifierOwner elementToRename, PsiElement substituted, Editor editor) { super(elementToRename, editor); myOldName = elementToRename.getName(); + mySubstituted = substituted; + mySubstitutedRange = mySubstituted != null && mySubstituted != myElementToRename && mySubstituted.getTextRange() != null ? myEditor.getDocument().createRangeMarker(mySubstituted.getTextRange()) : null; + showDialogAdvertisement("RenameElement"); } @@ -99,8 +106,7 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { final ArrayList references = new ArrayList(super.collectRefs(referencesSearchScope)); final PsiNamedElement variable = getVariable(); if (variable != null) { - final RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(variable); - final PsiElement substituted = processor.substituteElementToRename(variable, myEditor); + final PsiElement substituted = getSubstituted(); if (substituted != null && substituted != variable) { references.addAll(ReferencesSearch.search(substituted, referencesSearchScope, false).findAll()); } @@ -126,11 +132,10 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { boolean showChooser = super.appendAdditionalElement(stringUsages); PsiNamedElement variable = getVariable(); if (variable != null) { - RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(variable); - final PsiElement substituted = processor.substituteElementToRename(variable, myEditor); + final PsiElement substituted = getSubstituted(); if (substituted != null) { appendAdditionalElement(stringUsages, variable, substituted); - processor = RenamePsiElementProcessor.forElement(substituted); + RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(substituted); final HashMap allRenames = new HashMap(); PsiFile currentFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument()); processor.prepareRenaming(substituted, "", allRenames, new LocalSearchScope(currentFile)); @@ -163,9 +168,8 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { final NamesValidator namesValidator = LanguageNamesValidation.INSTANCE.forLanguage(variable.getLanguage()); LOG.assertTrue(namesValidator != null); if (namesValidator.isIdentifier(newName, myProject)) { - RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(variable); - final PsiElement substitutedElement = processor.substituteElementToRename(variable, myEditor); - if (substitutedElement == null) { + final PsiElement substituted = getSubstituted(); + if (substituted == null) { return; } @@ -173,13 +177,14 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { .message("renaming.0.1.to.2", UsageViewUtil.getType(variable), UsageViewUtil.getDescriptiveName(variable), newName); CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { public void run() { - final RenamePsiElementProcessor elementProcessor = RenamePsiElementProcessor.forElement(substitutedElement); + + final RenamePsiElementProcessor elementProcessor = RenamePsiElementProcessor.forElement(substituted); final RenameProcessor - renameProcessor = new RenameProcessor(myProject, substitutedElement, newName, - elementProcessor.isToSearchInComments(substitutedElement), - elementProcessor.isToSearchForTextOccurrences(substitutedElement)); + renameProcessor = new RenameProcessor(myProject, substituted, newName, + elementProcessor.isToSearchInComments(substituted), + elementProcessor.isToSearchForTextOccurrences(substituted)); for (AutomaticRenamerFactory factory : Extensions.getExtensions(AutomaticRenamerFactory.EP_NAME)) { - if (factory.isApplicable(substitutedElement) && factory.getOptionName() != null) { + if (factory.isApplicable(substituted) && factory.getOptionName() != null) { if (factory.isEnabled()) { renameProcessor.addRenamerFactory(factory); } @@ -254,4 +259,16 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { if (ex[0] != null) throw ex[0]; return markAction[0]; } + + @Nullable + public PsiElement getSubstituted() { + if (mySubstituted != null && mySubstituted.isValid()) return mySubstituted; + if (mySubstitutedRange != null) { + final PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument()); + if (psiFile != null) { + return PsiTreeUtil.getParentOfType(psiFile.findElementAt(mySubstitutedRange.getStartOffset()), PsiNameIdentifierOwner.class); + } + } + return getVariable(); + } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java index a72a435b9452..cfc21482fab4 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenameHandler.java @@ -112,23 +112,26 @@ public class VariableInplaceRenameHandler implements RenameHandler { boolean startedRename = renamer == null ? false : renamer.performInplaceRename(); if (!startedRename) { - try { - ourPreventInlineRenameFlag.set(Boolean.TRUE); - - RenameHandler handler = RenameHandlerRegistry.getInstance().getRenameHandler(dataContext); - assert handler != null; - handler.invoke( - elementToRename.getProject(), - editor, - elementToRename.getContainingFile(), dataContext - ); - } finally { - ourPreventInlineRenameFlag.set(null); - } + performDialogRename(elementToRename, editor, dataContext); } return renamer; } + protected static void performDialogRename(PsiElement elementToRename, Editor editor, DataContext dataContext) { + try { + ourPreventInlineRenameFlag.set(Boolean.TRUE); + RenameHandler handler = RenameHandlerRegistry.getInstance().getRenameHandler(dataContext); + assert handler != null; + handler.invoke( + elementToRename.getProject(), + editor, + elementToRename.getContainingFile(), dataContext + ); + } finally { + ourPreventInlineRenameFlag.set(null); + } + } + @Nullable protected VariableInplaceRenamer createRenamer(@NotNull PsiElement elementToRename, Editor editor) { return new VariableInplaceRenamer((PsiNameIdentifierOwner)elementToRename, editor); diff --git a/platform/platform-api/src/com/intellij/ui/AnActionButton.java b/platform/platform-api/src/com/intellij/ui/AnActionButton.java index 98789eda843f..7ecf3b2af477 100644 --- a/platform/platform-api/src/com/intellij/ui/AnActionButton.java +++ b/platform/platform-api/src/com/intellij/ui/AnActionButton.java @@ -30,6 +30,7 @@ public abstract class AnActionButton extends AnAction implements ShortcutProvide private boolean myEnabled = true; private boolean myVisible = true; private ShortcutSet myShortcut; + private AnAction myAction = null; private JComponent myContextComponent; public AnActionButton(String text) { @@ -47,6 +48,29 @@ public abstract class AnActionButton extends AnAction implements ShortcutProvide public AnActionButton() { } + + public static AnActionButton fromAction(final AnAction action) { + final Presentation presentation = action.getTemplatePresentation(); + return new AnActionButton(presentation.getText(), + presentation.getDescription(), + presentation.getIcon()) { + + @Override + public void actionPerformed(AnActionEvent e) { + action.actionPerformed(e); + } + + @Override + public void updateButton(AnActionEvent e) { + action.update(e); + final boolean enabled = e.getPresentation().isEnabled(); + final boolean visible = e.getPresentation().isVisible(); + if (enabled && visible) { + super.updateButton(e); + } + } + }; + } public boolean isEnabled() { return myEnabled; @@ -66,9 +90,17 @@ public abstract class AnActionButton extends AnAction implements ShortcutProvide @Override public final void update(AnActionEvent e) { - final boolean enabled = isEnabled() && isContextComponentOk(); + boolean myActionVisible = true; + boolean myActionEnabled = true; + if (myAction != null) { + myAction.update(e); + myActionEnabled = myAction.getTemplatePresentation().isEnabled(); + myActionVisible = myAction.getTemplatePresentation().isVisible(); + } + final boolean enabled = isEnabled() && isContextComponentOk() && myActionEnabled; e.getPresentation().setEnabled(enabled); - e.getPresentation().setVisible(isVisible()); + e.getPresentation().setVisible(isVisible() && myActionVisible); + if (enabled) { updateButton(e); } diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java index ae6086c25ba6..6d958b1affe1 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java @@ -16,6 +16,7 @@ package com.intellij.ui.tabs.impl; import com.intellij.ide.DataManager; +import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.DefaultActionGroup; @@ -103,6 +104,18 @@ public class TabLabel extends JPanel { }); } + @Override + public Insets getInsets() { + Insets insets = super.getInsets(); + if (myTabs.isEditorTabs()) { + if (UISettings.getInstance().SHOW_CLOSE_BUTTON) { + return new Insets(insets.top, insets.left, insets.bottom, 3); + } + } + + return insets; + } + public void setAligmentToCenter(boolean toCenter) { if (myCentered == toCenter && myLabel.getParent() != null) return; diff --git a/platform/platform-impl/src/com/intellij/injected/editor/MarkupModelWindow.java b/platform/platform-impl/src/com/intellij/injected/editor/MarkupModelWindow.java index 979e176c9861..1f7bed30b5f6 100644 --- a/platform/platform-impl/src/com/intellij/injected/editor/MarkupModelWindow.java +++ b/platform/platform-impl/src/com/intellij/injected/editor/MarkupModelWindow.java @@ -18,6 +18,7 @@ package com.intellij.injected.editor; import com.intellij.openapi.Disposable; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.ex.DisposableIterator; import com.intellij.openapi.editor.ex.MarkupModelEx; import com.intellij.openapi.editor.ex.RangeHighlighterEx; import com.intellij.openapi.editor.ex.SweepProcessor; @@ -25,15 +26,13 @@ import com.intellij.openapi.editor.impl.event.MarkupModelListener; import com.intellij.openapi.editor.markup.HighlighterTargetArea; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.util.ProperTextRange; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.UserDataHolderBase; -import com.intellij.openapi.util.ProperTextRange; import com.intellij.util.Consumer; import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; -import java.util.Iterator; - /** * @author cdr */ @@ -146,7 +145,7 @@ public class MarkupModelWindow extends UserDataHolderBase implements MarkupModel @NotNull @Override - public Iterator overlappingIterator(int startOffset, int endOffset) { + public DisposableIterator overlappingIterator(int startOffset, int endOffset) { // todo convert return myHostModel.overlappingIterator(startOffset, endOffset); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/MarkupModelEx.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/MarkupModelEx.java index e2edfecd7f4b..6dad403e5f4b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/MarkupModelEx.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/MarkupModelEx.java @@ -26,8 +26,6 @@ import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Iterator; - /** * @author max */ @@ -46,7 +44,7 @@ public interface MarkupModelEx extends MarkupModel { boolean processRangeHighlightersOutside(int start, int end, @NotNull Processor processor); @NotNull - Iterator overlappingIterator(int startOffset, int endOffset); + DisposableIterator overlappingIterator(int startOffset, int endOffset); // optimization: creates highlighter and fires only one event: highlighterCreated RangeHighlighterEx addRangeHighlighterAndChangeAttributes(int startOffset, diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java index 28d09326c4e2..f0b4720bf534 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/ex/util/EditorUtil.java @@ -320,26 +320,32 @@ public class EditorUtil { EditorEx editorImpl = (EditorEx)editor; int offset = start; IterationState state = new IterationState(editorImpl, start, end, false); - int fontType = state.getMergedAttributes().getFontType(); - int column = currentColumn[0]; - int spaceSize = getSpaceWidth(fontType, editorImpl); - for (; column < columnNumber && offset < end; offset++) { - if (offset >= state.getEndOffset()) { - state.advance(); - fontType = state.getMergedAttributes().getFontType(); - } + int column; + try { + int fontType = state.getMergedAttributes().getFontType(); + column = currentColumn[0]; + int spaceSize = getSpaceWidth(fontType, editorImpl); + for (; column < columnNumber && offset < end; offset++) { + if (offset >= state.getEndOffset()) { + state.advance(); + fontType = state.getMergedAttributes().getFontType(); + } - char c = text.charAt(offset); - if (c == '\t') { - int prevX = x; - x = nextTabStop(x, editorImpl); - column += columnsNumber(x - prevX, spaceSize); - } - else { - x += charWidth(c, fontType, editorImpl); - column++; + char c = text.charAt(offset); + if (c == '\t') { + int prevX = x; + x = nextTabStop(x, editorImpl); + column += columnsNumber(x - prevX, spaceSize); + } + else { + x += charWidth(c, fontType, editorImpl); + column++; + } } } + finally { + state.dispose(); + } if (column == columnNumber) { return offset; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 86d0467759a2..983810f02c62 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -399,64 +399,69 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse int docLength = document.getTextLength(); int patchedStartOffset = startOffset < docLength ? document.getLineStartOffset(document.getLineNumber(startOffset)) : docLength; int patchedEndOffset = endOffset <= docLength ? document.getLineEndOffset(document.getLineNumber(endOffset)) + 1 : docLength; - Iterator docHighlighters = docMarkup.overlappingIterator(patchedStartOffset, patchedEndOffset); + DisposableIterator docHighlighters = docMarkup.overlappingIterator(patchedStartOffset, patchedEndOffset); final MarkupModelEx editorMarkup = (MarkupModelEx)myEditor.getMarkupModel(); - Iterator editorHighlighters = editorMarkup.overlappingIterator(startOffset, endOffset); + DisposableIterator editorHighlighters = editorMarkup.overlappingIterator(startOffset, endOffset); - RangeHighlighterEx lastDocHighlighter = null; - RangeHighlighterEx lastEditorHighlighter = null; + try { + RangeHighlighterEx lastDocHighlighter = null; + RangeHighlighterEx lastEditorHighlighter = null; + while (true) { + if (lastDocHighlighter == null && docHighlighters.hasNext()) { + lastDocHighlighter = docHighlighters.next(); + if (!lastDocHighlighter.isValid() || lastDocHighlighter.getAffectedAreaStartOffset() > endOffset) { + lastDocHighlighter = null; + continue; + } + if (lastDocHighlighter.getAffectedAreaEndOffset() < startOffset) { + lastDocHighlighter = null; + continue; + } + } - while (true) { - if (lastDocHighlighter == null && docHighlighters.hasNext()) { - lastDocHighlighter = docHighlighters.next(); - if (!lastDocHighlighter.isValid() || lastDocHighlighter.getAffectedAreaStartOffset() > endOffset) { + if (lastEditorHighlighter == null && editorHighlighters.hasNext()) { + lastEditorHighlighter = editorHighlighters.next(); + if (!lastEditorHighlighter.isValid() || lastEditorHighlighter.getAffectedAreaStartOffset() > endOffset) { + lastEditorHighlighter = null; + continue; + } + if (lastEditorHighlighter.getAffectedAreaEndOffset() < startOffset) { + lastEditorHighlighter = null; + continue; + } + } + + if (lastDocHighlighter == null && lastEditorHighlighter == null) return; + + final RangeHighlighterEx lowerHighlighter; + + if (less(lastDocHighlighter, lastEditorHighlighter)) { + lowerHighlighter = lastDocHighlighter; lastDocHighlighter = null; - continue; } - if (lastDocHighlighter.getAffectedAreaEndOffset() < startOffset) { - lastDocHighlighter = null; - continue; - } - } - - if (lastEditorHighlighter == null && editorHighlighters.hasNext()) { - lastEditorHighlighter = editorHighlighters.next(); - if (!lastEditorHighlighter.isValid() || lastEditorHighlighter.getAffectedAreaStartOffset() > endOffset) { + else { + lowerHighlighter = lastEditorHighlighter; lastEditorHighlighter = null; - continue; } - if (lastEditorHighlighter.getAffectedAreaEndOffset() < startOffset) { - lastEditorHighlighter = null; - continue; + + assert lowerHighlighter != null; + if (!lowerHighlighter.isValid()) continue; + + int startLineIndex = lowerHighlighter.getDocument().getLineNumber(startOffset); + if (startLineIndex < 0 || startLineIndex >= document.getLineCount()) continue; + + int endLineIndex = lowerHighlighter.getDocument().getLineNumber(endOffset); + if (endLineIndex < 0 || endLineIndex >= document.getLineCount()) continue; + + if (lowerHighlighter.getEditorFilter().avaliableIn(myEditor)) { + processor.process(lowerHighlighter); } } - - if (lastDocHighlighter == null && lastEditorHighlighter == null) return; - - final RangeHighlighterEx lowerHighlighter; - - if (less(lastDocHighlighter, lastEditorHighlighter)) { - lowerHighlighter = lastDocHighlighter; - lastDocHighlighter = null; - } - else { - lowerHighlighter = lastEditorHighlighter; - lastEditorHighlighter = null; - } - - assert lowerHighlighter != null; - if (!lowerHighlighter.isValid()) continue; - - int startLineIndex = lowerHighlighter.getDocument().getLineNumber(startOffset); - if (startLineIndex < 0 || startLineIndex >= document.getLineCount()) continue; - - int endLineIndex = lowerHighlighter.getDocument().getLineNumber(endOffset); - if (endLineIndex < 0 || endLineIndex >= document.getLineCount()) continue; - - if (lowerHighlighter.getEditorFilter().avaliableIn(myEditor)) { - processor.process(lowerHighlighter); - } + } + finally { + docHighlighters.dispose(); + editorHighlighters.dispose(); } } @@ -968,7 +973,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse @Override public boolean isAnnotationsShown() { - return myTextAnnotationGutters.size() > 0; + return !myTextAnnotationGutters.isEmpty(); } @Override @@ -1122,7 +1127,7 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } } - if (toolTip != null && toolTip.length() != 0) { + if (toolTip != null && !toolTip.isEmpty()) { final Ref t = new Ref(e.getPoint()); int line = myEditor.yPositionToLogicalLine(e.getY()); ArrayList row = myLineToGutterRenderers.get(line); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 9943ff2fd45e..28f0d87f11a8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -985,10 +985,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi // We mark that we're under such circumstances then. boolean activeSoftWrapProcessed = logicalPosition.softWrapLinesOnCurrentLogicalLine <= 0; - int column = 0; - int prevX = 0; CharSequence text = myDocument.getCharsNoThreadCheck(); - char c = ' '; LogicalPosition endLogicalPosition = visualToLogicalPosition(new VisualPosition(line+1, 0)); int endOffset = logicalPositionToOffset(endLogicalPosition); @@ -1004,125 +1001,133 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } IterationState state = new IterationState(this, offset, endOffset, false); - int fontType = state.getMergedAttributes().getFontType(); - int spaceSize = EditorUtil.getSpaceWidth(fontType, this); + try { + int fontType = state.getMergedAttributes().getFontType(); + int spaceSize = EditorUtil.getSpaceWidth(fontType, this); - int x = 0; - int charWidth; - boolean onSoftWrapDrawing = false; - outer: - while (true) { - charWidth = -1; - if (offset >= textLength) { - break; - } + int x = 0; + int charWidth; + boolean onSoftWrapDrawing = false; + char c = ' '; + int prevX = 0; + int column = 0; + outer: + while (true) { + charWidth = -1; + if (offset >= textLength) { + break; + } - if (offset >= state.getEndOffset()) { - state.advance(); - fontType = state.getMergedAttributes().getFontType(); - } + if (offset >= state.getEndOffset()) { + state.advance(); + fontType = state.getMergedAttributes().getFontType(); + } - SoftWrap softWrap = mySoftWrapModel.getSoftWrap(offset); - if (softWrap != null) { - if (activeSoftWrapProcessed) { - prevX = x; - charWidth = getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED); - x += charWidth; - if (x >= px) { - onSoftWrapDrawing = true; + SoftWrap softWrap = mySoftWrapModel.getSoftWrap(offset); + if (softWrap != null) { + if (activeSoftWrapProcessed) { + prevX = x; + charWidth = getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED); + x += charWidth; + if (x >= px) { + onSoftWrapDrawing = true; + } + else { + column++; + } + break outer; } else { - column++; - } - break outer; - } - else { - CharSequence softWrapText = softWrap.getText(); - for (int i = 1/*Assuming line feed is located at the first position*/; i < softWrapText.length(); i++) { - c = softWrapText.charAt(i); + CharSequence softWrapText = softWrap.getText(); + for (int i = 1/*Assuming line feed is located at the first position*/; i < softWrapText.length(); i++) { + c = softWrapText.charAt(i); + prevX = x; + charWidth = charToVisibleWidth(c, fontType, x); + x += charWidth; + if (x >= px) { + break outer; + } + column += EditorUtil.columnsNumber(c, x, prevX, spaceSize); + } + + // Process 'after soft wrap' sign. prevX = x; - charWidth = charToVisibleWidth(c, fontType, x); + charWidth = mySoftWrapModel.getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP); x += charWidth; + if (x >= px) { + onSoftWrapDrawing = true; + break outer; + } + column++; + activeSoftWrapProcessed = true; + } + } + FoldRegion region = state.getCurrentFold(); + if (region != null) { + char[] placeholder = region.getPlaceholderText().toCharArray(); + for (char aPlaceholder : placeholder) { + c = aPlaceholder; + x += EditorUtil.charWidth(c, fontType, this); if (x >= px) { break outer; } - column += EditorUtil.columnsNumber(c, x, prevX, spaceSize); + column++; } - - // Process 'after soft wrap' sign. + offset = region.getEndOffset(); + } + else { prevX = x; - charWidth = mySoftWrapModel.getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP); + c = text.charAt(offset); + charWidth = charToVisibleWidth(c, fontType, x); + if (charWidth == 0) { + break; + } x += charWidth; + if (x >= px) { - onSoftWrapDrawing = true; - break outer; + break; } - column++; - activeSoftWrapProcessed = true; + column += EditorUtil.columnsNumber(c, x, prevX, spaceSize); + + offset++; } } - FoldRegion region = state.getCurrentFold(); - if (region != null) { - char[] placeholder = region.getPlaceholderText().toCharArray(); - for (char aPlaceholder : placeholder) { - c = aPlaceholder; - x += EditorUtil.charWidth(c, fontType, this); - if (x >= px) { - break outer; - } - column++; + + if (charWidth < 0) { + charWidth = EditorUtil.charWidth(c, fontType, this); + } + + if (charWidth < 0) { + charWidth = spaceSize; + } + + if (x >= px && c == '\t' && !onSoftWrapDrawing) { + if (mySettings.isCaretInsideTabs()) { + column += (px - prevX) / spaceSize; + if ((px - prevX) % spaceSize > spaceSize / 2) column++; + } + else if ((x - px) * 2 < x - prevX) { + column += EditorUtil.columnsNumber(c, x, prevX, spaceSize); } - offset = region.getEndOffset(); } else { - prevX = x; - c = text.charAt(offset); - charWidth = charToVisibleWidth(c, fontType, x); - if (charWidth == 0) { - break; - } - x += charWidth; - if (x >= px) { - break; + if ((x - px) * 2 < charWidth) column++; } - column += EditorUtil.columnsNumber(c, x, prevX, spaceSize); - - offset++; - } - } - - if (charWidth < 0) { - charWidth = EditorUtil.charWidth(c, fontType, this); - } - - if (charWidth < 0) { - charWidth = spaceSize; - } - - if (x >= px && c == '\t' && !onSoftWrapDrawing) { - if (mySettings.isCaretInsideTabs()) { - column += (px - prevX) / spaceSize; - if ((px - prevX) % spaceSize > spaceSize / 2) column++; - } - else if ((x - px) * 2 < x - prevX) { - column += EditorUtil.columnsNumber(c, x, prevX, spaceSize); - } - } - else { - if (x >= px) { - if ((x - px) * 2 < charWidth) column++; - } - else { - int diff = px - x; - column += diff / spaceSize; - if (diff % spaceSize * 2 >= spaceSize) { - column++; + else { + int diff = px - x; + column += diff / spaceSize; + if (diff % spaceSize * 2 >= spaceSize) { + column++; + } } } - } - return new VisualPosition(line, column); + return new VisualPosition(line, column); + } + finally { + state.dispose(); + } } /** @@ -1299,68 +1304,73 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi CharSequence text = myDocument.getCharsNoThreadCheck(); int textLength = myDocument.getTextLength(); IterationState state = new IterationState(this, startOffset, startOffset + length, false); - int fontType = state.getMergedAttributes().getFontType(); - int spaceSize = EditorUtil.getSpaceWidth(fontType, this); + try { + int fontType = state.getMergedAttributes().getFontType(); + int spaceSize = EditorUtil.getSpaceWidth(fontType, this); - int column = 0; - outer: - while (column < length) { - if (offset >= textLength) break; + int column = 0; + outer: + while (column < length) { + if (offset >= textLength) break; - if (offset >= state.getEndOffset()) { - state.advance(); - fontType = state.getMergedAttributes().getFontType(); - } - // We need to consider 'before soft wrap drawing'. - SoftWrap softWrap = getSoftWrapModel().getSoftWrap(offset); - if (softWrap != null && offset > startOffset) { - column++; - x += getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED); - // Assuming that first soft wrap symbol is line feed or all soft wrap symbols before the first line feed are spaces. - break; - } - - FoldRegion region = state.getCurrentFold(); - - if (region != null) { - char[] placeholder = region.getPlaceholderText().toCharArray(); - for (char aPlaceholder : placeholder) { - x += EditorUtil.charWidth(aPlaceholder, fontType, this); - column++; - if (column >= length) break outer; + if (offset >= state.getEndOffset()) { + state.advance(); + fontType = state.getMergedAttributes().getFontType(); } - offset = region.getEndOffset(); - } - else { - char c = text.charAt(offset); - if (c == '\n') { + // We need to consider 'before soft wrap drawing'. + SoftWrap softWrap = getSoftWrapModel().getSoftWrap(offset); + if (softWrap != null && offset > startOffset) { + column++; + x += getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED); + // Assuming that first soft wrap symbol is line feed or all soft wrap symbols before the first line feed are spaces. break; } - if (c == '\t') { - int prevX = x; - x = EditorUtil.nextTabStop(x, this); - int columnDiff = (x - prevX) / spaceSize; - if ((x - prevX) % spaceSize > 0) { - // There is a possible case that tabulation symbol takes more than one visual column to represent and it's shown at - // soft-wrapped line. Soft wrap sign width may be not divisible by space size, hence, part of tabulation symbol represented - // as a separate visual column may take less space than space width. - columnDiff++; + + FoldRegion region = state.getCurrentFold(); + + if (region != null) { + char[] placeholder = region.getPlaceholderText().toCharArray(); + for (char aPlaceholder : placeholder) { + x += EditorUtil.charWidth(aPlaceholder, fontType, this); + column++; + if (column >= length) break outer; } - column += columnDiff; + offset = region.getEndOffset(); } else { - x += EditorUtil.charWidth(c, fontType, this); - column++; + char c = text.charAt(offset); + if (c == '\n') { + break; + } + if (c == '\t') { + int prevX = x; + x = EditorUtil.nextTabStop(x, this); + int columnDiff = (x - prevX) / spaceSize; + if ((x - prevX) % spaceSize > 0) { + // There is a possible case that tabulation symbol takes more than one visual column to represent and it's shown at + // soft-wrapped line. Soft wrap sign width may be not divisible by space size, hence, part of tabulation symbol represented + // as a separate visual column may take less space than space width. + columnDiff++; + } + column += columnDiff; + } + else { + x += EditorUtil.charWidth(c, fontType, this); + column++; + } + offset++; } - offset++; } - } - if (column != length) { - x += EditorUtil.getSpaceWidth(fontType, this) * (length - column); - } + if (column != length) { + x += EditorUtil.getSpaceWidth(fontType, this) * (length - column); + } - return x; + return x; + } + finally { + state.dispose(); + } } public int visibleLineToY(int line) { @@ -1910,7 +1920,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi int start = clipStartOffset; int end = clipEndOffset; getSoftWrapModel().registerSoftWrapsIfNecessary(); - IterationState iterationState = new IterationState(this, start, end, isPaintSelection()); LineIterator lIterator = createLineIterator(); lIterator.start(start); @@ -1918,112 +1927,118 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi return; } - TextAttributes attributes = iterationState.getMergedAttributes(); - Color backColor = getBackgroundColor(attributes); - int fontType = attributes.getFontType(); - CharSequence text = myDocument.getCharsNoThreadCheck(); - int lastLineIndex = Math.max(0, myDocument.getLineCount() - 1); + IterationState iterationState = new IterationState(this, start, end, isPaintSelection()); + try { + TextAttributes attributes = iterationState.getMergedAttributes(); + Color backColor = getBackgroundColor(attributes); + int fontType = attributes.getFontType(); + CharSequence text = myDocument.getCharsNoThreadCheck(); + int lastLineIndex = Math.max(0, myDocument.getLineCount() - 1); - // There is a possible case that we need to draw background from the start of soft wrap-introduced visual line. Given position - // has valid 'y' coordinate then at it shouldn't be affected by soft wrap that corresponds to the visual line start offset. - // Hence, we store information about soft wrap to be skipped for further processing and adjust 'x' coordinate value if necessary. - TIntHashSet softWrapsToSkip = new TIntHashSet(); - SoftWrap softWrap = getSoftWrapModel().getSoftWrap(start); - if (softWrap != null) { - softWrapsToSkip.add(softWrap.getStart()); - Color color = null; - if (backColor != null && !backColor.equals(defaultBackground)) { - color = backColor; - } - - // There is a possible case that target clip points to soft wrap-introduced visual line and that it's an active - // line (caret cursor is located on it). We want to draw corresponding 'caret line' background for soft wraps-introduced - // virtual space then. - if (color == null && position.y == getCaretModel().getVisualPosition().line * getLineHeight()) { - color = getColorsScheme().getColor(EditorColors.CARET_ROW_COLOR); - } - - if (color != null) { - drawBackground(g, color, softWrap.getIndentInPixels(), position, defaultBackground, clip); - } - position.x = softWrap.getIndentInPixels(); - } - - // There is a possible case that caret is located at soft-wrapped line. We don't need to paint caret row background - // on a last visual line of that soft-wrapped line then. Below is a holder for the flag that indicates if caret row - // background is already drawn. - boolean[] caretRowPainted = new boolean[1]; - - while (!iterationState.atEnd() && !lIterator.atEnd()) { - int hEnd = iterationState.getEndOffset(); - int lEnd = lIterator.getEnd(); - - if (hEnd >= lEnd) { - FoldRegion collapsedFolderAt = myFoldingModel.getCollapsedRegionAtOffset(start); - if (collapsedFolderAt == null) { - position.x = drawSoftWrapAwareBackground(g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType, - defaultBackground, clip, softWrapsToSkip, caretRowPainted); - - if (lIterator.getLineNumber() < lastLineIndex) { - if (backColor != null && !backColor.equals(defaultBackground)) { - g.setColor(backColor); - g.fillRect(position.x, position.y, clip.x + clip.width - position.x, lineHeight); - } - } - else { - paintAfterFileEndBackground(iterationState, - g, - position, clip, - lineHeight, defaultBackground, caretRowPainted); - break; - } - - position.x = 0; - if (position.y > clip.y + clip.height) break; - position.y += lineHeight; - start = lEnd; + // There is a possible case that we need to draw background from the start of soft wrap-introduced visual line. Given position + // has valid 'y' coordinate then at it shouldn't be affected by soft wrap that corresponds to the visual line start offset. + // Hence, we store information about soft wrap to be skipped for further processing and adjust 'x' coordinate value if necessary. + TIntHashSet softWrapsToSkip = new TIntHashSet(); + SoftWrap softWrap = getSoftWrapModel().getSoftWrap(start); + if (softWrap != null) { + softWrapsToSkip.add(softWrap.getStart()); + Color color = null; + if (backColor != null && !backColor.equals(defaultBackground)) { + color = backColor; } - lIterator.advance(); + // There is a possible case that target clip points to soft wrap-introduced visual line and that it's an active + // line (caret cursor is located on it). We want to draw corresponding 'caret line' background for soft wraps-introduced + // virtual space then. + if (color == null && position.y == getCaretModel().getVisualPosition().line * getLineHeight()) { + color = getColorsScheme().getColor(EditorColors.CARET_ROW_COLOR); + } + + if (color != null) { + drawBackground(g, color, softWrap.getIndentInPixels(), position, defaultBackground, clip); + } + position.x = softWrap.getIndentInPixels(); } - else { - FoldRegion collapsedFolderAt = iterationState.getCurrentFold(); - if (collapsedFolderAt != null) { - softWrap = mySoftWrapModel.getSoftWrap(collapsedFolderAt.getStartOffset()); - if (softWrap != null) { - position.x = drawSoftWrapAwareBackground( - g, backColor, text, collapsedFolderAt.getStartOffset(), collapsedFolderAt.getStartOffset(), position, fontType, - defaultBackground, clip, softWrapsToSkip, caretRowPainted - ); + + // There is a possible case that caret is located at soft-wrapped line. We don't need to paint caret row background + // on a last visual line of that soft-wrapped line then. Below is a holder for the flag that indicates if caret row + // background is already drawn. + boolean[] caretRowPainted = new boolean[1]; + + while (!iterationState.atEnd() && !lIterator.atEnd()) { + int hEnd = iterationState.getEndOffset(); + int lEnd = lIterator.getEnd(); + + if (hEnd >= lEnd) { + FoldRegion collapsedFolderAt = myFoldingModel.getCollapsedRegionAtOffset(start); + if (collapsedFolderAt == null) { + position.x = drawSoftWrapAwareBackground(g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType, + defaultBackground, clip, softWrapsToSkip, caretRowPainted); + + if (lIterator.getLineNumber() < lastLineIndex) { + if (backColor != null && !backColor.equals(defaultBackground)) { + g.setColor(backColor); + g.fillRect(position.x, position.y, clip.x + clip.width - position.x, lineHeight); + } + } + else { + paintAfterFileEndBackground(iterationState, + g, + position, clip, + lineHeight, defaultBackground, caretRowPainted); + break; + } + + position.x = 0; + if (position.y > clip.y + clip.height) break; + position.y += lineHeight; + start = lEnd; } - position.x = drawBackground(g, backColor, collapsedFolderAt.getPlaceholderText(), position, fontType, defaultBackground, clip); + + lIterator.advance(); } else { - if (hEnd > lEnd - lIterator.getSeparatorLength()) { - position.x = drawSoftWrapAwareBackground( - g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType, - defaultBackground, clip, softWrapsToSkip, caretRowPainted - ); + FoldRegion collapsedFolderAt = iterationState.getCurrentFold(); + if (collapsedFolderAt != null) { + softWrap = mySoftWrapModel.getSoftWrap(collapsedFolderAt.getStartOffset()); + if (softWrap != null) { + position.x = drawSoftWrapAwareBackground( + g, backColor, text, collapsedFolderAt.getStartOffset(), collapsedFolderAt.getStartOffset(), position, fontType, + defaultBackground, clip, softWrapsToSkip, caretRowPainted + ); + } + position.x = drawBackground(g, backColor, collapsedFolderAt.getPlaceholderText(), position, fontType, defaultBackground, clip); } else { - position.x = drawSoftWrapAwareBackground( - g, backColor, text, start, hEnd, position, fontType, defaultBackground, clip, softWrapsToSkip, caretRowPainted - ); + if (hEnd > lEnd - lIterator.getSeparatorLength()) { + position.x = drawSoftWrapAwareBackground( + g, backColor, text, start, lEnd - lIterator.getSeparatorLength(), position, fontType, + defaultBackground, clip, softWrapsToSkip, caretRowPainted + ); + } + else { + position.x = drawSoftWrapAwareBackground( + g, backColor, text, start, hEnd, position, fontType, defaultBackground, clip, softWrapsToSkip, caretRowPainted + ); + } } - } - iterationState.advance(); - attributes = iterationState.getMergedAttributes(); - backColor = getBackgroundColor(attributes); - fontType = attributes.getFontType(); - start = iterationState.getStartOffset(); + iterationState.advance(); + attributes = iterationState.getMergedAttributes(); + backColor = getBackgroundColor(attributes); + fontType = attributes.getFontType(); + start = iterationState.getStartOffset(); + } + } + + flushBackground(g, clip); + + if (lIterator.getLineNumber() >= lastLineIndex && position.y <= clip.y + clip.height) { + paintAfterFileEndBackground(iterationState, g, position, clip, lineHeight, defaultBackground, caretRowPainted); } } - - flushBackground(g, clip); - - if (lIterator.getLineNumber() >= lastLineIndex && position.y <= clip.y + clip.height) { - paintAfterFileEndBackground(iterationState, g, position, clip, lineHeight, defaultBackground, caretRowPainted); + finally { + iterationState.dispose(); } // Perform additional activity if soft wrap is added or removed during repainting. @@ -2356,92 +2371,97 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi return; } - IterationState iterationState = new IterationState(this, start, clipEndOffset, isPaintSelection()); LineIterator lIterator = createLineIterator(); lIterator.start(start); if (lIterator.atEnd()) { return; } - TextAttributes attributes = iterationState.getMergedAttributes(); - Color currentColor = attributes.getForegroundColor(); - if (currentColor == null) { - currentColor = getForegroundColor(); - } - Color effectColor = attributes.getEffectColor(); - EffectType effectType = attributes.getEffectType(); - int fontType = attributes.getFontType(); - g.setColor(currentColor); - - final char[] chars = myDocument.getRawChars(); - - while (!iterationState.atEnd() && !lIterator.atEnd()) { - int hEnd = iterationState.getEndOffset(); - int lEnd = lIterator.getEnd(); - if (hEnd >= lEnd) { - FoldRegion collapsedFolderAt = myFoldingModel.getCollapsedRegionAtOffset(start); - if (collapsedFolderAt == null) { - drawStringWithSoftWraps(g, chars, start, lEnd - lIterator.getSeparatorLength(), position, clip, effectColor, - effectType, fontType, currentColor, logicalPosition); - position.x = 0; - if (position.y > clip.y + clip.height) { - break; - } - position.y += lineHeight; - start = lEnd; - } - -// myBorderEffect.eolReached(g, this); - lIterator.advance(); + IterationState iterationState = new IterationState(this, start, clipEndOffset, isPaintSelection()); + try { + TextAttributes attributes = iterationState.getMergedAttributes(); + Color currentColor = attributes.getForegroundColor(); + if (currentColor == null) { + currentColor = getForegroundColor(); } - else { - FoldRegion collapsedFolderAt = iterationState.getCurrentFold(); - if (collapsedFolderAt != null) { - SoftWrap softWrap = mySoftWrapModel.getSoftWrap(collapsedFolderAt.getStartOffset()); - if (softWrap != null) { - position.x = drawStringWithSoftWraps( - g, chars, collapsedFolderAt.getStartOffset(), collapsedFolderAt.getStartOffset(), position, clip, effectColor, effectType, - fontType, currentColor, logicalPosition - ); - } - int foldingXStart = position.x; - position.x = drawString( - g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType, fontType, currentColor - ); - //drawStringWithSoftWraps(g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType, - // fontType, currentColor, logicalPosition); - BorderEffect.paintFoldedEffect(g, foldingXStart, position.y, position.x, getLineHeight(), effectColor, effectType); + Color effectColor = attributes.getEffectColor(); + EffectType effectType = attributes.getEffectType(); + int fontType = attributes.getFontType(); + g.setColor(currentColor); + final char[] chars = myDocument.getRawChars(); + + while (!iterationState.atEnd() && !lIterator.atEnd()) { + int hEnd = iterationState.getEndOffset(); + int lEnd = lIterator.getEnd(); + if (hEnd >= lEnd) { + FoldRegion collapsedFolderAt = myFoldingModel.getCollapsedRegionAtOffset(start); + if (collapsedFolderAt == null) { + drawStringWithSoftWraps(g, chars, start, lEnd - lIterator.getSeparatorLength(), position, clip, effectColor, + effectType, fontType, currentColor, logicalPosition); + position.x = 0; + if (position.y > clip.y + clip.height) { + break; + } + position.y += lineHeight; + start = lEnd; + } + + // myBorderEffect.eolReached(g, this); + lIterator.advance(); } else { - position.x = drawStringWithSoftWraps(g, chars, start, Math.min(hEnd, lEnd - lIterator.getSeparatorLength()) , position, clip, - effectColor, effectType, fontType, currentColor, logicalPosition); + FoldRegion collapsedFolderAt = iterationState.getCurrentFold(); + if (collapsedFolderAt != null) { + SoftWrap softWrap = mySoftWrapModel.getSoftWrap(collapsedFolderAt.getStartOffset()); + if (softWrap != null) { + position.x = drawStringWithSoftWraps( + g, chars, collapsedFolderAt.getStartOffset(), collapsedFolderAt.getStartOffset(), position, clip, effectColor, effectType, + fontType, currentColor, logicalPosition + ); + } + int foldingXStart = position.x; + position.x = drawString( + g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType, fontType, currentColor + ); + //drawStringWithSoftWraps(g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType, + // fontType, currentColor, logicalPosition); + BorderEffect.paintFoldedEffect(g, foldingXStart, position.y, position.x, getLineHeight(), effectColor, effectType); + + } + else { + position.x = drawStringWithSoftWraps(g, chars, start, Math.min(hEnd, lEnd - lIterator.getSeparatorLength()) , position, clip, + effectColor, effectType, fontType, currentColor, logicalPosition); + } + + iterationState.advance(); + attributes = iterationState.getMergedAttributes(); + + currentColor = attributes.getForegroundColor(); + if (currentColor == null) { + currentColor = getForegroundColor(); + } + + effectColor = attributes.getEffectColor(); + effectType = attributes.getEffectType(); + fontType = attributes.getFontType(); + + start = iterationState.getStartOffset(); } + } - iterationState.advance(); - attributes = iterationState.getMergedAttributes(); - - currentColor = attributes.getForegroundColor(); - if (currentColor == null) { - currentColor = getForegroundColor(); - } - - effectColor = attributes.getEffectColor(); - effectType = attributes.getEffectType(); - fontType = attributes.getFontType(); - - start = iterationState.getStartOffset(); + FoldRegion collapsedFolderAt = iterationState.getCurrentFold(); + if (collapsedFolderAt != null) { + int foldingXStart = position.x; + int foldingXEnd = + drawStringWithSoftWraps(g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType, + fontType, currentColor, logicalPosition); + BorderEffect.paintFoldedEffect(g, foldingXStart, position.y, foldingXEnd, getLineHeight(), effectColor, effectType); + // myBorderEffect.collapsedFolderReached(g, this); } } - - FoldRegion collapsedFolderAt = iterationState.getCurrentFold(); - if (collapsedFolderAt != null) { - int foldingXStart = position.x; - int foldingXEnd = - drawStringWithSoftWraps(g, collapsedFolderAt.getPlaceholderText(), position, clip, effectColor, effectType, - fontType, currentColor, logicalPosition); - BorderEffect.paintFoldedEffect(g, foldingXStart, position.y, foldingXEnd, getLineHeight(), effectColor, effectType); -// myBorderEffect.collapsedFolderReached(g, this); + finally { + iterationState.dispose(); } flushCachedChars(g); @@ -5903,59 +5923,64 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } IterationState state = new IterationState(EditorImpl.this, offset, endOffset, false); - int fontType = state.getMergedAttributes().getFontType(); + try { + int fontType = state.getMergedAttributes().getFontType(); - int maxPreviousSoftWrappedWidth = -1; + int maxPreviousSoftWrappedWidth = -1; - while (offset < documentLength && line < lineCount) { - char c = text.charAt(offset); - if (offset >= state.getEndOffset()) { - state.advance(); - fontType = state.getMergedAttributes().getFontType(); - } - - while (softWrapsIndex < softWraps.size() && line < lineCount) { - SoftWrap softWrap = softWraps.get(softWrapsIndex); - if (softWrap.getStart() > offset) { - break; + while (offset < documentLength && line < lineCount) { + char c = text.charAt(offset); + if (offset >= state.getEndOffset()) { + state.advance(); + fontType = state.getMergedAttributes().getFontType(); } - softWrapsIndex++; - if (softWrap.getStart() == offset) { - maxPreviousSoftWrappedWidth = Math.max(maxPreviousSoftWrappedWidth, x); - x = softWrap.getIndentInPixels(); + + while (softWrapsIndex < softWraps.size() && line < lineCount) { + SoftWrap softWrap = softWraps.get(softWrapsIndex); + if (softWrap.getStart() > offset) { + break; + } + softWrapsIndex++; + if (softWrap.getStart() == offset) { + maxPreviousSoftWrappedWidth = Math.max(maxPreviousSoftWrappedWidth, x); + x = softWrap.getIndentInPixels(); + } + } + + FoldRegion collapsed = state.getCurrentFold(); + if (collapsed != null) { + String placeholder = collapsed.getPlaceholderText(); + for (int i = 0; i < placeholder.length(); i++) { + x += EditorUtil.charWidth(placeholder.charAt(i), fontType, EditorImpl.this); + } + offset = collapsed.getEndOffset(); + line = myDocument.getLineNumber(offset); + } + else if (c == '\t') { + x = EditorUtil.nextTabStop(x, EditorImpl.this); + offset++; + } + else if (c == '\n') { + int width = Math.max(x, maxPreviousSoftWrappedWidth); + myLineWidths.set(line, width); + maxCalculatedLine = Math.max(maxCalculatedLine, line); + if (line + 1 >= lineCount || myLineWidths.getQuick(line + 1) != -1) break; + offset++; + x = 0; + //noinspection AssignmentToForLoopParameter + line++; + if (line == lineCount - 1) { + lastLineLengthCalculated = true; + } + } + else { + x += ComplementaryFontsRegistry.getFontAbleToDisplay(c, fontSize, fontType, fontName).charWidth(c, myEditorComponent); + offset++; } } - - FoldRegion collapsed = state.getCurrentFold(); - if (collapsed != null) { - String placeholder = collapsed.getPlaceholderText(); - for (int i = 0; i < placeholder.length(); i++) { - x += EditorUtil.charWidth(placeholder.charAt(i), fontType, EditorImpl.this); - } - offset = collapsed.getEndOffset(); - line = myDocument.getLineNumber(offset); - } - else if (c == '\t') { - x = EditorUtil.nextTabStop(x, EditorImpl.this); - offset++; - } - else if (c == '\n') { - int width = Math.max(x, maxPreviousSoftWrappedWidth); - myLineWidths.set(line, width); - maxCalculatedLine = Math.max(maxCalculatedLine, line); - if (line + 1 >= lineCount || myLineWidths.getQuick(line + 1) != -1) break; - offset++; - x = 0; - //noinspection AssignmentToForLoopParameter - line++; - if (line == lineCount - 1) { - lastLineLengthCalculated = true; - } - } - else { - x += ComplementaryFontsRegistry.getFontAbleToDisplay(c, fontSize, fontType, fontName).charWidth(c, myEditorComponent); - offset++; - } + } + finally { + state.dispose(); } } @@ -6011,35 +6036,40 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi @Override public int calcColumnNumber(@NotNull CharSequence text, int start, int offset, int tabSize) { IterationState state = new IterationState(this, start, start+offset, false); - int fontType = state.getMergedAttributes().getFontType(); - int column = 0; - int x = 0; - int spaceSize = EditorUtil.getSpaceWidth(fontType, this); - for (int i = start; i < offset; i++) { - if (i >= state.getEndOffset()) { - state.advance(); - fontType = state.getMergedAttributes().getFontType(); + try { + int fontType = state.getMergedAttributes().getFontType(); + int column = 0; + int x = 0; + int spaceSize = EditorUtil.getSpaceWidth(fontType, this); + for (int i = start; i < offset; i++) { + if (i >= state.getEndOffset()) { + state.advance(); + fontType = state.getMergedAttributes().getFontType(); + } + + SoftWrap softWrap = getSoftWrapModel().getSoftWrap(i); + if (softWrap != null) { + column++; // For 'after soft wrap' drawing. + x = getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP); + } + + char c = text.charAt(i); + if (c == '\t') { + int prevX = x; + x = EditorUtil.nextTabStop(x, this); + column += EditorUtil.columnsNumber(c, x, prevX, spaceSize); + } + else { + x += EditorUtil.charWidth(c, fontType, this); + column++; + } } - SoftWrap softWrap = getSoftWrapModel().getSoftWrap(i); - if (softWrap != null) { - column++; // For 'after soft wrap' drawing. - x = getSoftWrapModel().getMinDrawingWidthInPixels(SoftWrapDrawingType.AFTER_SOFT_WRAP); - } - - char c = text.charAt(i); - if (c == '\t') { - int prevX = x; - x = EditorUtil.nextTabStop(x, this); - column += EditorUtil.columnsNumber(c, x, prevX, spaceSize); - } - else { - x += EditorUtil.charWidth(c, fontType, this); - column++; - } + return column; + } + finally { + state.dispose(); } - - return column; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java index 4490e1aca2e3..2367882c16fd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EmptyMarkupModel.java @@ -2,6 +2,7 @@ package com.intellij.openapi.editor.impl; import com.intellij.openapi.Disposable; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.ex.DisposableIterator; import com.intellij.openapi.editor.ex.MarkupModelEx; import com.intellij.openapi.editor.ex.RangeHighlighterEx; import com.intellij.openapi.editor.ex.SweepProcessor; @@ -13,12 +14,9 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.Key; import com.intellij.util.Consumer; import com.intellij.util.Processor; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Iterator; - /** * This is mock implementation to be used in null-object pattern where necessary. * @author max @@ -126,8 +124,8 @@ public class EmptyMarkupModel implements MarkupModelEx { @NotNull @Override - public Iterator overlappingIterator(int startOffset, int endOffset) { - return ContainerUtil.emptyIterator(); + public DisposableIterator overlappingIterator(int startOffset, int endOffset) { + return DisposableIterator.EMPTY; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java index cfb4c985734f..44250317f389 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/IterationState.java @@ -35,15 +35,13 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; -@SuppressWarnings({"ForLoopReplaceableByForEach"}) // Way too many garbage in AbstractList.iterator() produced otherwise. public final class IterationState { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.IterationState"); private final TextAttributes myMergedAttributes = new TextAttributes(); private final HighlighterIterator myHighlighterIterator; - private final HighlighterSweep myView = new HighlighterSweep(); - - private final HighlighterSweep myDoc = new HighlighterSweep(); + private final HighlighterSweep myView; + private final HighlighterSweep myDoc; private int myStartOffset; @@ -71,6 +69,9 @@ public final class IterationState { private final EditorEx myEditor; private final Color myReadOnlyColor; + /** + * You MUST CALL {@link #dispose()} afterwards + */ public IterationState(@NotNull EditorEx editor, int start, int end, boolean useCaretAndSelection) { ApplicationManager.getApplication().assertReadAccessAllowed(); myDocument = (DocumentEx)editor.getDocument(); @@ -104,22 +105,29 @@ public final class IterationState { myCurrentHighlighters = new ArrayList(); MarkupModelEx editorMarkup = (MarkupModelEx)editor.getMarkupModel(); - myView.init(editorMarkup, start, myEnd); + myView = new HighlighterSweep(editorMarkup, start, myEnd); final MarkupModelEx docMarkup = (MarkupModelEx)DocumentMarkupModel.forDocument(editor.getDocument(), editor.getProject(), true); - myDoc.init(docMarkup, start, myEnd); + myDoc = new HighlighterSweep(docMarkup, start, myEnd); myEndOffset = myStartOffset; advance(); } - private class HighlighterSweep { - private RangeHighlighterEx myNextHighlighter = null; - private PushBackIterator myIterator; + public void dispose() { + myView.dispose(); + myDoc.dispose(); + } - private void init(@NotNull MarkupModelEx markupModel, int start, int end) { - myIterator = new PushBackIterator(markupModel.overlappingIterator(start, end)); + private class HighlighterSweep { + private RangeHighlighterEx myNextHighlighter; + private final PushBackIterator myIterator; + private final DisposableIterator myDisposableIterator; + + private HighlighterSweep(@NotNull MarkupModelEx markupModel, int start, int end) { + myDisposableIterator = markupModel.overlappingIterator(start, end); + myIterator = new PushBackIterator(myDisposableIterator); int skipped = 0; while (myIterator.hasNext()) { RangeHighlighterEx highlighter = myIterator.next(); @@ -176,6 +184,10 @@ public final class IterationState { } return Integer.MAX_VALUE; } + + public void dispose() { + myDisposableIterator.dispose(); + } } private boolean skipHighlighter(@NotNull RangeHighlighterEx highlighter) { @@ -230,6 +242,7 @@ public final class IterationState { private int getGuardedBlockEnd(int start) { List blocks = myDocument.getGuardedBlocks(); int min = myEnd; + //noinspection ForLoopReplaceableByForEach for (int i = 0; i < blocks.size(); i++) { RangeMarker block = blocks.get(i); if (block.getStartOffset() > start) { @@ -257,7 +270,6 @@ public final class IterationState { private void advanceSegmentHighlighters() { myDoc.advance(); - myView.advance(); for (int i = myCurrentHighlighters.size() - 1; i >= 0; i--) { @@ -296,6 +308,7 @@ public final class IterationState { private int getMinSegmentHighlightersEnd() { int end = myEnd; + //noinspection ForLoopReplaceableByForEach for (int i = 0; i < myCurrentHighlighters.size(); i++) { RangeHighlighterEx highlighter = myCurrentHighlighters.get(i); if (highlighter.getAffectedAreaEndOffset() < end) { @@ -332,6 +345,7 @@ public final class IterationState { ContainerUtil.quickSort(myCurrentHighlighters, LayerComparator.INSTANCE); } + //noinspection ForLoopReplaceableByForEach for (int i = 0; i < size; i++) { RangeHighlighterEx highlighter = myCurrentHighlighters.get(i); if (highlighter.getTextAttributes() == TextAttributes.ERASE_MARKER) { @@ -342,6 +356,7 @@ public final class IterationState { List cachedAttributes = myCachedAttributesList; cachedAttributes.clear(); + //noinspection ForLoopReplaceableByForEach for (int i = 0; i < size; i++) { RangeHighlighterEx highlighter = myCurrentHighlighters.get(i); if (selection != null && highlighter.getLayer() < HighlighterLayer.SELECTION) { @@ -387,6 +402,7 @@ public final class IterationState { EffectType effectType = null; int fontType = 0; + //noinspection ForLoopReplaceableByForEach for (int i = 0; i < cachedAttributes.size(); i++) { TextAttributes attrs = cachedAttributes.get(i); @@ -453,6 +469,7 @@ public final class IterationState { ContainerUtil.quickSort(myCurrentHighlighters, LayerComparator.INSTANCE); + //noinspection ForLoopReplaceableByForEach for (int i = 0; i < myCurrentHighlighters.size(); i++) { RangeHighlighterEx highlighter = myCurrentHighlighters.get(i); if (caret != null && highlighter.getLayer() < HighlighterLayer.CARET_ROW) { diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java index e8f4cad9e41a..524082380b9d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/MarkupModelImpl.java @@ -28,6 +28,7 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.ex.DisposableIterator; import com.intellij.openapi.editor.ex.MarkupModelEx; import com.intellij.openapi.editor.ex.RangeHighlighterEx; import com.intellij.openapi.editor.ex.SweepProcessor; @@ -45,7 +46,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx { @@ -257,7 +257,7 @@ public class MarkupModelImpl extends UserDataHolderBase implements MarkupModelEx @Override @NotNull - public Iterator overlappingIterator(int startOffset, int endOffset) { + public DisposableIterator overlappingIterator(int startOffset, int endOffset) { return myHighlighterTree.overlappingIterator(startOffset, endOffset); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CacheEntry.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CacheEntry.java index 99adecc7a448..54890f9870aa 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CacheEntry.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CacheEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * 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. @@ -228,8 +228,8 @@ class CacheEntry implements Comparable, Cloneable { @Override public String toString() { - return "visual line: " + visualLine + ", offsets: " + startOffset + "-" + endOffset + ", fold regions: " - + Arrays.toString(myFoldingData.getValues()) + ", tab data: " + myTabPositions; + return System.identityHashCode(this) + "=visual line: " + visualLine + ", offsets: " + startOffset + "-" + endOffset + + ", fold regions: " + Arrays.toString(myFoldingData.getValues()) + ", tab data: " + myTabPositions; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CachingSoftWrapDataMapper.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CachingSoftWrapDataMapper.java index 0ff1694b6906..5fd1d61f2769 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CachingSoftWrapDataMapper.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/CachingSoftWrapDataMapper.java @@ -452,7 +452,8 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw CacheEntry beforeLast = myCache.get(myCache.size() - 2); CacheEntry last = myCache.get(myCache.size() - 1); if (beforeLast.visualLine == last.visualLine - || (beforeLast.visualLine + 1 == last.visualLine && last.startOffset - beforeLast.endOffset > 1)) + || (beforeLast.visualLine + 1 == last.visualLine && last.startOffset - beforeLast.endOffset > 1) + || last.startOffset > myEditor.getDocument().getTextLength()) { CharSequence editorState = ""; if (myEditor instanceof EditorImpl) { @@ -481,6 +482,13 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw myBeforeChangeState.cacheShouldBeUpdated = false; } + @Override + public void reset() { + myCache.clear(); + myAffectedByUpdateCacheEntries.clear(); + myNotAffectedByUpdateTailCacheEntries.clear(); + } + @SuppressWarnings({"UseOfSystemOutOrSystemErr", "UnusedDeclaration", "CallToPrintStackTrace"}) private void dumpCache() { Document document = myEditor.getDocument(); @@ -541,7 +549,7 @@ public class CachingSoftWrapDataMapper implements SoftWrapDataMapper, SoftWrapAw int softWrapIndex = myStorage.getSoftWrapIndex(offset); if (softWrapIndex >= 0) { - softWrapIndex++; // We want to process only soft wraps which offsets strictly more than the given one. + softWrapIndex++; // We want to process only soft wraps which offsets are strictly more than the given one. } else { softWrapIndex = -softWrapIndex - 1; diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java index d6056d23efc4..1223be9d2e6a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java @@ -118,6 +118,9 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume public void reset() { myEventsStorage.release(); myEventsStorage.add(myEditor.getDocument(), new IncrementalCacheUpdateEvent(myEditor.getDocument())); + for (SoftWrapAwareDocumentParsingListener listener : myListeners) { + listener.reset(); + } } public void release() { @@ -205,51 +208,56 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume myContext.text = document.getCharsSequence(); myContext.tokenStartOffset = start; IterationState iterationState = new IterationState(myEditor, start, document.getTextLength(), false); - TextAttributes attributes = iterationState.getMergedAttributes(); - myContext.fontType = attributes.getFontType(); - myContext.rangeEndOffset = event.getNewEndOffset(); - - EditorPosition position = new EditorPosition(logical, start, myEditor, myRepresentationHelper); - Point point = myEditor.visualPositionToXY(visual); - position.x = point.x; - int spaceWidth = EditorUtil.getSpaceWidth(myContext.fontType, myEditor); - - myContext.logicalLineData.update(logical.line, spaceWidth, myEditor); - - myContext.currentPosition = position; - myContext.lineStartPosition = position.clone(); - myContext.fontType2spaceWidth.put(myContext.fontType, spaceWidth); - myContext.softWrapStartOffset = position.offset; - - myContext.contentComponent = myEditor.getContentComponent(); - myContext.reservedWidthInPixels = myPainter.getMinDrawingWidth(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED); - - // Perform soft wraps calculation. - while (!iterationState.atEnd() && myContext.currentPosition.offset <= event.getNewEndOffset()) { - FoldRegion currentFold = iterationState.getCurrentFold(); - if (currentFold == null) { - myContext.tokenEndOffset = iterationState.getEndOffset(); - processNonFoldToken(); - } - else { - boolean continueProcessing = processCollapsedFoldRegion(currentFold); - if (!continueProcessing) { - return false; - } - - // 'myOffset2widthInPixels' contains information necessary to processing soft wraps that lay before the current offset. - // We do know that soft wraps are not allowed to go backward after processed collapsed fold region, hence, we drop - // information about processed symbols width. - myOffset2widthInPixels.clear(); - } - - iterationState.advance(); - attributes = iterationState.getMergedAttributes(); + try { + TextAttributes attributes = iterationState.getMergedAttributes(); myContext.fontType = attributes.getFontType(); - myContext.tokenStartOffset = iterationState.getStartOffset(); - myOffset2fontType.fill(myContext.tokenStartOffset, iterationState.getEndOffset(), myContext.fontType); + myContext.rangeEndOffset = event.getNewEndOffset(); + + EditorPosition position = new EditorPosition(logical, start, myEditor, myRepresentationHelper); + Point point = myEditor.visualPositionToXY(visual); + position.x = point.x; + int spaceWidth = EditorUtil.getSpaceWidth(myContext.fontType, myEditor); + + myContext.logicalLineData.update(logical.line, spaceWidth, myEditor); + + myContext.currentPosition = position; + myContext.lineStartPosition = position.clone(); + myContext.fontType2spaceWidth.put(myContext.fontType, spaceWidth); + myContext.softWrapStartOffset = position.offset; + + myContext.contentComponent = myEditor.getContentComponent(); + myContext.reservedWidthInPixels = myPainter.getMinDrawingWidth(SoftWrapDrawingType.BEFORE_SOFT_WRAP_LINE_FEED); + + // Perform soft wraps calculation. + while (!iterationState.atEnd() && myContext.currentPosition.offset <= event.getNewEndOffset()) { + FoldRegion currentFold = iterationState.getCurrentFold(); + if (currentFold == null) { + myContext.tokenEndOffset = iterationState.getEndOffset(); + processNonFoldToken(); + } + else { + boolean continueProcessing = processCollapsedFoldRegion(currentFold); + if (!continueProcessing) { + return false; + } + + // 'myOffset2widthInPixels' contains information necessary to processing soft wraps that lay before the current offset. + // We do know that soft wraps are not allowed to go backward after processed collapsed fold region, hence, we drop + // information about processed symbols width. + myOffset2widthInPixels.clear(); + } + + iterationState.advance(); + attributes = iterationState.getMergedAttributes(); + myContext.fontType = attributes.getFontType(); + myContext.tokenStartOffset = iterationState.getStartOffset(); + myOffset2fontType.fill(myContext.tokenStartOffset, iterationState.getEndOffset(), myContext.fontType); + } + notifyListenersOnVisualLineEnd(); + } + finally { + iterationState.dispose(); } - notifyListenersOnVisualLineEnd(); return true; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareDocumentParsingListener.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareDocumentParsingListener.java index 32bcf2c183bf..c9f113db9ba2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareDocumentParsingListener.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareDocumentParsingListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * 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. @@ -120,4 +120,9 @@ interface SoftWrapAwareDocumentParsingListener { * should be rolled back if this param value is false */ void onRecalculationEnd(@NotNull IncrementalCacheUpdateEvent event, boolean normal); + + /** + * Callback for asking to drop all cached information (if any). + */ + void reset(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareVisualSizeManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareVisualSizeManager.java index c5a12ff59922..78c6579f6140 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareVisualSizeManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapAwareVisualSizeManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * 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. @@ -120,4 +120,8 @@ public class SoftWrapAwareVisualSizeManager implements SoftWrapAwareDocumentPars @Override public void revertToOffset(int offset, int visualLine) { } + + @Override + public void reset() { + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/TabData.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/TabData.java index 12e1fe06d551..f4e6adcabd45 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/TabData.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/TabData.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2010 JetBrains s.r.o. + * 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. @@ -31,7 +31,7 @@ class TabData implements Cloneable { @Override public String toString() { - return offset + ", width: " + widthInColumns; + return "[" + offset + ", width: " + widthInColumns + "]"; } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java index 3c5409f220ba..f4cc2045a3ea 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java @@ -383,8 +383,8 @@ final class EditorTabbedContainer implements Disposable, CloseAction.CloseTarget @Override public void update(final AnActionEvent e) { - e.getPresentation().setIcon(myTabs instanceof JBEditorTabs && myTabs.isEditorTabs() ? myNewIcon : myIcon); - e.getPresentation().setHoveredIcon(myTabs instanceof JBEditorTabs && myTabs.isEditorTabs()? myNewHoveredIcon : myHoveredIcon); + e.getPresentation().setIcon(myTabs.isEditorTabs() ? myNewIcon : myIcon); + e.getPresentation().setHoveredIcon(myTabs.isEditorTabs()? myNewHoveredIcon : myHoveredIcon); e.getPresentation().setVisible(UISettings.getInstance().SHOW_CLOSE_BUTTON); } diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java index 0e6fd1991280..eb081e413848 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java @@ -621,6 +621,7 @@ public class EditorWindow { if (tabCount != 0) { final EditorWithProviderComposite firstEC = getEditorAt(0); myPanel = new JPanel(new BorderLayout()); + myPanel.setOpaque(false); myPanel.setBorder(new AdaptiveBorder()); myPanel.setOpaque(false); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java index 44edbdbc54ef..4ae17eaf4917 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java @@ -78,8 +78,7 @@ public class EditorsSplitters extends JPanel { public EditorsSplitters(final FileEditorManagerImpl manager, DockManager dockManager, boolean createOwnDockableContainer) { super(new BorderLayout()); - setOpaque(true); - setBackground(UIUtil.isUnderAquaLookAndFeel() ? JBTabsImpl.MAC_AQUA_BG_COLOR : Color.GRAY); + setOpaque(false); myManager = manager; myFocusWatcher = new MyFocusWatcher(); setFocusTraversalPolicy(new MyFocusTraversalPolicy()); @@ -304,6 +303,7 @@ public class EditorsSplitters extends JPanel { Splitter splitter; if (panel == null) { panel = new JPanel(new BorderLayout()); + panel.setOpaque(false); splitter = new Splitter(orientation, proportion, 0.1f, 0.9f); panel.add(splitter, BorderLayout.CENTER); splitter.setFirstComponent(readExternalPanel(first, null)); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java index ff19a12435e6..8c9fca553818 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java @@ -64,6 +64,7 @@ import com.intellij.ui.tabs.impl.JBTabsImpl; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.messages.impl.MessageListenerList; +import com.intellij.util.ui.SameColor; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; @@ -209,7 +210,17 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec if (myPanels == null) { synchronized (myInitLock) { if (myPanels == null) { - myPanels = new JPanel(new BorderLayout()); + myPanels = new JPanel(new BorderLayout()) { + @Override + public Color getBackground() { + boolean navBar = UISettings.getInstance().SHOW_NAVIGATION_BAR; + if (navBar) { + return UIUtil.getSlightlyDarkerColor(UIUtil.isUnderAquaLookAndFeel() ? new SameColor(200) : UIUtil.getPanelBackground()); + } else { + return UIUtil.isUnderAquaLookAndFeel() ? new SameColor(189) : UIUtil.getPanelBackground(); + } + } + }; myPanels.setBorder(new MyBorder()); mySplitters = new EditorsSplitters(this, myDockManager, true); myPanels.add(mySplitters, BorderLayout.CENTER); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesPanel.form b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesPanel.form index 1253b05bd2d0..7d35bc1db405 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesPanel.form +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesPanel.form @@ -5,7 +5,7 @@ - + @@ -52,7 +52,7 @@ - + diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java index 06824832886c..a8714fdb7ff6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowsPane.java @@ -31,6 +31,7 @@ import com.intellij.openapi.wm.ex.ToolWindowEx; import com.intellij.openapi.wm.impl.commands.FinalizableCommand; import com.intellij.reference.SoftReference; import com.intellij.util.containers.HashMap; +import com.intellij.util.ui.UIUtil; import javax.swing.*; import java.awt.*; @@ -1007,12 +1008,16 @@ final class ToolWindowsPane extends JLayeredPane implements Disposable { myBottomImageRef=new SoftReference(null); myTopImageRef=new SoftReference(null); setOpaque(true); - setBackground(Color.gray); add(splitter,JLayeredPane.DEFAULT_LAYER); splitter.setBounds(0,0,getWidth(),getHeight()); enableEvents(ComponentEvent.COMPONENT_EVENT_MASK); } + @Override + public Color getBackground() { + return SwingUtilities.getDeepestComponentAt(this, 0, 0) == this ? Color.GRAY : UIUtil.getPanelBackground(); + } + /** * TODO[vova] extract method * Lazily creates and returns bottom image for animation. diff --git a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form index 2c47a21e834b..e20d48ab1d9c 100644 --- a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form +++ b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.form @@ -33,7 +33,7 @@ - + diff --git a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java index 0ec0403a2492..73d6e706674b 100644 --- a/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java +++ b/platform/platform-impl/src/com/intellij/platform/NewDirectoryProjectDialog.java @@ -56,6 +56,8 @@ public class NewDirectoryProjectDialog extends DialogWrapper { private boolean myModifyingProjectName = false; private static final Object EMPTY_PROJECT_GENERATOR = new Object(); + private final String mySuggestedProjectName; + private boolean myProjectNameWasChanged = false; protected NewDirectoryProjectDialog(Project project) { super(project, true); @@ -65,9 +67,12 @@ public class NewDirectoryProjectDialog extends DialogWrapper { myLocationLabel.setLabelFor(myLocationField.getChildComponent()); myBaseDir = getBaseDir(); - File projectName = FileUtil.findSequentNonexistentFile(new File(myBaseDir), "untitled", ""); - myLocationField.setText(projectName.toString()); - myProjectNameTextField.setText(projectName.getName()); + + File suggestedProjectDirectory = FileUtil.findSequentNonexistentFile(new File(myBaseDir), "untitled", ""); + + myLocationField.setText(suggestedProjectDirectory.toString()); + myProjectNameTextField.setText(suggestedProjectDirectory.getName()); + mySuggestedProjectName = suggestedProjectDirectory.getName(); FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); ComponentWithBrowseButton.BrowseFolderActionListener listener = @@ -75,11 +80,16 @@ public class NewDirectoryProjectDialog extends DialogWrapper { project, descriptor, TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT) { - protected void onFileChoosen(VirtualFile chosenFile) { - super.onFileChoosen(chosenFile); myBaseDir = chosenFile.getPath(); - myLocationField.setText(new File(chosenFile.getPath(), myProjectNameTextField.getText()).toString()); + if (myProjectNameWasChanged) { + myLocationField.setText(new File(chosenFile.getPath(), myProjectNameTextField.getText()).toString()); + } else { + myModifyingLocation = true; + myLocationField.setText(chosenFile.getPath()); + myProjectNameTextField.setText(chosenFile.getName()); + myModifyingLocation = false; + } } }; myLocationField.addActionListener(listener); @@ -110,6 +120,7 @@ public class NewDirectoryProjectDialog extends DialogWrapper { myProjectNameTextField.getDocument().addDocumentListener(new DocumentAdapter() { protected void textChanged(final DocumentEvent e) { if (!myModifyingLocation) { + myProjectNameWasChanged = true; myModifyingProjectName = true; File f = new File(myBaseDir); myLocationField.setText(new File(f, myProjectNameTextField.getText()).getPath()); @@ -155,6 +166,10 @@ public class NewDirectoryProjectDialog extends DialogWrapper { }); } + private boolean projectNameWasChanged() { + return mySuggestedProjectName != null && !mySuggestedProjectName.equals(myProjectNameTextField.getText()); + } + private void checkValid() { String projectName = myProjectNameTextField.getText(); if (projectName.trim().isEmpty()) { diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java index 02b5343bf05e..1f6a4865e5c4 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java @@ -817,6 +817,37 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorP ((EditorImpl)myEditor).setPrefixTextAndAttributes(" ", new TextAttributes()); myEditor.getCaretModel().moveToOffset(text.length()); } + + public void testSoftWrapCacheReset() throws IOException { + // Inspired by IDEA-76537 - the point is to drop cached document info on complete soft wraps recalculation + String text = + "\t first line\n" + + "\t second line\n" + + "\t third line"; + + // Make soft wraps to build a document info cache. + init(300, text); + + // Modify document while soft wraps processing is off. + final EditorSettings settings = getEditor().getSettings(); + settings.setUseSoftWraps(false); + int startOffset = text.indexOf("\t third") - 1; + getEditor().getDocument().deleteString(startOffset, text.length()); + + // Enable soft wraps and ensure that the cache is correctly re-built. + settings.setUseSoftWraps(true); + + getEditor().getCaretModel().moveToOffset(getEditor().getDocument().getTextLength()); + type("\n test"); + + final int offset = getEditor().getDocument().getTextLength() - 1; + final LogicalPosition logicalPosition = getEditor().offsetToLogicalPosition(offset); + assertEquals(offset, getEditor().logicalPositionToOffset(logicalPosition)); + + final VisualPosition visualPosition = getEditor().offsetToVisualPosition(offset); + assertEquals(visualPosition, getEditor().logicalToVisualPosition(logicalPosition)); + assertEquals(logicalPosition, getEditor().visualToLogicalPosition(visualPosition)); + } private void init(final int visibleWidth, @NotNull String fileText) throws IOException { init(visibleWidth, fileText, TestFileType.TEXT); diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 30ae23cae219..57df2da3bffa 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -101,7 +101,7 @@ ide.tabbedPane.dragOutMultiplier=1.2 ide.mac.filechooser.showhidden.files=false ide.mac.filechooser.native=true -ide.mac.message.dialogs.as.sheets=false +ide.mac.message.dialogs.as.sheets=true ide.mac.inplaceDialogMnemonicsFix=true debugger.valueTooltipAutoShow=true diff --git a/platform/platform-resources/src/META-INF/LangExtensions.xml b/platform/platform-resources/src/META-INF/LangExtensions.xml index 2d846bb5d1b5..903cfba08491 100644 --- a/platform/platform-resources/src/META-INF/LangExtensions.xml +++ b/platform/platform-resources/src/META-INF/LangExtensions.xml @@ -457,6 +457,7 @@ + @@ -653,6 +654,7 @@ + diff --git a/platform/util/src/com/intellij/execution/process/ProcessHandler.java b/platform/util/src/com/intellij/execution/process/ProcessHandler.java index 383cedd4bc99..e0bdfd1fd957 100644 --- a/platform/util/src/com/intellij/execution/process/ProcessHandler.java +++ b/platform/util/src/com/intellij/execution/process/ProcessHandler.java @@ -189,6 +189,10 @@ public abstract class ProcessHandler extends UserDataHolderBase { public boolean isStartNotified() { return myState.get() > STATE_INITIAL; } + + public boolean isSilentlyDestroyOnClose() { + return false; + } private ProcessListener createEventMulticaster() { final Class listenerClass = ProcessListener.class; diff --git a/platform/util/src/com/intellij/openapi/ui/Splitter.java b/platform/util/src/com/intellij/openapi/ui/Splitter.java index 816fb6c27670..1aac8335f09a 100644 --- a/platform/util/src/com/intellij/openapi/ui/Splitter.java +++ b/platform/util/src/com/intellij/openapi/ui/Splitter.java @@ -101,6 +101,7 @@ public class Splitter extends JPanel { super.add(myDivider); myFocusWatcher = new FocusWatcher(); myFocusWatcher.install(this); + setOpaque(false); } public void setShowDividerControls(boolean showDividerControls) { @@ -463,7 +464,7 @@ public class Splitter extends JPanel { myResizeEnabled = true; setFocusable(false); enableEvents(MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK); - + setOpaque(false); setOrientation(myVerticalSplit); } @@ -486,7 +487,7 @@ public class Splitter extends JPanel { GridBagConstraints.CENTER, GridBagConstraints.EAST, new Insets(0, leftInsetIcon, 0, 0), 0, 0)); - if (myShowDividerControls) { + if (myShowDividerControls && false) { int xMask = isVerticalSplit ? 1 : 0; int yMask = isVerticalSplit ? 0 : 1; diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 01ed5a5a4d42..09abebf8f37d 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -1655,6 +1655,32 @@ public class StringUtil { idx += 2; } } + + public static String unescapeSlashes(@NotNull final String str) { + final StringBuilder buf = StringBuilderSpinAllocator.alloc(); + try { + unescapeSlashes(buf, str); + return buf.toString(); + } + finally { + StringBuilderSpinAllocator.dispose(buf); + } + } + + private static void unescapeSlashes(StringBuilder buf, String str) { + final int length = str.length(); + final int last = length - 1; + for (int i = 0; i < length; i++) { + char ch = str.charAt(i); + if (ch == '\\' && i != last) { + i++; + ch = str.charAt(i); + if (ch != '/') buf.append('\\'); + } + + buf.append(ch); + } + } public static void quote(@NotNull final StringBuilder builder) { quote(builder, '\"'); diff --git a/platform/util/src/com/intellij/util/containers/Queue.java b/platform/util/src/com/intellij/util/containers/Queue.java index aa0c112b96c5..a4c634254132 100644 --- a/platform/util/src/com/intellij/util/containers/Queue.java +++ b/platform/util/src/com/intellij/util/containers/Queue.java @@ -15,11 +15,12 @@ */ package com.intellij.util.containers; +import com.intellij.util.ArrayUtil; + import java.util.Arrays; import java.util.List; public class Queue { - private final static Object[] EMPTY = new Object[0]; private Object[] myArray; private int myFirst; private int myLast; @@ -29,7 +30,7 @@ public class Queue { private boolean isWrapped; public Queue(int initialCapacity) { - myArray = initialCapacity > 0 ? new Object[initialCapacity] : EMPTY; + myArray = initialCapacity > 0 ? new Object[initialCapacity] : ArrayUtil.EMPTY_OBJECT_ARRAY; } public void addLast(T object) { diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 9cf265b380a5..ad77eff02c51 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -465,6 +465,11 @@ public class UIUtil { public static Color getInactiveTextColor() { return UIManager.getColor("textInactiveText"); } + + public static Color getSlightlyDarkerColor(Color c) { + float[] hsl = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), new float[3]); + return new Color(Color.HSBtoRGB(hsl[0], hsl[1], hsl[2] - .08f > 0 ? hsl[2] - .08f : hsl[2])); + } /** * @deprecated use com.intellij.util.ui.UIUtil#getTextFieldBackground() diff --git a/platform/util/testSrc/com/intellij/util/containers/QueueTest.java b/platform/util/testSrc/com/intellij/util/containers/QueueTest.java index 833fad9398d1..1435d96e2b6f 100644 --- a/platform/util/testSrc/com/intellij/util/containers/QueueTest.java +++ b/platform/util/testSrc/com/intellij/util/containers/QueueTest.java @@ -48,6 +48,15 @@ public class QueueTest extends TestCase { testEmpty(); } + public void testQuibble() { + com.intellij.util.containers.Queue queue = new com.intellij.util.containers.Queue(0); + String xxx = "xxx"; + queue.addLast(xxx); + CHECK.compareAll(queue.toArray(), new String[] {xxx}); + Object x = queue.pullFirst(); + assertEquals(xxx,x); + assertTrue(queue.isEmpty()); + } public void testCycling() { com.intellij.util.containers.Queue queue = new com.intellij.util.containers.Queue(10); for (int i = 0; i < 9; i++) { diff --git a/plugins/IntelliLang/src/intentionDescriptions/QuickEditAction/after.java.template b/plugins/IntelliLang/src/intentionDescriptions/QuickEditAction/after.java.template index 391250caa0ad..67fb495564cd 100644 --- a/plugins/IntelliLang/src/intentionDescriptions/QuickEditAction/after.java.template +++ b/plugins/IntelliLang/src/intentionDescriptions/QuickEditAction/after.java.template @@ -1 +1,10 @@ -XXX \ No newline at end of file +import java.sql.*; + +public class Test { + public void runScript(Statement st) throws SQLException { + st.execute("create table some_table (id integer primary key)"); + st.execute("insert into some_table values(1)"); + st.execute("select * from some_table"); + st.execute("drop table some_table"); + } +} \ No newline at end of file diff --git a/plugins/IntelliLang/src/intentionDescriptions/QuickEditAction/before.java.template b/plugins/IntelliLang/src/intentionDescriptions/QuickEditAction/before.java.template index 391250caa0ad..f6ee718db163 100644 --- a/plugins/IntelliLang/src/intentionDescriptions/QuickEditAction/before.java.template +++ b/plugins/IntelliLang/src/intentionDescriptions/QuickEditAction/before.java.template @@ -1 +1,10 @@ -XXX \ No newline at end of file +import java.sql.*; + +public class Test { + public void runScript(Statement st) throws SQLException { + st.execute("create table some_table (id integer primary key)"); + st.execute("insert into some_table values(1)"); + st.execute("select * from some_table"); + st.execute("drop table some_table"); + } +} \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java index d8591f2494cc..ad689abb01a3 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java @@ -365,7 +365,7 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { } } - private static class MyValidityState extends ResourcesValidityState { + private static class MyValidityState extends ResourceNamesValidityState { private final String myCustomGenPathR; private final Set myNonExistingFiles; private final int myPlatformToolsRevision; diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java index 176e5eba9141..b2e494bfe3b2 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java @@ -15,6 +15,7 @@ */ package org.jetbrains.android.compiler; +import com.android.resources.ResourceType; import com.intellij.CommonBundle; import com.intellij.compiler.impl.CompileContextImpl; import com.intellij.compiler.impl.ModuleCompileScope; @@ -46,8 +47,13 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.HashSet; +import org.jetbrains.android.dom.resources.Attr; +import org.jetbrains.android.dom.resources.DeclareStyleable; +import org.jetbrains.android.dom.resources.ResourceElement; +import org.jetbrains.android.dom.resources.Resources; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidRootUtil; +import org.jetbrains.android.resourceManagers.LocalResourceManager; import org.jetbrains.android.sdk.AndroidPlatform; import org.jetbrains.android.sdk.AndroidSdkType; import org.jetbrains.android.util.AndroidUtils; @@ -680,4 +686,75 @@ public class AndroidCompileUtil { createSourceRootIfNotExist(sourceRootPath, module); } } -} + + public static void collectAllResources(@NotNull final AndroidFacet facet, final Set resourceSet) { + final LocalResourceManager manager = facet.getLocalResourceManager(); + for (final String resType : ResourceType.getNames()) { + for (final ResourceElement element : manager.getValueResources(resType)) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + if (!element.isValid() || facet.getModule().isDisposed() || facet.getModule().getProject().isDisposed()) { + return; + } + final String name = element.getName().getValue(); + + if (name != null) { + resourceSet.add(new ResourceEntry(resType, name)); + } + } + }); + } + } + + for (final Resources resources : manager.getResourceElements()) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + if (!resources.isValid() || facet.getModule().isDisposed() || facet.getModule().getProject().isDisposed()) { + return; + } + + for (final Attr attr : resources.getAttrs()) { + final String name = attr.getName().getValue(); + + if (name != null) { + resourceSet.add(new ResourceEntry(ResourceType.ATTR.getName(), name)); + } + } + + for (final DeclareStyleable styleable : resources.getDeclareStyleables()) { + final String name = styleable.getName().getValue(); + + if (name != null) { + resourceSet.add(new ResourceEntry(ResourceType.DECLARE_STYLEABLE.getName(), name)); + } + } + } + }); + } + + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + if (facet.getModule().isDisposed() || facet.getModule().getProject().isDisposed()) { + return; + } + + for (String id : manager.getIds()) { + resourceSet.add(new ResourceEntry(ResourceType.ID.getName(), id)); + } + } + }); + final HashSet visited = new HashSet(); + + for (VirtualFile subdir : manager.getResourceSubdirs(null)) { + final HashSet resourceFiles = new HashSet(); + AndroidUtils.collectFiles(subdir, visited, resourceFiles); + + for (VirtualFile file : resourceFiles) { + resourceSet.add(new ResourceEntry(subdir.getName(), file.getName())); + } + } + } +} \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java index a8b9523fc7cb..17d70f0d0d1d 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidMavenResourcesCompiler.java @@ -166,7 +166,7 @@ public class AndroidMavenResourcesCompiler implements SourceGeneratingCompiler { } } - private static class MyValidityState extends ResourcesValidityState { + private static class MyValidityState extends ResourceNamesValidityState { private final long[] myMavenArtifactsTimespamps; private MyValidityState(Module module) { diff --git a/plugins/android/src/org/jetbrains/android/compiler/ResourceEntry.java b/plugins/android/src/org/jetbrains/android/compiler/ResourceEntry.java new file mode 100644 index 000000000000..868e523eb3f2 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/compiler/ResourceEntry.java @@ -0,0 +1,46 @@ +package org.jetbrains.android.compiler; + +import org.jetbrains.annotations.NotNull; + +/** +* @author Eugene.Kudelevsky +*/ +public class ResourceEntry { + private final String myType; + private final String myName; + + ResourceEntry(@NotNull String type, @NotNull String name) { + myType = type; + myName = name; + } + + @NotNull + public String getType() { + return myType; + } + + @NotNull + public String getName() { + return myName; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ResourceEntry entry = (ResourceEntry)o; + + if (!myName.equals(entry.myName)) return false; + if (!myType.equals(entry.myType)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myType.hashCode(); + result = 31 * result + myName.hashCode(); + return result; + } +} diff --git a/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java b/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java new file mode 100644 index 000000000000..e1aefdc3aa16 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/compiler/ResourceNamesValidityState.java @@ -0,0 +1,78 @@ +package org.jetbrains.android.compiler; + +import com.android.sdklib.IAndroidTarget; +import com.intellij.openapi.compiler.ValidityState; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.HashSet; +import org.jetbrains.android.facet.AndroidFacet; +import org.jetbrains.android.facet.AndroidRootUtil; +import org.jetbrains.android.sdk.AndroidPlatform; +import org.jetbrains.annotations.NotNull; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Set; + +/** + * @author Eugene.Kudelevsky + */ +public class ResourceNamesValidityState implements ValidityState { + private final Set myResourcesSet = new HashSet(); + private final String myAndroidTargetHashString; + private final long myManifestTimestamp; + + public ResourceNamesValidityState(@NotNull Module module) { + final AndroidFacet facet = AndroidFacet.getInstance(module); + assert facet != null; + + final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform(); + final IAndroidTarget target = platform != null ? platform.getTarget() : null; + myAndroidTargetHashString = target != null ? target.hashString() : ""; + + final VirtualFile manifestFile = AndroidRootUtil.getManifestFile(facet.getModule()); + myManifestTimestamp = manifestFile != null ? manifestFile.getModificationStamp() : -1; + + AndroidCompileUtil.collectAllResources(facet, myResourcesSet); + } + + public ResourceNamesValidityState(@NotNull DataInput in) throws IOException { + myAndroidTargetHashString = in.readUTF(); + myManifestTimestamp = in.readLong(); + + final int resourcesCount = in.readInt(); + + for (int i = 0; i < resourcesCount; i++) { + final String type = in.readUTF(); + final String name = in.readUTF(); + myResourcesSet.add(new ResourceEntry(type, name)); + } + } + + @Override + public boolean equalsTo(ValidityState otherState) { + if (!(otherState instanceof ResourceNamesValidityState)) { + return false; + } + + final ResourceNamesValidityState other = (ResourceNamesValidityState)otherState; + + return other.myAndroidTargetHashString.equals(myAndroidTargetHashString) && + other.myManifestTimestamp == myManifestTimestamp && + other.myResourcesSet.equals(myResourcesSet); + } + + @Override + public void save(DataOutput out) throws IOException { + out.writeUTF(myAndroidTargetHashString); + out.writeLong(myManifestTimestamp); + + out.writeInt(myResourcesSet.size()); + + for (ResourceEntry resourceEntry : myResourcesSet) { + out.writeUTF(resourceEntry.getType()); + out.writeUTF(resourceEntry.getName()); + } + } +} diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java index 184221decd74..2fb3ba73ca52 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java @@ -55,7 +55,6 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.VirtualFileAdapter; import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDocumentManager; @@ -67,12 +66,10 @@ import com.intellij.psi.xml.XmlTag; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; import com.intellij.util.containers.HashMap; +import com.intellij.util.containers.HashSet; import com.intellij.util.xml.ConvertContext; import com.intellij.util.xml.DomElement; -import org.jetbrains.android.compiler.AndroidAptCompiler; -import org.jetbrains.android.compiler.AndroidCompileUtil; -import org.jetbrains.android.compiler.AndroidIdlCompiler; -import org.jetbrains.android.compiler.AndroidRenderscriptCompiler; +import org.jetbrains.android.compiler.*; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.resourceManagers.LocalResourceManager; import org.jetbrains.android.resourceManagers.ResourceManager; @@ -96,7 +93,7 @@ public class AndroidFacet extends Facet { private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.facet.AndroidFacet"); public static final FacetTypeId ID = new FacetTypeId("android"); - private VirtualFileAdapter myListener; + private AndroidResourceFilesListener myListener; private AvdManager myAvdManager = null; @@ -351,6 +348,11 @@ public class AndroidFacet extends Facet { if (project.isDisposed()) { return; } + + final HashSet resourceSet = new HashSet(); + AndroidCompileUtil.collectAllResources(AndroidFacet.this, resourceSet); + myListener.setResourceSet(resourceSet); + if (getConfiguration().REGENERATE_R_JAVA && AndroidAptCompiler.isToCompileModule(module, getConfiguration())) { AndroidCompileUtil.generate(module, new AndroidAptCompiler()); } diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java b/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java index 335349295351..465e30d082f5 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java @@ -18,18 +18,16 @@ package org.jetbrains.android.facet; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.GeneratingCompiler; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.*; +import com.intellij.util.containers.HashSet; import com.intellij.util.ui.update.MergingUpdateQueue; import com.intellij.util.ui.update.Update; -import org.jetbrains.android.compiler.AndroidAptCompiler; -import org.jetbrains.android.compiler.AndroidCompileUtil; -import org.jetbrains.android.compiler.AndroidIdlCompiler; -import org.jetbrains.android.compiler.AndroidRenderscriptCompiler; +import org.jetbrains.android.compiler.*; import org.jetbrains.android.dom.manifest.Manifest; import org.jetbrains.android.fileTypes.AndroidIdlFileType; import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType; @@ -37,6 +35,8 @@ import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Set; + import static org.jetbrains.android.util.AndroidUtils.findSourceRoot; /** @@ -47,12 +47,14 @@ import static org.jetbrains.android.util.AndroidUtils.findSourceRoot; * To change this template use File | Settings | File Templates. */ class AndroidResourceFilesListener extends VirtualFileAdapter { - private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.facet.AndroidResourceFilesListener"); private final MergingUpdateQueue myQueue; private final AndroidFacet myFacet; private String myCachedPackage = null; + private volatile Set myResourceSet = new HashSet(); + private static final Object RESOURCES_SET_LOCK = new Object(); + public AndroidResourceFilesListener(final AndroidFacet facet) { myFacet = facet; myQueue = new MergingUpdateQueue("AndroidResourcesCompilationQueue", 300, true, null, myFacet, null, false); @@ -117,11 +119,14 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { file.getFileType() == AndroidRenderscriptFileType.INSTANCE || getManifestFileName().equals(file.getName()) || (gp != null && gp.isDirectory() && getResDirName().equals(gp.getName()))) { - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - public void run() { - myQueue.queue(new MyUpdate(e)); - } - }); + + myQueue.queue(new MyUpdate(e)); + } + } + + public void setResourceSet(@NotNull Set resourceSet) { + synchronized (RESOURCES_SET_LOCK) { + myResourceSet = resourceSet; } } @@ -137,54 +142,89 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { if (ApplicationManager.getApplication().isUnitTestMode()) { return; } + final GeneratingCompiler compilerToRun = ApplicationManager.getApplication().runReadAction(new Computable() { @Nullable public GeneratingCompiler compute() { - if (myFacet.isDisposed()) return null; - Module myModule = myFacet.getModule(); - Project project = myModule.getProject(); - if (project.isDisposed()) return null; - VirtualFile file = myEvent.getFile(); - Module module = ModuleUtil.findModuleForFile(file, project); - if (module == myModule) { - VirtualFile parent = myEvent.getParent(); - if (parent != null) { - parent = parent.getParent(); - if (AndroidAptCompiler.isToCompileModule(module, myFacet.getConfiguration()) && - (myFacet.getConfiguration().REGENERATE_R_JAVA && parent == AndroidRootUtil.getResourceDir(module) || - AndroidRootUtil.getManifestFile(module) == file)) { - Manifest manifest = myFacet.getManifest(); - String aPackage = manifest != null ? manifest.getPackage().getValue() : null; - if (myCachedPackage != null && !myCachedPackage.equals(aPackage)) { - String aptGenDirPath = myFacet.getAptGenSourceRootPath(); - AndroidCompileUtil.removeDuplicatingClasses(myModule, myCachedPackage, AndroidUtils.R_CLASS_NAME, null, aptGenDirPath); - } - myCachedPackage = aPackage; - myFacet.getLocalResourceManager().invalidateAttributeDefinitions(); - return new AndroidAptCompiler(); - } - - if (myFacet.getConfiguration().REGENERATE_JAVA_BY_AIDL && file.getFileType() == AndroidIdlFileType.ourFileType) { - VirtualFile sourceRoot = findSourceRoot(myModule, file); - if (sourceRoot != null && AndroidRootUtil.getAidlGenDir(module, myFacet) != sourceRoot) { - return new AndroidIdlCompiler(project); - } - } - - if (file.getFileType() == AndroidRenderscriptFileType.INSTANCE) { - final VirtualFile sourceRoot = findSourceRoot(myModule, file); - if (sourceRoot != null && AndroidRootUtil.getRenderscriptGenDir(myModule) != sourceRoot) { - return new AndroidRenderscriptCompiler(); - } - } - } - } - return null; + return computeCompilerToRun(); } }); - if (compilerToRun != null) { - AndroidCompileUtil.generate(myFacet.getModule(), compilerToRun, true); + + if (compilerToRun == null) { + return; } + + if (compilerToRun instanceof AndroidAptCompiler) { + final HashSet resourceSet = new HashSet(); + + DumbService.getInstance(myFacet.getModule().getProject()).waitForSmartMode(); + + AndroidCompileUtil.collectAllResources(myFacet, resourceSet); + + synchronized (RESOURCES_SET_LOCK) { + if (resourceSet.equals(myResourceSet)) { + return; + } + myResourceSet = resourceSet; + } + } + AndroidCompileUtil.generate(myFacet.getModule(), compilerToRun, true); + } + + @Nullable + private GeneratingCompiler computeCompilerToRun() { + if (myFacet.isDisposed()) { + return null; + } + final Module myModule = myFacet.getModule(); + final Project project = myModule.getProject(); + + if (project.isDisposed()) { + return null; + } + final VirtualFile file = myEvent.getFile(); + final Module module = ModuleUtil.findModuleForFile(file, project); + + if (module != myModule) { + return null; + } + + VirtualFile parent = myEvent.getParent(); + if (parent == null) { + return null; + } + + parent = parent.getParent(); + if (AndroidAptCompiler.isToCompileModule(module, myFacet.getConfiguration()) && + (myFacet.getConfiguration().REGENERATE_R_JAVA && parent == AndroidRootUtil.getResourceDir(module) || + AndroidRootUtil.getManifestFile(module) == file)) { + final Manifest manifest = myFacet.getManifest(); + final String aPackage = manifest != null ? manifest.getPackage().getValue() : null; + + if (myCachedPackage != null && !myCachedPackage.equals(aPackage)) { + String aptGenDirPath = myFacet.getAptGenSourceRootPath(); + AndroidCompileUtil.removeDuplicatingClasses(myModule, myCachedPackage, AndroidUtils.R_CLASS_NAME, null, aptGenDirPath); + } + myCachedPackage = aPackage; + myFacet.getLocalResourceManager().invalidateAttributeDefinitions(); + + return new AndroidAptCompiler(); + } + + if (myFacet.getConfiguration().REGENERATE_JAVA_BY_AIDL && file.getFileType() == AndroidIdlFileType.ourFileType) { + VirtualFile sourceRoot = findSourceRoot(myModule, file); + if (sourceRoot != null && AndroidRootUtil.getAidlGenDir(module, myFacet) != sourceRoot) { + return new AndroidIdlCompiler(project); + } + } + + if (file.getFileType() == AndroidRenderscriptFileType.INSTANCE) { + final VirtualFile sourceRoot = findSourceRoot(myModule, file); + if (sourceRoot != null && AndroidRootUtil.getRenderscriptGenDir(myModule) != sourceRoot) { + return new AndroidRenderscriptCompiler(); + } + } + return null; } @Override @@ -192,10 +232,19 @@ class AndroidResourceFilesListener extends VirtualFileAdapter { if (update instanceof MyUpdate) { VirtualFile hisFile = ((MyUpdate)update).myEvent.getFile(); VirtualFile file = myEvent.getFile(); - if (hisFile == file) return true; + + if (hisFile == file) { + return true; + } + if (hisFile.getFileType() == AndroidIdlFileType.ourFileType || file.getFileType() == AndroidIdlFileType.ourFileType) { return hisFile.getFileType() == file.getFileType(); } + + if (hisFile.getFileType() == AndroidRenderscriptFileType.INSTANCE || file.getFileType() == AndroidRenderscriptFileType.INSTANCE) { + return hisFile.getFileType() == file.getFileType(); + } + return true; } return false; diff --git a/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java b/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java index 0708dd494024..77b2052c4dae 100644 --- a/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java +++ b/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java @@ -259,6 +259,9 @@ public abstract class ResourceManager { ApplicationManager.getApplication().runReadAction(new Runnable() { @Override public void run() { + if (!resources.isValid() || myModule.isDisposed() || myModule.getProject().isDisposed()) { + return; + } result.addAll(getValueResources(resourceType, resources)); } }); diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index a2d199be85a3..584b94f7eca1 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -252,6 +252,8 @@ + + diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java index 95b05cd7b5a3..0302cc827230 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java @@ -844,7 +844,9 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator { String substring = text.substring(quote.length()); String[] parts; - IElementType elementType = literal.getFirstChild().getNode().getElementType(); + PsiElement child = literal.getFirstChild(); + if (child == null) child = literal; + IElementType elementType = child.getNode().getElementType(); boolean isSimpleString = elementType == GroovyTokenTypes.mSTRING_LITERAL || elementType == GroovyTokenTypes.mGSTRING_LITERAL || elementType == GroovyTokenTypes.mREGEX_LITERAL; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java index e12d416d0d44..acb5fddf1d03 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java @@ -94,8 +94,8 @@ public class GroovyCodeFragmentFactory implements CodeFragmentFactory { javaText.append("groovy.lang.MetaClass |mc;\n"); javaText.append("java.lang.Class |clazz;\n"); if (!isStatic) { - javaText.append("|clazz = ((java.lang.Object)this).getClass();\n"); - javaText.append("|mc = ((groovy.lang.GroovyObject)this).getMetaClass();\n"); + javaText.append("|clazz = this.getClass();\n"); + javaText.append("|mc = this.getMetaClass();\n"); } else { assert contextClass != null; javaText.append("|clazz = java.lang.Class.forName(\"").append(contextClass.getQualifiedName()).append("\");\n"); @@ -118,16 +118,16 @@ public class GroovyCodeFragmentFactory implements CodeFragmentFactory { javaText.append("groovy.lang.ExpandoMetaClass |emc = new groovy.lang.ExpandoMetaClass(|clazz);\n"); if (!isStatic) { javaText.append("|emc.setProperty(\"").append(EVAL_NAME).append("\", |closure);\n"); - javaText.append("((groovy.lang.GroovyObject)this).setMetaClass(|emc);\n"); + javaText.append("this.setMetaClass(|emc);\n"); } else { - javaText.append("((groovy.lang.GroovyObject)|emc.getProperty(\"static\")).setProperty(\"").append(EVAL_NAME).append("\", |closure);\n"); + javaText.append("|emc.getProperty(\"static\").setProperty(\"").append(EVAL_NAME).append("\", |closure);\n"); javaText.append("groovy.lang.GroovySystem.getMetaClassRegistry().setMetaClass(|clazz, |emc);\n"); } javaText.append("|emc.initialize();\n"); javaText.append(unwrapVals(values)); if (!isStatic) { javaText.append("java.lang.Object |res = ((groovy.lang.MetaClassImpl)|emc).invokeMethod(this, \"").append(EVAL_NAME).append("\", |resVals);\n"); - javaText.append("((groovy.lang.GroovyObject)this).setMetaClass(|mc);"); //try/finally is not supported + javaText.append("this.setMetaClass(|mc);"); //try/finally is not supported } else { javaText.append("java.lang.Object |res = ((groovy.lang.MetaClassImpl)|emc).invokeStaticMethod(|clazz, \"").append(EVAL_NAME).append("\", |resVals);\n"); javaText.append("groovy.lang.GroovySystem.getMetaClassRegistry().setMetaClass(|clazz, |mc);\n"); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyTopLevelParentClassProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyTopLevelParentClassProvider.java new file mode 100644 index 000000000000..b1858a4d3e04 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyTopLevelParentClassProvider.java @@ -0,0 +1,51 @@ +/* + * 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 org.jetbrains.plugins.groovy.debugger; + +import com.intellij.debugger.engine.TopLevelParentClassProvider; +import com.intellij.psi.PsiAnonymousClass; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; + +/** + * @author Max Medvedev + */ +public class GroovyTopLevelParentClassProvider extends TopLevelParentClassProvider { + @Nullable + @Override + protected PsiClass getCustomTopLevelParentClass(PsiClass psiClass) { + if (!(psiClass instanceof GrTypeDefinition)) return null; + + PsiClass enclosing = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class, true); + while (enclosing != null) { + psiClass = enclosing; + enclosing = PsiTreeUtil.getParentOfType(enclosing, PsiClass.class, true); + } + + if (psiClass instanceof PsiAnonymousClass) { + final PsiFile file = psiClass.getContainingFile(); + if (file instanceof GroovyFile) { + return ((GroovyFile)file).getScriptClass(); + } + } + + return psiClass; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java index 304cc0956644..016eeba65cc0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/editor/GroovyLiteralCopyPasteProcessor.java @@ -64,7 +64,12 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce IElementType tokenType = token.getNode().getElementType(); if (tokenType == mREGEX_CONTENT || tokenType == mREGEX_LITERAL) { - return StringUtil.escapeSlashes(s); + if (escapeSlashes) { + return StringUtil.escapeSlashes(s); + } + else { + return s; + } } String chars; @@ -87,4 +92,17 @@ public class GroovyLiteralCopyPasteProcessor extends StringLiteralCopyPasteProce StringUtil.escapeStringCharacters(s.length(), s, chars, escapeSlashes, buffer); return buffer.toString(); } + + @NotNull + @Override + protected String unescape(String text, PsiElement token) { + final IElementType tokenType = token.getNode().getElementType(); + + if (tokenType == mREGEX_CONTENT || tokenType == mREGEX_LITERAL) { + return StringUtil.unescapeSlashes(text); + } + + return super.unescape(text, token); + } + } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/literals/GrLiteral.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/literals/GrLiteral.java index 797684b0d03c..f543c5aea6cb 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/literals/GrLiteral.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/literals/GrLiteral.java @@ -23,4 +23,5 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres * @author ilyas */ public interface GrLiteral extends GrExpression, PsiLiteral { + void setStringValue(String value); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 526184056fbe..1fa360b6d49d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -709,13 +709,19 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl TYPE_CALCULATOR = new NullableFunction() { @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrStringImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrStringImpl.java index 16a2964096a6..161f3a5bded8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrStringImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/literals/GrStringImpl.java @@ -35,7 +35,7 @@ import java.util.List; /** * @author ilyas */ -public class GrStringImpl extends GrExpressionImpl implements GrString { +public class GrStringImpl extends GrAbstractLiteral implements GrString { private static final Function TYPE_CALCULATOR = new Function() { @Override public PsiType fun(GrStringImpl grString) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteTest.groovy index fdc8f2c63eb0..068f9efe47d3 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/GroovyCopyPasteTest.groovy @@ -25,39 +25,6 @@ import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase class GroovyCopyPasteTest extends LightCodeInsightFixtureTestCase { int myAddImportsOld - public void testEscapeSlashesInRegex() { - myFixture.configureByText 'a.groovy', 'a/b' - myFixture.performEditorAction IdeActions.ACTION_COPY - myFixture.configureByText 'b.groovy', 'def x = /smth/' - myFixture.performEditorAction IdeActions.ACTION_PASTE - myFixture.checkResult 'def x = /smtha\\/b/' - } - - public void testEscapeSlashesInRegexFromRegex() { - myFixture.configureByText 'a.groovy', 'def x = /a\\/b/' - myFixture.performEditorAction IdeActions.ACTION_COPY - myFixture.configureByText 'b.groovy', 'def x = /smth/' - myFixture.performEditorAction IdeActions.ACTION_PASTE - myFixture.checkResult 'def x = /smtha\\/b/' - } - - void testDontEscapeSymbolsInRegex(){ - myFixture.configureByText 'a.groovy', '''def x = a/b''' - myFixture.performEditorAction IdeActions.ACTION_COPY - myFixture.configureByText 'b.groovy', 'def x = / /' - myFixture.performEditorAction IdeActions.ACTION_PASTE - myFixture.checkResult '''def x = /a\\/b /''' - } - - public void testEscapeDollarInGString() { - myFixture.configureByText 'a.groovy', '''def x = '$ab/''' - myFixture.performEditorAction IdeActions.ACTION_COPY - myFixture.configureByText 'b.groovy', 'def x = "smthh"' - myFixture.performEditorAction IdeActions.ACTION_PASTE - myFixture.checkResult 'def x = "smth$ah"' - - } - @Override protected void setUp() throws Exception { super.setUp(); @@ -73,41 +40,64 @@ class GroovyCopyPasteTest extends LightCodeInsightFixtureTestCase { settings.ADD_IMPORTS_ON_PASTE = myAddImportsOld; super.tearDown(); } + + private void doTest(String fromFileName, String fromText, String toText, String expected) { + myFixture.configureByText fromFileName, fromText + myFixture.performEditorAction IdeActions.ACTION_COPY + myFixture.configureByText 'b.groovy', toText + myFixture.performEditorAction IdeActions.ACTION_PASTE + myFixture.checkResult expected + } + + public void testEscapeSlashesInRegex() { + doTest 'a.groovy', 'a/b', 'def x = /smth/', 'def x = /smtha\\/b/' + } + + public void testEscapeSlashesInRegexFromRegex() { + doTest 'a.groovy', 'def x = /a\\/b/', 'def x = /smth/', 'def x = /smtha\\/b/' + } + + void testDontEscapeSymbolsInRegex(){ + doTest 'a.groovy', '''def x = a/b''', 'def x = / /', '''def x = /a\\/b /''' + } + + public void testEscapeDollarInGString() { + doTest 'a.groovy', '''def x = '$ab/''', 'def x = "smthh"', 'def x = "smth\\$ah"' + + } public void testRestoreImports() { myFixture.addClass("package foo; public class Foo {}") - myFixture.configureByText 'a.groovy', '''import foo.*; Foo f''' - myFixture.performEditorAction IdeActions.ACTION_COPY - myFixture.configureByText 'b.groovy', '' - myFixture.performEditorAction IdeActions.ACTION_PASTE - myFixture.checkResult '''import foo.Foo + doTest 'a.groovy', '''import foo.*; Foo f''', '', '''import foo.Foo Foo f''' } public void testPasteMultilineIntoMultilineGString() throws Exception { - myFixture.configureByText 'a.txt', 'a/b\nc/d' - myFixture.performEditorAction IdeActions.ACTION_COPY - myFixture.configureByText 'b.groovy', 'def x = """smth"""' - myFixture.performEditorAction IdeActions.ACTION_PASTE - myFixture.checkResult 'def x = """smtha/b\nc/d"""' + doTest 'a.txt', 'a/b\nc/d', 'def x = """smth"""', 'def x = """smtha/b\nc/d"""' } public void testPasteMultilineIntoString() throws Exception { - myFixture.configureByText 'a.txt', 'a\nd' - myFixture.performEditorAction IdeActions.ACTION_COPY - myFixture.configureByText 'b.groovy', "def x = 'smth'" - myFixture.performEditorAction IdeActions.ACTION_PASTE - myFixture.checkResult "def x = 'smtha\\n' +\n 'd'" + doTest 'a.txt', 'a\nd', "def x = 'smth'", "def x = 'smtha\\n' +\n 'd'" } public void testPasteMultilineIntoGString() throws Exception { - myFixture.configureByText 'a.txt', 'a\nd' - myFixture.performEditorAction IdeActions.ACTION_COPY - myFixture.configureByText 'b.groovy', 'def x = "smth"' - myFixture.performEditorAction IdeActions.ACTION_PASTE - myFixture.checkResult 'def x = "smtha\\n" +\n "d"' + doTest 'a.txt', 'a\nd', 'def x = "smth"', 'def x = "smtha\\n" +\n "d"' + } + + public void testGStringEolReplace() throws Exception { + doTest 'a.txt', + '''first +second +''', + '''def x = """ +foo +"""''', + '''def x = """ +first +second +"""''' } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy index 79a28143d451..186e7c9b77d4 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy @@ -211,6 +211,22 @@ cl.parseClass('''$mcText''', 'MyClass.groovy').foo(2) eval 'a', '2' } } + + void testAnonymousClassInScript() { + myFixture.addFileToProject('Foo.groovy', '''\ +new Runnable() { + void run() { + print 'foo' + } +}.run() + +''') + addBreakpoint 'Foo.groovy', 2 + runDebugger 'Foo', { + waitForBreakpoint() + eval '1+1', '2' + } + } private def addBreakpoint(String fileName, int line) { VirtualFile file = null diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/ErrorAnalyzer.java b/plugins/ui-designer/src/com/intellij/uiDesigner/ErrorAnalyzer.java index 1a1987c1c942..8eef6609d08a 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/ErrorAnalyzer.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/ErrorAnalyzer.java @@ -80,22 +80,26 @@ public final class ErrorAnalyzer { @Nullable final GuiEditor editor, @NotNull final IRootContainer rootContainer, @Nullable final ProgressIndicator progress) { + if (module.isDisposed()) { + return; + } + // 1. Validate class to bind final String classToBind = rootContainer.getClassToBind(); final PsiClass psiClass; - if(classToBind != null){ + if (classToBind != null) { psiClass = FormEditingUtil.findClassToBind(module, classToBind); - if(psiClass == null){ + if (psiClass == null) { final QuickFix[] fixes = editor != null ? new QuickFix[]{new CreateClassToBindFix(editor, classToBind)} : QuickFix.EMPTY_ARRAY; final ErrorInfo errorInfo = new ErrorInfo(null, null, UIDesignerBundle.message("error.class.does.not.exist", classToBind), HighlightDisplayLevel.ERROR, fixes); rootContainer.putClientProperty(CLIENT_PROP_CLASS_TO_BIND_ERROR, errorInfo); } - else{ + else { rootContainer.putClientProperty(CLIENT_PROP_CLASS_TO_BIND_ERROR, null); } } - else{ + else { rootContainer.putClientProperty(CLIENT_PROP_CLASS_TO_BIND_ERROR, null); psiClass = null; } @@ -116,13 +120,13 @@ public final class ErrorAnalyzer { final String binding = component.getBinding(); // a. Check that field exists and field is not static - if(psiClass != null && binding != null) { + if (psiClass != null && binding != null) { if (validateFieldInClass(component, binding, component.getComponentClassName(), psiClass, editor, module)) return true; } // b. Check that binding is unique if (binding != null) { - if(usedBindings.contains(binding)){ + if (usedBindings.contains(binding)) { // TODO[vova] implement component.putClientProperty( CLIENT_PROP_BINDING_ERROR, @@ -162,14 +166,14 @@ public final class ErrorAnalyzer { // Clear previous error (if any) component.putClientProperty(CLIENT_PROP_ERROR_ARRAY, null); - if(!(component instanceof IContainer)){ + if (!(component instanceof IContainer)) { return true; } final IContainer container = (IContainer)component; - if(container instanceof IRootContainer){ + if (container instanceof IRootContainer) { final IRootContainer rootContainer = (IRootContainer)container; - if(rootContainer.getComponentCount() > 1){ + if (rootContainer.getComponentCount() > 1) { // TODO[vova] implement putError(component, new ErrorInfo( component, null, UIDesignerBundle.message("error.multiple.toplevel.components"), @@ -178,13 +182,13 @@ public final class ErrorAnalyzer { )); } } - else if(container.isXY() && container.getComponentCount() > 0){ + else if (container.isXY() && container.getComponentCount() > 0) { // TODO[vova] implement putError(component, new ErrorInfo( - component, null, UIDesignerBundle.message("error.panel.not.laid.out"), - HighlightDisplayLevel.ERROR, - QuickFix.EMPTY_ARRAY - ) + component, null, UIDesignerBundle.message("error.panel.not.laid.out"), + HighlightDisplayLevel.ERROR, + QuickFix.EMPTY_ARRAY + ) ); } return true; @@ -199,14 +203,14 @@ public final class ErrorAnalyzer { if (formPsiFile != null && rootContainer instanceof RadRootContainer) { final List formInspectionTools = new ArrayList(); final FormInspectionTool[] registeredFormInspections = Extensions.getExtensions(FormInspectionTool.EP_NAME); - for(FormInspectionTool formInspectionTool: registeredFormInspections) { + for (FormInspectionTool formInspectionTool : registeredFormInspections) { if (formInspectionTool.isActive(formPsiFile) && !rootContainer.isInspectionSuppressed(formInspectionTool.getShortName(), null)) { formInspectionTools.add(formInspectionTool); } } if (formInspectionTools.size() > 0 && editor != null) { - for(FormInspectionTool tool: formInspectionTools) { + for (FormInspectionTool tool : formInspectionTools) { tool.startCheckForm(rootContainer); } FormEditingUtil.iterate( @@ -215,7 +219,7 @@ public final class ErrorAnalyzer { public boolean visit(final RadComponent component) { if (progress != null && progress.isCanceled()) return false; - for(FormInspectionTool tool: formInspectionTools) { + for (FormInspectionTool tool : formInspectionTools) { if (rootContainer.isInspectionSuppressed(tool.getShortName(), component.getId())) continue; ErrorInfo[] errorInfos = tool.checkComponent(editor, component); if (errorInfos != null) { @@ -231,7 +235,7 @@ public final class ErrorAnalyzer { } } ); - for(FormInspectionTool tool: formInspectionTools) { + for (FormInspectionTool tool : formInspectionTools) { tool.doneCheckForm(rootContainer); } } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentPtrDescriptor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentPtrDescriptor.java index 5ec5045b6321..6db460c216dd 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentPtrDescriptor.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentPtrDescriptor.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.uiDesigner.radComponents.RadComponent; import com.intellij.uiDesigner.radComponents.RadRootContainer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * @author Anton Katilin @@ -39,9 +40,9 @@ final class ComponentPtrDescriptor extends NodeDescriptor { myPtr=ptr; } - public boolean update(){ + public boolean update() { myPtr.validate(); - if(!myPtr.isValid()){ + if(!myPtr.isValid()) { myPtr=null; return true; } @@ -49,7 +50,10 @@ final class ComponentPtrDescriptor extends NodeDescriptor { final String oldBinding = myBinding; final String oldTitle = myTitle; final RadComponent component = myPtr.getComponent(); - if(component instanceof RadRootContainer){ + if (component.getModule().isDisposed()) { + return false; + } + if(component instanceof RadRootContainer) { myBinding = ((RadRootContainer)component).getClassToBind(); } else{ @@ -59,6 +63,7 @@ final class ComponentPtrDescriptor extends NodeDescriptor { return !Comparing.equal(oldBinding,myBinding) || !Comparing.equal(oldTitle, myTitle); } + @Nullable public RadComponent getComponent() { return myPtr != null ? myPtr.getComponent() : null; } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentTreeStructure.java b/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentTreeStructure.java index a7b0d9124234..100bff453c98 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentTreeStructure.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentTreeStructure.java @@ -42,13 +42,8 @@ final class ComponentTreeStructure extends AbstractTreeStructure{ private final GuiEditor myEditor; public ComponentTreeStructure(@NotNull final GuiEditor editor){ - myRootElement=new Object() { - @Override - public String toString() { - return "root of component tree structure " + ComponentTreeStructure.this.toString(); - } - }; - myEditor=editor; + myRootElement = new ComponentTreeStructureRoot(); + myEditor = editor; } public Object getRootElement(){ @@ -107,7 +102,7 @@ final class ComponentTreeStructure extends AbstractTreeStructure{ } public Object getParentElement(final Object element){ - if(element==myRootElement){ + if (element instanceof ComponentTreeStructureRoot) { return null; } else if (element instanceof LwInspectionSuppression[] || element instanceof RadButtonGroup[]) { @@ -180,4 +175,11 @@ final class ComponentTreeStructure extends AbstractTreeStructure{ public boolean hasSomethingToCommit(){ return false; } + + private class ComponentTreeStructureRoot { + @Override + public String toString() { + return "root of component tree structure " + ComponentTreeStructure.this.toString(); + } + } } diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 6345c2431ea2..453e54c19a68 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -121,6 +121,7 @@ + diff --git a/xml/impl/src/com/intellij/codeInsight/folding/impl/XmlElementSignatureProvider.java b/xml/impl/src/com/intellij/codeInsight/folding/impl/XmlElementSignatureProvider.java index 912a73751bcd..2d7f7e0439f0 100644 --- a/xml/impl/src/com/intellij/codeInsight/folding/impl/XmlElementSignatureProvider.java +++ b/xml/impl/src/com/intellij/codeInsight/folding/impl/XmlElementSignatureProvider.java @@ -24,6 +24,7 @@ import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.xml.util.HtmlUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.StringTokenizer; @@ -58,7 +59,12 @@ public class XmlElementSignatureProvider extends AbstractElementSignatureProvide } @Override - protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file, @NotNull PsiElement parent, @NotNull String type, @NotNull StringTokenizer tokenizer) { + protected PsiElement restoreBySignatureTokens(@NotNull PsiFile file, + @NotNull PsiElement parent, + @NotNull String type, + @NotNull StringTokenizer tokenizer, + @Nullable StringBuilder processingInfoStorage) + { if (type.equals("tag")) { String name = tokenizer.nextToken(); diff --git a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java index a03324dcbd16..e9493f197f39 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java +++ b/xml/impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java @@ -79,7 +79,6 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { private volatile String myLocalName; private volatile XmlAttribute[] myAttributes = null; private volatile Map myAttributeValueMap = null; - private CachedValue myTags = null; private volatile XmlTagValue myValue = null; private volatile Map> myNSDescriptorsMap = null; private volatile String myCachedNamespace; @@ -121,7 +120,6 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { myHaveNamespaceDeclarations = false; myValue = null; myNSDescriptorsMap = null; - myTags = null; super.clearCaches(); } @@ -608,29 +606,28 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag { @NotNull public XmlTag[] getSubTags() { - CachedValue value = myTags; - if (value == null) { - value = myTags = CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider() { - @Override - public Result compute() { - final List result = new ArrayList(); + return CachedValuesManager.getManager(getProject()).getCachedValue(this, new CachedValueProvider() { + @Override + public Result compute() { + final List result = new ArrayList(); - fillSubTags(result); + fillSubTags(result); - final int s = result.size(); - XmlTag[] tags = s > 0 ? ContainerUtil.toArray(result, new XmlTag[s]) : EMPTY; - return Result.create(tags, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + final int s = result.size(); + XmlTag[] tags = s > 0 ? ContainerUtil.toArray(result, new XmlTag[s]) : EMPTY; + return Result.create(tags, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); - } - }, false); - } - return value.getValue(); + } + }); } protected void fillSubTags(final List result) { processElements(new PsiElementProcessor() { public boolean execute(@NotNull PsiElement element) { - if (element instanceof XmlTag) result.add((XmlTag)element); + if (element instanceof XmlTag) { + assert element.isValid(); + result.add((XmlTag)element); + } return true; } }, this); diff --git a/xml/impl/src/com/intellij/xml/util/XmlUtil.java b/xml/impl/src/com/intellij/xml/util/XmlUtil.java index dcdec7836600..82853600c7cc 100644 --- a/xml/impl/src/com/intellij/xml/util/XmlUtil.java +++ b/xml/impl/src/com/intellij/xml/util/XmlUtil.java @@ -57,10 +57,7 @@ import com.intellij.psi.impl.source.xml.XmlEntityRefImpl; import com.intellij.psi.scope.processor.FilterElementProcessor; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.CachedValue; -import com.intellij.psi.util.CachedValueProvider; -import com.intellij.psi.util.CachedValuesManager; -import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.*; import com.intellij.psi.xml.*; import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; @@ -672,12 +669,13 @@ public class XmlUtil { final PsiElement[] inclusion = CachedValuesManager.getManager(xincludeTag.getProject()).getCachedValue(xincludeTag, new CachedValueProvider() { public Result compute() { - return RecursionManager.doPreventingRecursion(xincludeTag, true, new Computable>() { + PsiElement[] result = RecursionManager.doPreventingRecursion(xincludeTag, true, new NullableComputable() { @Override - public Result compute() { + public PsiElement[] compute() { return computeInclusion(xincludeTag); } }); + return Result.create(result, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); } }); @@ -690,39 +688,26 @@ public class XmlUtil { return true; } - private static final Key>> COPY_CACHE = Key.create("XInclude.CopyCache"); - - private static CachedValueProvider.Result computeInclusion(final XmlTag xincludeTag) { - final PsiFile containingFile = xincludeTag.getContainingFile(); - + @Nullable + private static PsiElement[] computeInclusion(final XmlTag xincludeTag) { final XmlFile included = XmlIncludeHandler.resolveXIncludeFile(xincludeTag); final XmlDocument document = included != null ? included.getDocument() : null; final XmlTag rootTag = document != null ? document.getRootTag() : null; if (rootTag != null) { final String xpointer = xincludeTag.getAttributeValue("xpointer", XINCLUDE_URI); - Trinity> cached = xincludeTag.getUserData(COPY_CACHE); - if (cached == null || !cached.first.equals(included) || !Comparing.equal(cached.second, xpointer)) { - cached = Trinity.create(included, xpointer, CachedValuesManager.getManager(xincludeTag.getProject()).createCachedValue(new CachedValueProvider() { - @Override - public Result compute() { - final XmlTag[] includeTag = extractXpointer(rootTag, xpointer); - PsiElement[] result = new PsiElement[includeTag.length]; - for (int i = 0; i < includeTag.length; i++) { - XmlTag xmlTag = includeTag[i]; - final PsiElement psiElement = xmlTag.copy(); - psiElement.putUserData(XmlElement.INCLUDING_ELEMENT, xincludeTag.getParentTag()); - psiElement.putUserData(ORIGINAL_ELEMENT, PsiAnchor.create(xmlTag)); - result[i] = psiElement; - } - return Result.create(result, included); - } - }, false)); - xincludeTag.putUserData(COPY_CACHE, cached); + final XmlTag[] includeTag = extractXpointer(rootTag, xpointer); + PsiElement[] result = new PsiElement[includeTag.length]; + for (int i = 0; i < includeTag.length; i++) { + XmlTag xmlTag = includeTag[i]; + final PsiElement psiElement = xmlTag.copy(); + psiElement.putUserData(XmlElement.INCLUDING_ELEMENT, xincludeTag.getParentTag()); + psiElement.putUserData(ORIGINAL_ELEMENT, PsiAnchor.create(xmlTag)); + result[i] = psiElement; } - return new CachedValueProvider.Result(cached.third.getValue(), containingFile); + return result; } - return new CachedValueProvider.Result(null, containingFile); + return null; } private static XmlTag[] extractXpointer(XmlTag rootTag, @Nullable final String xpointer) {