diff --git a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java index d0cf979c2905..75320bf17347 100644 --- a/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java +++ b/java/java-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilder.java @@ -17,7 +17,7 @@ package com.intellij.codeInsight.folding.impl; import com.intellij.codeInsight.folding.JavaCodeFoldingSettings; import com.intellij.lang.ASTNode; -import com.intellij.lang.folding.FoldingBuilderEx; +import com.intellij.lang.folding.CustomFoldingBuilder; import com.intellij.lang.folding.FoldingDescriptor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -33,6 +33,7 @@ import com.intellij.psi.impl.source.PsiClassReferenceType; import com.intellij.psi.impl.source.SourceTreeToPsiMap; import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod; import com.intellij.psi.impl.source.tree.JavaDocElementType; +import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PropertyUtil; @@ -47,25 +48,27 @@ import org.jetbrains.annotations.Nullable; import java.util.*; -public class JavaFoldingBuilder extends FoldingBuilderEx implements DumbAware { +public class JavaFoldingBuilder extends CustomFoldingBuilder implements DumbAware { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.folding.impl.JavaFoldingBuilder"); private static final String SMILEY = "<~>"; - @NotNull - public FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement element, @NotNull Document document, boolean quick) { - if (!(element instanceof PsiJavaFile)) { - return FoldingDescriptor.EMPTY; + @Override + protected void buildLanguageFoldRegions(@NotNull List descriptors, + @NotNull PsiElement root, + @NotNull Document document, + boolean quick) { + if (!(root instanceof PsiJavaFile)) { + return; } - PsiJavaFile file = (PsiJavaFile) element; + PsiJavaFile file = (PsiJavaFile) root; - List result = new ArrayList(); PsiImportList importList = file.getImportList(); if (importList != null) { PsiImportStatementBase[] statements = importList.getAllImportStatements(); if (statements.length > 1) { final TextRange rangeToFold = getRangeToFold(importList); if (rangeToFold != null && rangeToFold.getLength() > 1) { - result.add(new FoldingDescriptor(importList, rangeToFold)); + descriptors.add(new FoldingDescriptor(importList, rangeToFold)); } } } @@ -73,7 +76,7 @@ public class JavaFoldingBuilder extends FoldingBuilderEx implements DumbAware { PsiClass[] classes = file.getClasses(); for (PsiClass aClass : classes) { ProgressManager.checkCanceled(); - addElementsToFold(result, aClass, document, true, quick); + addElementsToFold(descriptors, aClass, document, true, quick); } TextRange range = getFileHeader(file); @@ -94,10 +97,8 @@ public class JavaFoldingBuilder extends FoldingBuilderEx implements DumbAware { anchorElementToUse = candidate; } } - result.add(new FoldingDescriptor(anchorElementToUse, range)); + descriptors.add(new FoldingDescriptor(anchorElementToUse, range)); } - - return result.toArray(new FoldingDescriptor[result.size()]); } private void addElementsToFold(List list, PsiClass aClass, Document document, boolean foldJavaDocs, boolean quick) { @@ -160,14 +161,14 @@ public class JavaFoldingBuilder extends FoldingBuilderEx implements DumbAware { else if (child instanceof PsiClass) { addElementsToFold(list, (PsiClass)child, document, true, quick); } - else if (child instanceof PsiComment) { + else if (child instanceof PsiComment && !isCustomRegionStart(child.getNode()) && !isCustomRegionEnd(child.getNode())) { addCommentFolds((PsiComment)child, processedComments, list); } } } - @NotNull - public String getPlaceholderText(@NotNull final ASTNode node) { + @Override + protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) { return getPlaceholderText(SourceTreeToPsiMap.treeElementToPsi(node)); } @@ -196,7 +197,8 @@ public class JavaFoldingBuilder extends FoldingBuilderEx implements DumbAware { return "..."; } - public boolean isCollapsedByDefault(@NotNull final ASTNode node) { + @Override + protected boolean isRegionCollapsedByDefault(@NotNull ASTNode node) { final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(node); JavaCodeFoldingSettings settings = JavaCodeFoldingSettings.getInstance(); if (element instanceof PsiNewExpression || element instanceof PsiJavaToken) { @@ -734,5 +736,16 @@ public class JavaFoldingBuilder extends FoldingBuilderEx implements DumbAware { return false; } } + + @Override + protected boolean isCustomFoldingCandidate(ASTNode node) { + return node.getElementType() == JavaTokenType.END_OF_LINE_COMMENT; + } + + @Override + protected boolean isCustomFoldingRoot(ASTNode node) { + IElementType nodeType = node.getElementType(); + return nodeType == JavaElementType.CLASS || nodeType == JavaElementType.CODE_BLOCK; + } } diff --git a/java/java-tests/testData/codeInsight/folding/CustomFolding.java b/java/java-tests/testData/codeInsight/folding/CustomFolding.java new file mode 100644 index 000000000000..d68f535f79dd --- /dev/null +++ b/java/java-tests/testData/codeInsight/folding/CustomFolding.java @@ -0,0 +1,17 @@ +public class Test { + // + private int x; + private int y; + // + + // + private void doSomething() { + StringBuilder s = new StringBuilder(); + // + s.append("a"); + s.append("b"); + // + System.out.println(s.toString()); + } + // +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy index 7c5c84e11a6d..5797be458246 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -133,6 +133,10 @@ class Test { assertTrue closureStartFold.expanded assertTrue closureEndFold.expanded } + + public void testCustomFolding() { + myFixture.testFolding("$PathManagerEx.testDataPath/codeInsight/folding/${getTestName(false)}.java"); + } private def configure(String text) { myFixture.configureByText("a.java", text) diff --git a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java index e6803f563670..1b5822fbe3e2 100644 --- a/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java +++ b/platform/lang-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java @@ -29,7 +29,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D List descriptors = new ArrayList(); if (CustomFoldingProvider.getAllProviders().length > 0) { myDefaultProvider = null; - addCustomFoldingRegionsRecursively(root.getNode(), descriptors); + addCustomFoldingRegionsRecursively(null, root.getNode(), descriptors); } buildLanguageFoldRegions(descriptors, root, document, quick); return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); @@ -54,30 +54,32 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D @NotNull PsiElement root, @NotNull Document document, boolean quick); - - private void addCustomFoldingRegionsRecursively(@NotNull ASTNode node, List descriptors) { - Stack customFoldingNodesStack = new Stack(1); + + private void addCustomFoldingRegionsRecursively(@Nullable FoldingStack foldingStack, + @NotNull ASTNode node, + List descriptors) { + FoldingStack localFoldingStack = isCustomFoldingRoot(node) || foldingStack == null ? new FoldingStack(node) : foldingStack; for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) { if (isCustomRegionStart(child)) { - customFoldingNodesStack.push(child); + localFoldingStack.push(child); } else if (isCustomRegionEnd(child)) { - if (!customFoldingNodesStack.isEmpty()) { - ASTNode startNode = customFoldingNodesStack.pop(); + if (!localFoldingStack.isEmpty()) { + ASTNode startNode = localFoldingStack.pop(); int startOffset = startNode.getTextRange().getStartOffset(); TextRange range = new TextRange(startOffset, child.getTextRange().getEndOffset()); - descriptors.add(new FoldingDescriptor(node, range)); + descriptors.add(new FoldingDescriptor(localFoldingStack.getOwner(), range)); } } else { - addCustomFoldingRegionsRecursively(child, descriptors); + addCustomFoldingRegionsRecursively(localFoldingStack, child, descriptors); } } } @Override public final String getPlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) { - if (mayContainCustomFoldings(node)) { + if (isCustomFoldingRoot(node)) { PsiFile file = node.getPsi().getContainingFile(); PsiElement contextElement = file.findElementAt(range.getStartOffset()); if (contextElement != null && isCustomFoldingCandidate(contextElement.getNode())) { @@ -103,7 +105,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D @Override public final boolean isCollapsedByDefault(@NotNull ASTNode node) { // TODO: Modify Folding API and pass here folding range. - if (mayContainCustomFoldings(node)) { + if (isCustomFoldingRoot(node)) { for (ASTNode child = node.getFirstChildNode(); child != null; child = child.getTreeNext()) { if (isCustomRegionStart(child)) { String childText = child.getText(); @@ -178,14 +180,28 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements D } /** - * Returns true if the node may contain custom foldings in its immediate child nodes. By default any node will be checked for custom - * foldings but for performance reasons it makes sense to override this method to check only the nodes which actually may contain - * custom folding nodes (for example, group statements). + * Checks if the node is used as custom folding root. Any custom folding elements inside the root are considered to be at the same level + * even if they are located at different levels of PSI tree. Collected folding descriptors always contain only root elements with + * appropriate ranges. The method returns true if the node has any child elements. * * @param node The node to check. - * @return True if the node may contain custom folding nodes (true by default). + * @return True if the node is a root for custom foldings. */ - protected boolean mayContainCustomFoldings(ASTNode node) { - return true; + protected boolean isCustomFoldingRoot(ASTNode node) { + return node.getFirstChildNode() != null; + } + + private static class FoldingStack extends Stack { + private ASTNode owner; + + public FoldingStack(@NotNull ASTNode owner) { + super(1); + this.owner = owner; + } + + @NotNull + public ASTNode getOwner() { + return this.owner; + } } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java index 08a6cbf6eee0..151b63aa46b2 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/InplaceRefactoring.java @@ -25,12 +25,11 @@ import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.codeInsight.lookup.impl.LookupImpl; import com.intellij.codeInsight.template.*; -import com.intellij.codeInsight.template.Result; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.injected.editor.VirtualFileWindow; import com.intellij.openapi.actionSystem.Shortcut; -import com.intellij.openapi.application.*; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.command.impl.FinishMarkAction; @@ -41,6 +40,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.extensions.Extensions; @@ -599,7 +599,7 @@ public abstract class InplaceRefactoring { if (contains(stringUsage.second.shiftRight(element.getTextRange().getStartOffset()), offset)) return element; } - LOG.assertTrue(false); + LOG.error(nameIdentifier); return null; } @@ -699,9 +699,14 @@ public abstract class InplaceRefactoring { } finally { if (!bind) { - FinishMarkAction.finish(myProject, myEditor, myMarkAction); - if (myBeforeRevert != null) { - myBeforeRevert.dispose(); + try { + ((EditorImpl)myEditor).stopDumb(); + } + finally { + FinishMarkAction.finish(myProject, myEditor, myMarkAction); + if (myBeforeRevert != null) { + myBeforeRevert.dispose(); + } } } } 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 39358467cd74..83a651f15028 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 @@ -22,6 +22,7 @@ import com.intellij.openapi.command.impl.FinishMarkAction; import com.intellij.openapi.command.impl.StartMarkAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; @@ -207,9 +208,14 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { } } finally { - FinishMarkAction.finish(myProject, myEditor, markAction); - if (myBeforeRevert != null) { - myEditor.getCaretModel().moveToOffset(myBeforeRevert.getEndOffset()); + try { + ((EditorImpl)myEditor).stopDumb(); + } + finally { + FinishMarkAction.finish(myProject, myEditor, markAction); + if (myBeforeRevert != null) { + myEditor.getCaretModel().moveToOffset(myBeforeRevert.getEndOffset()); + } } } } @@ -223,6 +229,7 @@ public class MemberInplaceRenamer extends VariableInplaceRenamer { public void finish(boolean success) { super.finish(success); if (success) { + ((EditorImpl)myEditor).startDumb(); revertState(); } } diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java index 32f28bee2eb3..0268a3086787 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java +++ b/platform/lang-impl/src/com/intellij/refactoring/rename/inplace/VariableInplaceRenamer.java @@ -27,6 +27,7 @@ import com.intellij.openapi.command.impl.FinishMarkAction; import com.intellij.openapi.command.impl.StartMarkAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.editor.impl.EditorImpl; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; @@ -83,7 +84,6 @@ public class VariableInplaceRenamer extends InplaceRefactoring { final String initialName, final String oldName) { super(editor, elementToRename, project, initialName, oldName); - } public boolean performInplaceRename() { @@ -114,7 +114,8 @@ public class VariableInplaceRenamer extends InplaceRefactoring { final PsiFile containingFile) { if (appendAdditionalElement(stringUsages)) { return super.buildTemplateAndStart(refs, stringUsages, scope, containingFile); - } else { + } + else { final RenameChooser renameChooser = new RenameChooser(myEditor) { @Override protected void runRenameTemplate(Collection> stringUsages) { @@ -178,63 +179,79 @@ public class VariableInplaceRenamer extends InplaceRefactoring { } } + protected void renameSynthetic(String newName) { + } + protected void performRefactoringRename(final String newName, final StartMarkAction markAction) { try { - performAutomaticRename(newName); - } - finally { - FinishMarkAction.finish(myProject, myEditor, markAction); - } - } + new WriteCommandAction(myProject, getCommandName()) { + @Override + protected void run(Result result) throws Throwable { + renameSynthetic(newName); + } + }.execute(); - protected void performAutomaticRename(String newName) { - PsiNamedElement elementToRename = getVariable(); - for (AutomaticRenamerFactory renamerFactory : Extensions.getExtensions(AutomaticRenamerFactory.EP_NAME)) { - if (renamerFactory.isApplicable(elementToRename)) { - final List usages = new ArrayList(); - final AutomaticRenamer renamer = renamerFactory.createRenamer(elementToRename, newName, new ArrayList()); - if (renamer.hasAnythingToRename()) { - if (!ApplicationManager.getApplication().isUnitTestMode()) { - final AutomaticRenamingDialog renamingDialog = new AutomaticRenamingDialog(myProject, renamer); - renamingDialog.show(); - if (!renamingDialog.isOK()) return; - } - - final Runnable runnable = new Runnable() { - public void run() { - renamer.findUsages(usages, false, false); + PsiNamedElement elementToRename = getVariable(); + for (AutomaticRenamerFactory renamerFactory : Extensions.getExtensions(AutomaticRenamerFactory.EP_NAME)) { + if (renamerFactory.isApplicable(elementToRename)) { + final List usages = new ArrayList(); + final AutomaticRenamer renamer = + renamerFactory.createRenamer(elementToRename, newName, new ArrayList()); + if (renamer.hasAnythingToRename()) { + if (!ApplicationManager.getApplication().isUnitTestMode()) { + final AutomaticRenamingDialog renamingDialog = new AutomaticRenamingDialog(myProject, renamer); + renamingDialog.show(); + if (!renamingDialog.isOK()) return; } - }; - if (!ProgressManager.getInstance() - .runProcessWithProgressSynchronously(runnable, RefactoringBundle.message("searching.for.variables"), true, myProject)) { - return; - } - - if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, PsiUtilCore.toPsiElementArray(renamer.getElements()))) return; - final UsageInfo[] usageInfos = usages.toArray(new UsageInfo[usages.size()]); - final MultiMap classified = RenameProcessor.classifyUsages(renamer.getElements(), usageInfos); - for (final PsiNamedElement element : renamer.getElements()) { - new WriteCommandAction(myProject, getCommandName()) { - @Override - protected void run(Result result) throws Throwable { - final String newElementName = renamer.getNewName(element); - if (newElementName != null) { - final Collection infos = classified.get(element); - RenameUtil.doRenameGenericNamedElement(element, newElementName, infos.toArray(new UsageInfo[infos.size()]), null); - } + final Runnable runnable = new Runnable() { + public void run() { + renamer.findUsages(usages, false, false); } - }.execute(); + }; + + if (!ProgressManager.getInstance() + .runProcessWithProgressSynchronously(runnable, RefactoringBundle.message("searching.for.variables"), true, myProject)) { + return; + } + + if (!CommonRefactoringUtil.checkReadOnlyStatus(myProject, PsiUtilCore.toPsiElementArray(renamer.getElements()))) return; + final UsageInfo[] usageInfos = usages.toArray(new UsageInfo[usages.size()]); + final MultiMap classified = RenameProcessor.classifyUsages(renamer.getElements(), usageInfos); + for (final PsiNamedElement element : renamer.getElements()) { + new WriteCommandAction(myProject, getCommandName()) { + @Override + protected void run(Result result) throws Throwable { + final String newElementName = renamer.getNewName(element); + if (newElementName != null) { + final Collection infos = classified.get(element); + RenameUtil.doRenameGenericNamedElement(element, newElementName, infos.toArray(new UsageInfo[infos.size()]), null); + } + } + }.execute(); + } } } } } + finally { + try { + ((EditorImpl)myEditor).stopDumb(); + } + finally { + FinishMarkAction.finish(myProject, myEditor, markAction); + } + } } @Override protected String getCommandName() { PsiNamedElement variable = getVariable(); + if (variable == null) { + LOG.error(myElementToRename); + return "Rename"; + } return RefactoringBundle.message("renaming.0.1.to.2", UsageViewUtil.getType(variable), UsageViewUtil.getDescriptiveName(variable), variable.getName()); } @@ -277,7 +294,7 @@ public class VariableInplaceRenamer extends InplaceRefactoring { } private boolean isIdentifier(final String newName) { - + final NamesValidator namesValidator = LanguageNamesValidation.INSTANCE.forLanguage(myLanguage); return namesValidator == null || namesValidator.isIdentifier(newName, myProject); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java index 5d650e62dacc..477c546cb56d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java @@ -19,15 +19,15 @@ import com.intellij.ide.IdeEventQueue; import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.PlatformDataKeys; -import com.intellij.openapi.editor.VisualPosition; -import com.intellij.ui.components.Magnificator; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.impl.ApplicationImpl; +import com.intellij.openapi.editor.VisualPosition; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.ui.Queryable; import com.intellij.openapi.ui.TypingTarget; import com.intellij.openapi.util.ActionCallback; +import com.intellij.ui.components.Magnificator; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; @@ -147,7 +147,7 @@ public class EditorComponentImpl extends JComponent implements Scrollable, DataP ((Graphics2D)g).setComposite(AlphaComposite.Src); UISettings.setupAntialiasing(g); - myEditor.paint(g); + myEditor.paint((Graphics2D)g); } finally { ((ApplicationImpl)ApplicationManager.getApplication()).editorPaintFinish(); 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 7b96a465a25f..f286def57c1f 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 @@ -109,6 +109,7 @@ import java.awt.dnd.DropTargetDropEvent; import java.awt.event.*; import java.awt.font.TextHitInfo; import java.awt.im.InputMethodRequests; +import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.lang.reflect.Field; @@ -129,6 +130,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi public static final Key> EDITABLE_AREA_MARKER = Key.create("editable.area.marker"); private static final boolean HONOR_CAMEL_HUMPS_ON_TRIPLE_CLICK = Boolean.parseBoolean(System.getProperty("idea.honor.camel.humps.on.triple.click")); + public static final Key BUFFER = Key.create("buffer"); private final DocumentImpl myDocument; private final JPanel myPanel; @@ -1649,7 +1651,40 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi return isReleased; } - void paint(Graphics g) { + public void stopDumb() { + putUserData(BUFFER, null); + } + + /** + * {@link #stopDumb()} must be performed in finally + */ + public void startDumb() { + final EditorComponentImpl component = getContentComponent(); + final Dimension dimension = component.getSize(); + BufferedImage image = new BufferedImage(dimension.width, dimension.height, BufferedImage.TYPE_INT_RGB); + final Graphics2D graphics = image.createGraphics(); + graphics.setClip(0, 0, dimension.width, dimension.height); + paint(graphics); + putUserData(BUFFER, image); + } + + void paint(Graphics2D g) { + Rectangle clip = g.getClipBounds(); + + if (clip == null) { + return; + } + + if (Registry.is("editor.dumb.mode.available")) { + final BufferedImage buffer = getUserData(BUFFER); + if (buffer != null) { + final Point point = new Point(clip.x, clip.y); + SwingUtilities.convertPointFromScreen(point, getContentComponent()); + g.drawImage(buffer, null, 0, 0); + return; + } + } + startOptimizedScrolling(); if (myUpdateCursor) { @@ -1657,11 +1692,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myUpdateCursor = false; } - Rectangle clip = g.getClipBounds(); - - if (clip == null) { - return; - } Rectangle visibleArea = getScrollingModel().getVisibleArea(); if (visibleArea == null) { diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 9f6a55986f07..e094693bc48b 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -187,3 +187,5 @@ disable.toolwindow.overlayed=true disable.toolwindow.overlayed.description=Disable transparent toolwindow stripes core.pooled.threads=20 + +editor.dumb.mode.available=true \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/inplace/GrVariableInplaceRenamer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/inplace/GrVariableInplaceRenamer.java index 271214f7fc09..688af8e84329 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/inplace/GrVariableInplaceRenamer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/rename/inplace/GrVariableInplaceRenamer.java @@ -15,10 +15,6 @@ */ package org.jetbrains.plugins.groovy.refactoring.rename.inplace; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.command.impl.FinishMarkAction; -import com.intellij.openapi.command.impl.StartMarkAction; import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.PsiNamedElement; @@ -39,27 +35,15 @@ public class GrVariableInplaceRenamer extends VariableInplaceRenamer { super(elementToRename, editor); } - @Override - protected void performRefactoringRename(final String newName, StartMarkAction markAction) { - try { - new WriteCommandAction(myProject, getCommandName()) { - @Override - protected void run(Result result) throws Throwable { - PsiNamedElement elementToRename = getVariable(); - if (elementToRename instanceof ClosureSyntheticParameter && !"it".equals(newName)) { - final GrClosableBlock closure = ((ClosureSyntheticParameter)elementToRename).getClosure(); - final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myProject); - final PsiType type = ((ClosureSyntheticParameter)elementToRename).getTypeGroovy(); - final GrParameter newParam = factory.createParameter(newName, TypesUtil.unboxPrimitiveTypeWrapper(type)); - final GrParameter added = closure.addParameter(newParam); - GrReferenceAdjuster.shortenReferences(added); - } - } - }.execute(); - performAutomaticRename(newName); - } - finally { - FinishMarkAction.finish(myProject, myEditor, markAction); + protected void renameSynthetic(String newName) { + PsiNamedElement elementToRename = getVariable(); + if (elementToRename instanceof ClosureSyntheticParameter && !"it".equals(newName)) { + final GrClosableBlock closure = ((ClosureSyntheticParameter)elementToRename).getClosure(); + final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myProject); + final PsiType type = ((ClosureSyntheticParameter)elementToRename).getTypeGroovy(); + final GrParameter newParam = factory.createParameter(newName, TypesUtil.unboxPrimitiveTypeWrapper(type)); + final GrParameter added = closure.addParameter(newParam); + GrReferenceAdjuster.shortenReferences(added); } } }