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);
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..8b4ceef2605b 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;
@@ -171,25 +173,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) {
@@ -274,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
@@ -357,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)));
}
@@ -370,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/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/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);
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/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(),
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);
+ }
+ }
+ }
+ }
}
}
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-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
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));
}
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/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());
}
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);
}
}
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.
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 @@
-
-
+
+
+
+
+
+