From ea7daa05cc83335cf28ae498e5b9b65f9b1526f0 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 3 Mar 2016 16:15:39 +0100 Subject: [PATCH 01/11] inline superclass: skip constructors without body, e.g. kotlin default constructors (IDEA-152476) --- .../InlineSuperClassRefactoringProcessor.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java index 23a3c59b2ae0..0eff2c9ecd4e 100644 --- a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java @@ -171,25 +171,26 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori final PsiMethod[] superConstructors = mySuperClass.getConstructors(); for (PsiMethod constructor : targetClass.getConstructors()) { final PsiCodeBlock constrBody = constructor.getBody(); - LOG.assertTrue(constrBody != null); - final PsiStatement[] statements = constrBody.getStatements(); - if (statements.length > 0) { - final PsiStatement firstConstrStatement = statements[0]; - if (firstConstrStatement instanceof PsiExpressionStatement) { - final PsiExpression expression = ((PsiExpressionStatement)firstConstrStatement).getExpression(); - if (expression instanceof PsiMethodCallExpression) { - final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)expression).getMethodExpression(); - if (methodExpression.getText().equals(PsiKeyword.SUPER)) { - final PsiMethod superConstructor = ((PsiMethodCallExpression)expression).resolveMethod(); - if (superConstructor != null && superConstructor.getBody() != null) { - usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression)expression)); - continue; + if (constrBody != null) { + final PsiStatement[] statements = constrBody.getStatements(); + if (statements.length > 0) { + final PsiStatement firstConstrStatement = statements[0]; + if (firstConstrStatement instanceof PsiExpressionStatement) { + final PsiExpression expression = ((PsiExpressionStatement)firstConstrStatement).getExpression(); + if (expression instanceof PsiMethodCallExpression) { + final PsiReferenceExpression methodExpression = ((PsiMethodCallExpression)expression).getMethodExpression(); + if (methodExpression.getText().equals(PsiKeyword.SUPER)) { + final PsiMethod superConstructor = ((PsiMethodCallExpression)expression).resolveMethod(); + if (superConstructor != null && superConstructor.getBody() != null) { + usages.add(new InlineSuperCallUsageInfo((PsiMethodCallExpression)expression)); + continue; + } } } } } } - + //insert implicit call to super for (PsiMethod superConstructor : superConstructors) { if (superConstructor.getParameterList().getParametersCount() == 0) { From 20a8fcc015f94bd45a28106546d75a2e514447bc Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 3 Mar 2016 16:41:03 +0100 Subject: [PATCH 02/11] inline local: search for usages in use-scope, accept non-project files (IDEA-152532) --- .../com/intellij/refactoring/inline/InlineLocalHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java index 34ce8e6f4bb6..cd0f28c6aa4d 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineLocalHandler.java @@ -32,7 +32,6 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.wm.WindowManager; import com.intellij.psi.*; import com.intellij.psi.controlFlow.DefUseUtil; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; @@ -78,7 +77,7 @@ public class InlineLocalHandler extends JavaInlineActionHandler { final String localName = local.getName(); - final Query query = ReferencesSearch.search(local, GlobalSearchScope.allScope(project), false); + final Query query = ReferencesSearch.search(local, local.getUseScope()); if (query.findFirst() == null){ LOG.assertTrue(refExpr == null); String message = RefactoringBundle.message("variable.is.never.used", localName); From db30803beedd98f301b605607a28659301f04aee Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 3 Mar 2016 18:24:43 +0100 Subject: [PATCH 03/11] inline superclass: don't start push refactoring (with find usages, etc) inside inline; don't collect usages in all inheritors when at the end only one would be processed (IDEA-152480) --- .../InlineSuperClassRefactoringProcessor.java | 70 +++++++++---------- .../after/Test.java | 2 +- .../AbstractPushDownProcessor.java | 41 ++++++----- 3 files changed, 54 insertions(+), 59 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java index 0eff2c9ecd4e..1c9de953f11f 100644 --- a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java @@ -42,8 +42,10 @@ import com.intellij.refactoring.util.classMembers.MemberInfoStorage; import com.intellij.usageView.UsageInfo; import com.intellij.usageView.UsageViewDescriptor; import com.intellij.util.ArrayUtilRt; +import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.intellij.util.Processor; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; @@ -275,50 +277,44 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori } protected void performRefactoring(@NotNull final UsageInfo[] usages) { - final DocCommentPolicy docPolicy = new DocCommentPolicy(myPolicy); - new PushDownProcessor(mySuperClass, myMemberInfos, docPolicy) { - //push down conflicts are already collected - @Override - protected boolean showConflicts(@NotNull MultiMap conflicts, UsageInfo[] usages) { - return true; - } + try { + final UsageInfo[] infos = ContainerUtil.map2Array(myTargetClasses, UsageInfo.class, new Function() { + @Override + public UsageInfo fun(PsiClass psiClass) { + return new UsageInfo(psiClass); + } + }); + new PushDownProcessor(mySuperClass, myMemberInfos, new DocCommentPolicy(myPolicy)).pushDownToClasses(infos); - @Override - protected void performRefactoring(@NotNull UsageInfo[] pushDownUsages) { - if (myCurrentInheritor != null) { - pushDownToDedicatedClass(myCurrentInheritor); - } else { - super.performRefactoring(pushDownUsages); - } - CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); - for (UsageInfo usageInfo : usages) { - if (!(usageInfo instanceof ReplaceExtendsListUsageInfo || usageInfo instanceof RemoveImportUsageInfo)) { - try { - ((FixableUsageInfo)usageInfo).fixUsage(); - } - catch (IncorrectOperationException e) { - LOG.info(e); - } - } - } - replaceInnerTypeUsages(); - - //postpone broken hierarchy - for (UsageInfo usage : usages) { - if (usage instanceof ReplaceExtendsListUsageInfo || usage instanceof RemoveImportUsageInfo) { - ((FixableUsageInfo)usage).fixUsage(); - } - } - if (myCurrentInheritor == null) { + CommonRefactoringUtil.sortDepthFirstRightLeftOrder(usages); + for (UsageInfo usageInfo : usages) { + if (!(usageInfo instanceof ReplaceExtendsListUsageInfo || usageInfo instanceof RemoveImportUsageInfo)) { try { - mySuperClass.delete(); + ((FixableUsageInfo)usageInfo).fixUsage(); } catch (IncorrectOperationException e) { - LOG.error(e); + LOG.info(e); } } } - }.run(); + + replaceInnerTypeUsages(); + + //postpone broken hierarchy + for (UsageInfo usage : usages) { + if (usage instanceof ReplaceExtendsListUsageInfo || usage instanceof RemoveImportUsageInfo) { + ((FixableUsageInfo)usage).fixUsage(); + } + } + + //delete the class if all refs replaced + if (myCurrentInheritor == null) { + mySuperClass.delete(); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } } @Nullable diff --git a/java/java-tests/testData/refactoring/inlineSuperClass/superConstructorWithFieldInitialization/after/Test.java b/java/java-tests/testData/refactoring/inlineSuperClass/superConstructorWithFieldInitialization/after/Test.java index f95077f47cb6..a9952f3f94a8 100644 --- a/java/java-tests/testData/refactoring/inlineSuperClass/superConstructorWithFieldInitialization/after/Test.java +++ b/java/java-tests/testData/refactoring/inlineSuperClass/superConstructorWithFieldInitialization/after/Test.java @@ -2,6 +2,6 @@ class Test { private final String field; Test(){ - field = "text"; + this.field = "text"; } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/refactoring/memberPushDown/AbstractPushDownProcessor.java b/platform/lang-impl/src/com/intellij/refactoring/memberPushDown/AbstractPushDownProcessor.java index f874021df7b9..43ad20993dca 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/memberPushDown/AbstractPushDownProcessor.java +++ b/platform/lang-impl/src/com/intellij/refactoring/memberPushDown/AbstractPushDownProcessor.java @@ -159,25 +159,7 @@ public abstract class AbstractPushDownProcessor extends BaseRefactoringProcessor @Override protected void performRefactoring(@NotNull UsageInfo[] usages) { try { - myDelegate.prepareToPush(myPushDownData); - final PsiElement sourceClass = myPushDownData.getSourceClass(); - if (mySubClassData != null) { - final PsiElement subClass = myDelegate.createSubClass(sourceClass, mySubClassData); - if (subClass != null) { - myDelegate.pushDownToClass(subClass, myPushDownData); - } - } - else { - for (UsageInfo usage : usages) { - final PsiElement element = usage.getElement(); - if (element != null) { - final PushDownDelegate targetDelegate = PushDownDelegate.findDelegateForTarget(sourceClass, element); - if (targetDelegate != null) { - targetDelegate.pushDownToClass(element, myPushDownData); - } - } - } - } + pushDownToClasses(usages); myDelegate.removeFromSourceClass(myPushDownData); } catch (IncorrectOperationException e) { @@ -185,8 +167,25 @@ public abstract class AbstractPushDownProcessor extends BaseRefactoringProcessor } } - protected void pushDownToDedicatedClass(PsiElement currentInheritor) { + public void pushDownToClasses(@NotNull UsageInfo[] usages) { myDelegate.prepareToPush(myPushDownData); - myDelegate.pushDownToClass(currentInheritor, myPushDownData); + final PsiElement sourceClass = myPushDownData.getSourceClass(); + if (mySubClassData != null) { + final PsiElement subClass = myDelegate.createSubClass(sourceClass, mySubClassData); + if (subClass != null) { + myDelegate.pushDownToClass(subClass, myPushDownData); + } + } + else { + for (UsageInfo usage : usages) { + final PsiElement element = usage.getElement(); + if (element != null) { + final PushDownDelegate targetDelegate = PushDownDelegate.findDelegateForTarget(sourceClass, element); + if (targetDelegate != null) { + targetDelegate.pushDownToClass(element, myPushDownData); + } + } + } + } } } From eeb4e4f49f230f252f550e39f36202206fd6259c Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 3 Mar 2016 18:49:12 +0100 Subject: [PATCH 04/11] inline superclass: proceed arrays (IDEA-152539) --- .../InlineSuperClassRefactoringProcessor.java | 9 ++++++--- .../inlineSuperClass/arrayTypeElements/after/Test.java | 9 +++++++++ .../arrayTypeElements/before/Super.java | 10 ++++++++++ .../arrayTypeElements/before/Test.java | 1 + .../com/intellij/refactoring/InlineSuperClassTest.java | 1 + 5 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/after/Test.java create mode 100644 java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/before/Super.java create mode 100644 java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/before/Test.java diff --git a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java index 1c9de953f11f..8b4ceef2605b 100644 --- a/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inlineSuperClass/InlineSuperClassRefactoringProcessor.java @@ -354,7 +354,7 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori public void visitTypeElement(final PsiTypeElement typeElement) { super.visitTypeElement(typeElement); final PsiType superClassType = typeElement.getType(); - if (PsiUtil.resolveClassInType(superClassType) == mySuperClass) { + if (PsiUtil.resolveClassInClassTypeOnly(superClassType) == mySuperClass) { PsiSubstitutor subst = getSuperClassSubstitutor(superClassType, targetClassType, resolveHelper, targetClass); replacementMap.put(new UsageInfo(typeElement), elementFactory.createTypeElement(elementFactory.createType(targetClass, subst))); } @@ -367,8 +367,11 @@ public class InlineSuperClassRefactoringProcessor extends FixableUsagesRefactori if (PsiUtil.resolveClassInType(superClassType) == mySuperClass) { PsiSubstitutor subst = getSuperClassSubstitutor(superClassType, targetClassType, resolveHelper, targetClass); try { - replacementMap.put(new UsageInfo(expression), elementFactory.createExpressionFromText("new " + elementFactory.createType( - targetClass, subst).getCanonicalText() + expression.getArgumentList().getText(), expression)); + final String typeCanonicalText = elementFactory.createType(targetClass, subst).getCanonicalText(); + final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference(); + if (classReference != null) { + replacementMap.put(new UsageInfo(classReference), elementFactory.createReferenceFromText(typeCanonicalText, expression)); + } } catch (IncorrectOperationException e) { LOG.error(e); diff --git a/java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/after/Test.java b/java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/after/Test.java new file mode 100644 index 000000000000..053d10d307ea --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/after/Test.java @@ -0,0 +1,9 @@ +class Test { + public static Test[] getArray() { + return new Test[0]; + } + + public static Test[] getArrayWithInitializer() { + return new Test[]{}; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/before/Super.java b/java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/before/Super.java new file mode 100644 index 000000000000..29e1e5a1aa6c --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/before/Super.java @@ -0,0 +1,10 @@ +class Super { + public static Super[] getArray() { + return new Super[0]; + } + + public static Super[] getArrayWithInitializer() { + return new Super[]{}; + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/before/Test.java b/java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/before/Test.java new file mode 100644 index 000000000000..e22cc838eaab --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineSuperClass/arrayTypeElements/before/Test.java @@ -0,0 +1 @@ +class Test extends Super {} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/InlineSuperClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/InlineSuperClassTest.java index 4ee7e74c0dcc..074f1b1e7110 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/InlineSuperClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/InlineSuperClassTest.java @@ -71,6 +71,7 @@ public class InlineSuperClassTest extends MultiFileTestCase { public void testInterfaceHierarchyWithSubstitution() { doTest(); } public void testTypeParameterBound() { doTest();} public void testInlineInterfaceDoNotChangeConstructor() { doTest(); } + public void testArrayTypeElements() { doTest(); } private void doTest() { doTest(false, false); From 40b3d08774bfc82b140b99513221b462307d19fa Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Thu, 3 Mar 2016 21:30:30 +0300 Subject: [PATCH 05/11] IDEA-149210 Rework IDE notifications --- .../intellij/notification/Notification.java | 23 +++++++++--- .../notification/NotificationAction.java | 37 +++++++++++++++++++ .../com/intellij/notification/EventLog.java | 2 +- .../impl/NotificationsManagerImpl.java | 4 +- 4 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 platform/platform-api/src/com/intellij/notification/NotificationAction.java diff --git a/platform/platform-api/src/com/intellij/notification/Notification.java b/platform/platform-api/src/com/intellij/notification/Notification.java index 9bb6d5bbe062..6f6acc73e4e8 100644 --- a/platform/platform-api/src/com/intellij/notification/Notification.java +++ b/platform/platform-api/src/com/intellij/notification/Notification.java @@ -15,10 +15,7 @@ */ package com.intellij.notification; -import com.intellij.openapi.actionSystem.ActionPlaces; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -28,6 +25,7 @@ import com.intellij.openapi.ui.popup.LightweightWindowEvent; import com.intellij.openapi.util.text.StringUtil; import com.intellij.reference.SoftReference; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,6 +39,7 @@ import java.util.List; */ public class Notification { private static final Logger LOG = Logger.getInstance("#com.intellij.notification.Notification"); + private static final DataKey KEY = DataKey.create("Notification"); private final String myGroupId; private Icon myIcon; @@ -195,8 +194,20 @@ public class Notification { return ContainerUtil.notNullize(myActions); } - public static void fire(@NotNull AnAction action) { - AnActionEvent event = AnActionEvent.createFromAnAction(action, null, ActionPlaces.UNKNOWN, DataContext.EMPTY_CONTEXT); + @NotNull + public static Notification get(@NotNull AnActionEvent e) { + //noinspection ConstantConditions + return e.getData(KEY); + } + + public static void fire(@NotNull final Notification notification, @NotNull AnAction action) { + AnActionEvent event = AnActionEvent.createFromAnAction(action, null, ActionPlaces.UNKNOWN, new DataContext() { + @Nullable + @Override + public Object getData(@NonNls String dataId) { + return KEY.getName().equals(dataId) ? notification : null; + } + }); if (ActionUtil.lastUpdateAndCheckDumb(action, event, false)) { ActionUtil.performActionDumbAware(action, event); } diff --git a/platform/platform-api/src/com/intellij/notification/NotificationAction.java b/platform/platform-api/src/com/intellij/notification/NotificationAction.java new file mode 100644 index 000000000000..e5d164edb9b1 --- /dev/null +++ b/platform/platform-api/src/com/intellij/notification/NotificationAction.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2016 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.notification; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Alexander Lobas + */ +public abstract class NotificationAction extends AnAction { + public NotificationAction(@Nullable String text) { + super(text); + } + + @Override + public void actionPerformed(AnActionEvent e) { + actionPerformed(e, Notification.get(e)); + } + + public abstract void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification); +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/notification/EventLog.java b/platform/platform-impl/src/com/intellij/notification/EventLog.java index 71e27d5ceb27..ee8871d590cc 100644 --- a/platform/platform-impl/src/com/intellij/notification/EventLog.java +++ b/platform/platform-impl/src/com/intellij/notification/EventLog.java @@ -134,7 +134,7 @@ public class EventLog { Notification n = new Notification("", "", ".", NotificationType.INFORMATION, new NotificationListener() { @Override public void hyperlinkUpdate(@NotNull Notification n, @NotNull HyperlinkEvent event) { - Notification.fire(notification.getActions().get(Integer.parseInt(event.getDescription()))); + Notification.fire(notification, notification.getActions().get(Integer.parseInt(event.getDescription()))); } }); if (title.length() > 0 || content.length() > 0) { diff --git a/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java b/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java index f7cce06180ba..7952ad2a6278 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/notification/impl/NotificationsManagerImpl.java @@ -729,7 +729,7 @@ public class NotificationsManagerImpl extends NotificationsManager { return balloon; } - private static void createActionPanel(@NotNull Notification notification, @NotNull JPanel centerPanel, int gap) { + private static void createActionPanel(@NotNull final Notification notification, @NotNull JPanel centerPanel, int gap) { JPanel actionPanel = new NonOpaquePanel(new HorizontalLayout(gap, SwingConstants.CENTER)); centerPanel.add(BorderLayout.SOUTH, actionPanel); @@ -763,7 +763,7 @@ public class NotificationsManagerImpl extends NotificationsManager { new LinkLabel(presentation.getText(), presentation.getIcon(), new LinkListener() { @Override public void linkSelected(LinkLabel aSource, AnAction action) { - Notification.fire(action); + Notification.fire(notification, action); } }, action)); } From 27da085da20e0741d9ec9f45a75aa2e3c379fd58 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Thu, 3 Mar 2016 22:27:22 +0300 Subject: [PATCH 06/11] IDEA-152528 Keyboard shortcut input dialog is not repainted properly --- .../src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java index 22d4bcdc633c..3ff1d0247db2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/ui/ShortcutDialog.java @@ -98,6 +98,7 @@ abstract class ShortcutDialog extends DialogWrapper { } } myConflictsPanel.revalidate(); + myConflictsPanel.repaint(); } myConflictsPanel.setVisible(0 < myConflictsContainer.getComponentCount()); } From 9a431f0252040f2f427b3dac45b0ee059b118160 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 4 Mar 2016 08:08:09 +0100 Subject: [PATCH 07/11] TransactionGuard: expand javadoc + FAQ, @WrapInTransaction, minor movements --- .../openapi/application/TransactionGuard.java | 75 +++++++++---------- .../openapi/application/TransactionKind.java | 66 ++++++++++++++++ .../application/WrapInTransaction.java | 22 ++++++ .../application/TransactionGuardImpl.java | 6 +- .../CompletionProgressIndicator.java | 3 +- .../openapi/actionSystem/ex/ActionUtil.java | 9 +++ 6 files changed, 137 insertions(+), 44 deletions(-) create mode 100644 platform/core-api/src/com/intellij/openapi/application/TransactionKind.java create mode 100644 platform/core-api/src/com/intellij/openapi/application/WrapInTransaction.java diff --git a/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java b/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java index a206e8310e23..54841737ca3f 100644 --- a/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java +++ b/platform/core-api/src/com/intellij/openapi/application/TransactionGuard.java @@ -16,7 +16,6 @@ package com.intellij.openapi.application; import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.progress.ProcessCanceledException; import org.jetbrains.annotations.NotNull; @@ -29,7 +28,7 @@ import org.jetbrains.annotations.NotNull; * and process UI events in other ways: it's guaranteed that no one will be able to sneak in with an unexpected model change using * {@link javax.swing.SwingUtilities#invokeLater(Runnable)} or analogs.

* - * Transactions are run on UI thread. They have read access by default.

+ * Transactions are run on UI thread. They have read access by default. All write actions should be performed inside a transaction.

* * The recommended way to perform a transaction is to invoke {@link #submitTransaction(Runnable)}. It either runs the transaction immediately * (if on UI thread and there's no other transaction running) or queues it to invoke at some later moment, when it becomes possible.

@@ -40,31 +39,43 @@ import org.jetbrains.annotations.NotNull; * the main transaction and executed immediately. Use {@link #acceptNestedTransactions(TransactionKind...)} for that. Inner transactions * should be given some kind in such circumstances: {@link #submitMergeableTransaction(TransactionKind, Runnable)}. * + *

FAQ

+ * + * Q: I've got "Write access is allowed from model transactions only" exception, what do I do?
+ * A: Add a transaction somewhere into the call stack, to the outermost callee where having read/write model consistency is needed. + * If it's a user action, transaction should be synchronous (see {@link #startSynchronousTransaction(TransactionKind)}. For AnAction + * inheritors, {@link WrapInTransaction} annotation might be handy. Note that not all actions need to be wrapped into transactions, only + * those that require the model to be consistent. For example, actions that display settings dialogs or VCS actions are most likely exempt. + *

+ * + * If the exception occurs not inside a user action, it's probably from some kind of "invokeLater". + * Then, replace "invokeLater" with {@link #submitTransaction(Runnable)} or + * {@link #submitMergeableTransaction(TransactionKind, Runnable)} call.

+ * + * Q: I've got "Nested transactions are not allowed" exception, what do I do?
+ * A: First, find the place in the stack where the outer transaction is started. Then, see if there is any Swing event pumping + * in between two transactions (e.g. a dialog is shown). If not, one of two transactions is superfluous, remove it. If there + * is event pumping, check if the client code (e.g. the one showing the dialog) is prepared to the nested model modifications + * of the specified kinds. For example, refactoring dialogs might be prepared to {@link TransactionKind#TEXT_EDITING} kind + * (for text field editing inside the dialogs) but not + * other model changes, e.g. root changes. The outer transaction code might then specify which kinds it's prepared to (by using + * {@link #acceptNestedTransactions(TransactionKind...)}), and the inner transaction code should have the very same transaction kind + * (by using {@link #submitMergeableTransaction(TransactionKind, Runnable)} or {@link #startSynchronousTransaction(TransactionKind)}). + * If the nested transaction is not expected by the outer code, it must be made asynchronous by using either {@link #submitTransaction(Runnable)} + * or {@link #submitMergeableTransaction(TransactionKind, Runnable)}. + *

+ * + * Q: What's the difference between transactions and read/write actions and commands ({@link com.intellij.openapi.command.CommandProcessor})?
+ * A: Transactions are more abstract and can contain several write actions and even commands inside. Read/write actions guarantee that no + * one else will modify the model, while transactions allow for some modification, but in a way controlled by transaction kinds. Commands + * are used for tracking document changes for undo/redo functionality, so they're orthogonal to transactions. + * * @see Application#runReadAction(Runnable) * @see Application#runWriteAction(Runnable) * @since 146.* * @author peter */ public abstract class TransactionGuard { - /** - * This kind represents document modifications via editor actions, code completion and document->PSI commit. - * @see com.intellij.psi.PsiDocumentManager#commitDocument(Document) - */ - public static final TransactionKind TEXT_EDITING = new TransactionKind("TEXT_EDITING"); - /** - * This kind represents any model modifications: - *

  • PSI or document changes - *
  • Virtual file system changes, e.g. files created/deleted/renamed/content-changed, - * caused by refresh process or explicit operations. - *
  • Project root set change - *
  • Dumb mode (reindexing) start/finish, (see {@link com.intellij.openapi.project.DumbService}). - */ - public static final TransactionKind ANY_CHANGE = new TransactionKind("ANY_CHANGE"); - - /** - * Transactions of this kind won't be merged into other transactions - */ - public static final TransactionKind NO_MERGE = new TransactionKind("NO_MERGE"); public static TransactionGuard getInstance() { return ServiceManager.getService(TransactionGuard.class); @@ -75,12 +86,12 @@ public abstract class TransactionGuard { * The code will be run on Swing thread immediately or after all other queued transactions (if any) have been completed.

    * * For more advanced version, see {@link #submitMergeableTransaction(TransactionKind, Runnable)}. - * Transactions submitted via this method use {@link #NO_MERGE} kind. + * Transactions submitted via this method use {@link TransactionKind#NO_MERGE} kind. * * @param transaction code to execute inside a transaction. */ public static void submitTransaction(@NotNull Runnable transaction) { - getInstance().submitMergeableTransaction(NO_MERGE, transaction); + getInstance().submitMergeableTransaction(TransactionKind.NO_MERGE, transaction); } /** @@ -110,7 +121,7 @@ public abstract class TransactionGuard { * and executes the provided code immediately. Otherwise * adds the runnable to a queue. When all transactions scheduled before this one are finished, executes the given * runnable under a transaction. - * @param kind a kind object to enable transaction merging or {@link #NO_MERGE}, if no merging is required. + * @param kind a kind object to enable transaction merging or {@link TransactionKind#NO_MERGE}, if no merging is required. * @param transaction code to execute inside a transaction. */ public abstract void submitMergeableTransaction(@NotNull TransactionKind kind, @NotNull Runnable transaction); @@ -126,20 +137,4 @@ public abstract class TransactionGuard { */ @NotNull public abstract AccessToken acceptNestedTransactions(TransactionKind... kinds); - - /** - * A kind of transaction used in {@link #acceptNestedTransactions(TransactionKind...)} - */ - public static final class TransactionKind { - private final String myName; - - public TransactionKind(@NotNull String name) { - myName = name; - } - - @Override - public String toString() { - return myName; - } - } } diff --git a/platform/core-api/src/com/intellij/openapi/application/TransactionKind.java b/platform/core-api/src/com/intellij/openapi/application/TransactionKind.java new file mode 100644 index 000000000000..bc7d3be0da3b --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/application/TransactionKind.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2016 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.application; + +import com.intellij.openapi.editor.Document; + +/** + * A kind of transaction used in {@link TransactionGuard#submitMergeableTransaction(TransactionKind, Runnable)} + * and {@link TransactionGuard#acceptNestedTransactions(TransactionKind...)}. + */ +public interface TransactionKind { + /** + * Same as {@link Common#TEXT_EDITING} + */ + TransactionKind TEXT_EDITING = Common.TEXT_EDITING; + + /** + * Same as {@link Common#NO_MERGE} + */ + TransactionKind NO_MERGE = Common.NO_MERGE; + + /** + * Same as {@link Common#ANY_CHANGE} + */ + TransactionKind ANY_CHANGE = Common.ANY_CHANGE; + + /** + * An auxiliary enum to make it possible to use transaction kinds in annotations + */ + enum Common implements TransactionKind { + + /** + * This kind represents document modifications via editor actions, code completion and document->PSI commit. + * @see com.intellij.psi.PsiDocumentManager#commitDocument(Document) + */ + TEXT_EDITING, + + /** + * This kind represents any model modifications: + *

  • PSI or document changes + *
  • Virtual file system changes, e.g. files created/deleted/renamed/content-changed, + * caused by refresh process or explicit operations. + *
  • Project root set change + *
  • Dumb mode (reindexing) start/finish, (see {@link com.intellij.openapi.project.DumbService}). + */ + ANY_CHANGE, + + /** + * Transactions of this kind won't be merged into other transactions + */ + NO_MERGE + } +} diff --git a/platform/core-api/src/com/intellij/openapi/application/WrapInTransaction.java b/platform/core-api/src/com/intellij/openapi/application/WrapInTransaction.java new file mode 100644 index 000000000000..711dc54680e4 --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/application/WrapInTransaction.java @@ -0,0 +1,22 @@ +package com.intellij.openapi.application; + +import java.lang.annotation.*; + +/** + * Add this annotation to actions (AnAction inheritors) to make them run inside a transaction. + * + * @see TransactionGuard + * @since 146.* + * @author peter + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface WrapInTransaction { + + /** + * @return the kind of transaction to wrap the action into. By default, it's {@link TransactionKind#NO_MERGE}. + */ + TransactionKind.Common value() default TransactionKind.Common.NO_MERGE; +} diff --git a/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java b/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java index 71ca6baf3aca..3d627e9956f0 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/application/TransactionGuardImpl.java @@ -39,7 +39,7 @@ public class TransactionGuardImpl extends TransactionGuard { @NotNull public AccessToken startSynchronousTransaction(@NotNull TransactionKind kind) throws IllegalStateException { ApplicationManager.getApplication().assertIsDispatchThread(); - if (kind != NO_MERGE && myMergeableKinds.contains(kind)) { + if (kind != TransactionKind.NO_MERGE && myMergeableKinds.contains(kind)) { return AccessToken.EMPTY_ACCESS_TOKEN; } if (myInsideTransaction) { @@ -68,7 +68,7 @@ public class TransactionGuardImpl extends TransactionGuard { Runnable next = myQueue.poll(); if (next != null) { - runSyncTransaction(NO_MERGE, next); + runSyncTransaction(TransactionKind.NO_MERGE, next); } } }, app.getDisposed()); @@ -95,7 +95,7 @@ public class TransactionGuardImpl extends TransactionGuard { Runnable runnable = new Runnable() { @Override public void run() { - if (!myInsideTransaction || kind != NO_MERGE && myMergeableKinds.contains(kind)) { + if (!myInsideTransaction || kind != TransactionKind.NO_MERGE && myMergeableKinds.contains(kind)) { runSyncTransaction(kind, transaction); } else { 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 51f8daee7706..d8922f01001f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java @@ -35,6 +35,7 @@ import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.TransactionKind; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.diagnostic.Logger; @@ -476,7 +477,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement void disposeIndicator() { // our offset map should be disposed under write action, so that duringCompletion (read action) won't access it after disposing - TransactionGuard.getInstance().submitMergeableTransaction(TransactionGuard.TEXT_EDITING, () -> + TransactionGuard.getInstance().submitMergeableTransaction(TransactionKind.TEXT_EDITING, () -> ApplicationManager.getApplication().runWriteAction(() -> Disposer.dispose(this))); } diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ActionUtil.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ActionUtil.java index 1ce55d4c8f3b..db468ae8e7f9 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ActionUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ActionUtil.java @@ -16,7 +16,10 @@ package com.intellij.openapi.actionSystem.ex; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ApplicationNamesInfo; +import com.intellij.openapi.application.TransactionGuard; +import com.intellij.openapi.application.WrapInTransaction; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; @@ -187,12 +190,18 @@ public class ActionUtil { } public static void performActionDumbAware(AnAction action, AnActionEvent e) { + WrapInTransaction annotation = action.getClass().getAnnotation(WrapInTransaction.class); + AccessToken token = annotation == null ? AccessToken.EMPTY_ACCESS_TOKEN + : TransactionGuard.getInstance().startSynchronousTransaction(annotation.value()); try { action.actionPerformed(e); } catch (IndexNotReadyException e1) { showDumbModeWarning(e); } + finally { + token.finish(); + } } @NotNull From fb8f84946731208b14898897603f809137a55392 Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 4 Mar 2016 08:10:44 +0100 Subject: [PATCH 08/11] handle INRE in more actionPerformed calls --- .../intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java | 6 ++---- .../src/com/intellij/ui/popup/PopupFactoryImpl.java | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java index 202999b53b90..1cfb301ef9d7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java +++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java @@ -23,9 +23,7 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.actionSystem.impl.PresentationFactory; -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.application.*; import com.intellij.openapi.keymap.KeyMapBundle; import com.intellij.openapi.keymap.Keymap; import com.intellij.openapi.keymap.KeymapManager; @@ -592,7 +590,7 @@ public final class IdeKeyEventDispatcher implements Disposable { .showInBestPositionFor(ctx); } else { - action.actionPerformed(actionEvent); + ActionUtil.performActionDumbAware(action, actionEvent); } if (Registry.is("actionSystem.fixLostTyping")) { diff --git a/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java b/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java index 16380ca99424..1ff011466417 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/PopupFactoryImpl.java @@ -858,7 +858,7 @@ public class PopupFactoryImpl extends JBPopupFactory { ActionManager.getInstance(), modifiers); event.setInjectedContext(action.isInInjectedContext()); if (ActionUtil.lastUpdateAndCheckDumb(action, event, false)) { - action.actionPerformed(event); + ActionUtil.performActionDumbAware(action, event); } } From 425a2a97c8db649ab65164a56bf73283809fe38b Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Fri, 4 Mar 2016 11:05:13 +0300 Subject: [PATCH 09/11] disable a workaround for a Mac OS JDK issue, when custom JDK with a fix is used --- platform/util/src/com/intellij/Patches.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/Patches.java b/platform/util/src/com/intellij/Patches.java index 5d8321543b11..a06ab6414d92 100644 --- a/platform/util/src/com/intellij/Patches.java +++ b/platform/util/src/com/intellij/Patches.java @@ -139,7 +139,22 @@ public class Patches { /** * On Mac OS font ligatures are not supported for natively loaded fonts, font needs to be loaded explicitly by JDK. */ - public static final boolean JDK_BUG_ID_7162125 = SystemInfo.isMac && !SystemInfo.isJavaVersionAtLeast("1.9"); + public static final boolean JDK_BUG_ID_7162125; + static { + boolean value; + if (!SystemInfo.isMac || SystemInfo.isJavaVersionAtLeast("1.9")) value = false; + else if (!SystemInfo.isJetbrainsJvm) value = true; + else { + try { + Class.forName("sun.font.CCompositeFont"); + value = Boolean.getBoolean("disable.font.substitution"); + } + catch (Throwable e) { + value = true; + } + } + JDK_BUG_ID_7162125 = value; + } /** * XToolkit.getScreenInsets() may be very slow. From 4fe0dc283c38b036e17bcd95e7b1257ada27bbed Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Fri, 4 Mar 2016 11:44:17 +0300 Subject: [PATCH 10/11] Don't disable popup on Ctrl+hover for non-navigatable items, just don't change their style to hyperlink and don't change mouse cursor (required for WEB-13238) This also restores a condition defining non-navigatable elements created for WEB-4470, which was partially removed for IDEA-108939 --- .../navigation/CtrlMouseHandler.java | 30 ++++++++++++++++--- .../navigation/NavigationUtil.java | 1 + 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java index 5f08e3f34543..a1249a0b1564 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/CtrlMouseHandler.java @@ -416,6 +416,8 @@ public class CtrlMouseHandler extends AbstractProjectComponent { public abstract DocInfo getInfo(); public abstract boolean isValid(@NotNull Document document); + + public abstract boolean isNavigatable(); public abstract void showDocInfo(@NotNull DocumentationManager docManager); @@ -467,11 +469,15 @@ public class CtrlMouseHandler extends AbstractProjectComponent { public boolean isValid(@NotNull Document document) { if (!myTargetElement.isValid()) return false; if (!myElementAtPointer.isValid()) return false; - if (myTargetElement == myElementAtPointer) return false; return rangesAreCorrect(document); } + @Override + public boolean isNavigatable() { + return myTargetElement != myElementAtPointer && myTargetElement != myElementAtPointer.getParent(); + } + @Override public void showDocInfo(@NotNull DocumentationManager docManager) { docManager.showJavaDocInfo(myTargetElement, myElementAtPointer, null); @@ -499,6 +505,11 @@ public class CtrlMouseHandler extends AbstractProjectComponent { return rangesAreCorrect(document); } + @Override + public boolean isNavigatable() { + return true; + } + @Override public void showDocInfo(@NotNull DocumentationManager docManager) { // Do nothing @@ -612,6 +623,11 @@ public class CtrlMouseHandler extends AbstractProjectComponent { public boolean isValid(@NotNull Document document) { return element.isValid(); } + + @Override + public boolean isNavigatable() { + return true; + } }; } } @@ -871,7 +887,9 @@ public class CtrlMouseHandler extends AbstractProjectComponent { } else { // highlighter already set - internalComponent.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + if (info.isNavigatable()) { + internalComponent.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } return; } } @@ -960,11 +978,15 @@ public class CtrlMouseHandler extends AbstractProjectComponent { internalComponent.addKeyListener(myEditorKeyListener); editor.getScrollingModel().addVisibleAreaListener(myVisibleAreaListener); final Cursor cursor = internalComponent.getCursor(); - internalComponent.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + if (info.isNavigatable()) { + internalComponent.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } myFileEditorManager.addFileEditorManagerListener(myFileEditorManagerListener); List highlighters = new ArrayList(); - TextAttributes attributes = myEditorColorsManager.getGlobalScheme().getAttributes(EditorColors.REFERENCE_HYPERLINK_COLOR); + TextAttributes attributes = info.isNavigatable() + ? myEditorColorsManager.getGlobalScheme().getAttributes(EditorColors.REFERENCE_HYPERLINK_COLOR) + : new TextAttributes(null, HintUtil.INFORMATION_COLOR, null, null, Font.PLAIN); for (TextRange range : info.getRanges()) { TextAttributes attr = NavigationUtil.patchAttributesColor(attributes, range, editor); final RangeHighlighter highlighter = editor.getMarkupModel().addRangeHighlighter(range.getStartOffset(), range.getEndOffset(), diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java index 187bfa349cec..749331eba30a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/NavigationUtil.java @@ -225,6 +225,7 @@ public final class NavigationUtil { */ @SuppressWarnings("UseJBColor") public static TextAttributes patchAttributesColor(TextAttributes attributes, @NotNull TextRange range, @NotNull Editor editor) { + if (attributes.getForegroundColor() == null && attributes.getEffectColor() == null) return attributes; MarkupModel model = DocumentMarkupModel.forDocument(editor.getDocument(), editor.getProject(), false); if (model != null) { if (!((MarkupModelEx)model).processRangeHighlightersOverlappingWith(range.getStartOffset(), range.getEndOffset(), From 1d3f1bb5a00eb33cc25da37cbc357d6a32307ed2 Mon Sep 17 00:00:00 2001 From: Liana Bakradze Date: Fri, 4 Mar 2016 12:32:08 +0300 Subject: [PATCH 11/11] added with to study EP's --- .../course-creator/resources/META-INF/plugin.xml | 1 + .../student/resources/META-INF/plugin.xml | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/python/educational-core/course-creator/resources/META-INF/plugin.xml b/python/educational-core/course-creator/resources/META-INF/plugin.xml index 3480859e7905..d4778320c08c 100644 --- a/python/educational-core/course-creator/resources/META-INF/plugin.xml +++ b/python/educational-core/course-creator/resources/META-INF/plugin.xml @@ -45,6 +45,7 @@ + diff --git a/python/educational-core/student/resources/META-INF/plugin.xml b/python/educational-core/student/resources/META-INF/plugin.xml index e13c821f55f6..823ec10abf07 100644 --- a/python/educational-core/student/resources/META-INF/plugin.xml +++ b/python/educational-core/student/resources/META-INF/plugin.xml @@ -30,8 +30,12 @@ - - + + + + + +