Merge remote-tracking branch 'origin/master'

This commit is contained in:
Vladimir.Orlov
2016-09-15 16:53:39 +03:00
4 changed files with 107 additions and 13 deletions
@@ -36,6 +36,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.packageDependencies.DependencyRule;
import com.intellij.packageDependencies.DependencyValidationManager;
@@ -319,13 +320,17 @@ public abstract class ImportClassFixBase<T extends PsiElement, R extends PsiRefe
boolean canImportHere = true;
boolean isInModlessContext = Registry.is("ide.perProjectModality") ?
!LaterInvocator.isInModalContextForProject(editor.getProject()) :
!LaterInvocator.isInModalContext();
if (classes.length == 1 &&
(canImportHere = canImportHere(allowCaretNearRef, editor, psiFile, classes[0].getName())) &&
(FileTypeUtils.isInServerPageFile(psiFile) ?
CodeInsightSettings.getInstance().JSP_ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY :
CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY) &&
(ApplicationManager.getApplication().isUnitTestMode() || DaemonListeners.canChangeFileSilently(psiFile)) &&
!LaterInvocator.isInModalContext() &&
isInModlessContext &&
!autoImportWillInsertUnexpectedCharacters(classes[0])
) {
CommandProcessor.getInstance().runUndoTransparentAction(() -> action.execute());
@@ -142,7 +142,7 @@ public class MigrateAssertToMatcherAssertInspection extends LocalInspectionTool
replaced = TypeConversionDescriptor.replaceExpression(methodCall, templatePair.getFirst(), templatePair.getSecond());
}
catch (IncorrectOperationException e) {
LOG.error("Replacer can't can't match expression:\n" +
LOG.error("Replacer can't match expression:\n" +
methodCall.getText() +
"\nwith replacement template:\n(" +
templatePair.getFirst() +
@@ -23,6 +23,7 @@ import com.intellij.openapi.diagnostic.FrequentEventDetector;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
@@ -33,6 +34,7 @@ import com.intellij.util.ExceptionUtil;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import com.intellij.util.containers.WeakHashMap;
import com.intellij.util.ui.UIUtil;
import io.netty.util.internal.SystemPropertyUtil;
import org.jetbrains.annotations.NonNls;
@@ -80,7 +82,13 @@ public class LaterInvocator {
}
}
// Application modal entities
private static final List<Object> ourModalEntities = ContainerUtil.createLockFreeCopyOnWriteList();
// Per-project modal entities
private static WeakHashMap<Project, List<Dialog>> projectToModalEntities = new WeakHashMap<>();
private static WeakHashMap<Project, Stack<ModalityState>> projectToModalEntitiesStack = new WeakHashMap<>();
private static final Stack<ModalityState> ourModalityStack = new Stack<>(ModalityState.NON_MODAL);
private static final List<RunnableInfo> ourQueue = new ArrayList<>(); //protected by LOCK
private static volatile int ourQueueSkipCount; // optimization
@@ -204,6 +212,60 @@ public class LaterInvocator {
}
}
public static void enterModal(Project project, Dialog dialog) {
LOG.assertTrue(isDispatchThread(), "enterModal() should be invoked in event-dispatch thread");
if (LOG.isDebugEnabled()) {
LOG.debug("enterModal:" + dialog.getName() + " ; for project: " + project.getName());
}
if (project == null) {
enterModal(dialog);
}
List<Dialog> modalEntitiesList = projectToModalEntities.getOrDefault(project, ContainerUtil.createLockFreeCopyOnWriteList());
projectToModalEntities.put(project, modalEntitiesList);
modalEntitiesList.add(dialog);
Stack<ModalityState> modalEntitiesStack = projectToModalEntitiesStack.getOrDefault(project, new Stack<>(ModalityState.NON_MODAL));
projectToModalEntitiesStack.put(project, modalEntitiesStack);
modalEntitiesStack.push(new ModalityStateEx(ArrayUtil.toObjectArray(ourModalEntities)));
}
public static void leaveModal(Project project, Dialog dialog) {
LOG.assertTrue(isDispatchThread(), "leaveModal() should be invoked in event-dispatch thread");
if (LOG.isDebugEnabled()) {
LOG.debug("leaveModal:" + dialog.getName() + " ; for project: " + project.getName());
}
ourModalityStateMulticaster.getMulticaster().beforeModalityStateChanged(false);
int index = ourModalEntities.indexOf(dialog);
if (index != -1) {
ourModalEntities.remove(index);
ourModalityStack.remove(index + 1);
for (int i = 1; i < ourModalityStack.size(); i++) {
((ModalityStateEx)ourModalityStack.get(i)).removeModality(dialog);
}
} else {
List<Dialog> dialogs = projectToModalEntities.get(project);
int perProjectIndex = dialogs.indexOf(dialog);
LOG.assertTrue(perProjectIndex >= 0);
dialogs.remove(perProjectIndex);
Stack<ModalityState> states = projectToModalEntitiesStack.get(project);
states.remove(perProjectIndex + 1);
for (int i = 1; i < states.size(); i++) {
((ModalityStateEx)states.get(i)).removeModality(dialog);
}
}
ourQueueSkipCount = 0;
requestFlush();
}
public static void leaveModal(@NotNull Object modalEntity) {
LOG.assertTrue(isDispatchThread(), "leaveModal() should be invoked in event-dispatch thread");
@@ -235,13 +297,17 @@ public class LaterInvocator {
requestFlush();
}
public static Object[] getCurrentModalEntitiesForProject(Project project) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (ourModalEntities.isEmpty()) {
return ArrayUtil.toObjectArray(ourModalEntities);
}
return ArrayUtil.toObjectArray(projectToModalEntities.get(project));
}
@NotNull
public static Object[] getCurrentModalEntities() {
ApplicationManager.getApplication().assertIsDispatchThread();
//TODO!
//LOG.assertTrue(IdeEventQueue.getInstance().isInInputEvent() || isInMyRunnable());
return ArrayUtil.toObjectArray(ourModalEntities);
return getCurrentModalEntitiesForProject(null);
}
@NotNull
@@ -249,9 +315,22 @@ public class LaterInvocator {
return ourModalityStack.peek();
}
public static boolean isInModalContext() {
public static boolean isInModalContextForProject(final Project project) {
LOG.assertTrue(isDispatchThread());
return !ourModalEntities.isEmpty();
if (ourModalEntities.isEmpty()) return false;
List<Dialog> modalEntitiesForProject = getModalEntitiesForProject(project);
return modalEntitiesForProject == null || modalEntitiesForProject.isEmpty();
}
private static List<Dialog> getModalEntitiesForProject(Project project) {
return projectToModalEntities.get(project);
}
public static boolean isInModalContext() {
return isInModalContextForProject(null);
}
private static boolean isDispatchThread() {
@@ -268,8 +347,8 @@ public class LaterInvocator {
* There might be some requests in the queue, but ourFlushQueueRunnable might not be scheduled yet. In these circumstances
* {@link EventQueue#peekEvent()} default implementation would return null, and {@link UIUtil#dispatchAllInvocationEvents()} would
* stop processing events too early and lead to spurious test failures.
*
* @see IdeEventQueue#peekEvent()
*
* @see IdeEventQueue#peekEvent()
*/
public static boolean ensureFlushRequested() {
if (getNextEvent(false) != null) {
@@ -438,9 +438,15 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
boolean changeModalityState = appStarted && myDialog.isModal()
&& !isProgressDialog(); // ProgressWindow starts a modality state itself
Project project = myProject;
if (changeModalityState) {
commandProcessor.enterModal();
LaterInvocator.enterModal(myDialog);
if (Registry.is("ide.perProjectModality")) {
LaterInvocator.enterModal(project, myDialog.getWindow());
} else {
LaterInvocator.enterModal(myDialog);
}
}
if (appStarted) {
@@ -453,7 +459,11 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
finally {
if (changeModalityState) {
commandProcessor.leaveModal();
LaterInvocator.leaveModal(myDialog);
if (Registry.is("ide.perProjectModality")) {
LaterInvocator.leaveModal(project, myDialog.getWindow());
} else {
LaterInvocator.leaveModal(myDialog);
}
}
myDialog.getFocusManager().doWhenFocusSettlesDown(result.createSetDoneRunnable());