mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
fix non-nested modality state support
This commit is contained in:
@@ -17,44 +17,30 @@ package com.intellij.openapi.application.impl;
|
||||
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.WeakList;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ModalityStateEx extends ModalityState {
|
||||
private static final WeakReference[] EMPTY_REFS_ARRAY = new WeakReference[0];
|
||||
private final WeakList myModalEntities = new WeakList();
|
||||
|
||||
private final WeakReference[] myModalEntities;
|
||||
|
||||
public ModalityStateEx() {
|
||||
this(EMPTY_REFS_ARRAY);
|
||||
}
|
||||
public ModalityStateEx() { } // used by reflection to initialize NON_MODAL
|
||||
|
||||
public ModalityStateEx(@NotNull Object[] modalEntities) {
|
||||
if (modalEntities.length > 0) {
|
||||
myModalEntities = new WeakReference[modalEntities.length];
|
||||
for (int i = 0; i < modalEntities.length; i++) {
|
||||
Object entity = modalEntities[i];
|
||||
myModalEntities[i] = new WeakReference<Object>(entity);
|
||||
}
|
||||
}
|
||||
else{
|
||||
myModalEntities = EMPTY_REFS_ARRAY;
|
||||
}
|
||||
Collections.addAll(myModalEntities, modalEntities);
|
||||
}
|
||||
|
||||
private List<Object> getModalEntities() {
|
||||
return ContainerUtil.mapNotNull(myModalEntities, new Function<WeakReference, Object>() {
|
||||
@Override
|
||||
public Object fun(WeakReference reference) {
|
||||
return reference.get();
|
||||
}
|
||||
});
|
||||
ArrayList<Object> result = new ArrayList<Object>();
|
||||
for (Object entity : myModalEntities) {
|
||||
result.add(entity);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -64,8 +50,9 @@ public class ModalityStateEx extends ModalityState {
|
||||
|
||||
@NotNull
|
||||
ModalityStateEx appendEntity(@NotNull Object anEntity){
|
||||
List<Object> list = new ArrayList<Object>(myModalEntities.length+1);
|
||||
list.addAll(getModalEntities());
|
||||
List<Object> modalEntities = getModalEntities();
|
||||
List<Object> list = new ArrayList<Object>(modalEntities.size() + 1);
|
||||
list.addAll(modalEntities);
|
||||
list.add(anEntity);
|
||||
return new ModalityStateEx(list.toArray());
|
||||
}
|
||||
@@ -81,21 +68,10 @@ public class ModalityStateEx extends ModalityState {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean contains(@NotNull Object modalEntity) {
|
||||
return getModalEntities().contains(modalEntity);
|
||||
}
|
||||
|
||||
@NonNls
|
||||
public String toString() {
|
||||
if (myModalEntities.length == 0) return "ModalityState.NON_MODAL";
|
||||
@NonNls StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("ModalityState:");
|
||||
for (int i = 0; i < myModalEntities.length; i++) {
|
||||
Object entity = myModalEntities[i].get();
|
||||
if (i > 0) buffer.append(", ");
|
||||
buffer.append(entity);
|
||||
}
|
||||
return buffer.toString();
|
||||
List<Object> modalEntities = getModalEntities();
|
||||
return modalEntities.isEmpty() ? "ModalityState.NON_MODAL" : "ModalityState:" + StringUtil.join(modalEntities, ", ");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -113,4 +89,8 @@ public class ModalityStateEx extends ModalityState {
|
||||
public int hashCode() {
|
||||
return getModalEntities().hashCode();
|
||||
}
|
||||
|
||||
void removeModality(Object modalEntity) {
|
||||
myModalEntities.remove(modalEntity);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-38
@@ -41,7 +41,6 @@ import org.jetbrains.annotations.TestOnly;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@@ -89,8 +88,6 @@ public class LaterInvocator {
|
||||
|
||||
private static final EventDispatcher<ModalityStateListener> ourModalityStateMulticaster = EventDispatcher.create(ModalityStateListener.class);
|
||||
|
||||
private static final List<RunnableInfo> ourForcedFlushQueue = new ArrayList<RunnableInfo>();
|
||||
|
||||
public static void addModalityStateListener(@NotNull ModalityStateListener listener, @NotNull Disposable parentDisposable) {
|
||||
if (!ourModalityStateMulticaster.getListeners().contains(listener)) {
|
||||
ourModalityStateMulticaster.addListener(listener, parentDisposable);
|
||||
@@ -204,43 +201,25 @@ public class LaterInvocator {
|
||||
LOG.debug("leaveModal:" + modalEntity);
|
||||
}
|
||||
|
||||
//noinspection StatementWithEmptyBody
|
||||
while (ourFlushQueueRunnable.runNextEvent());
|
||||
|
||||
ourModalityStateMulticaster.getMulticaster().beforeModalityStateChanged(false);
|
||||
|
||||
boolean removed = ourModalEntities.remove(modalEntity);
|
||||
if (ourModalityStack.size() > 1) {
|
||||
ourModalityStack.pop();
|
||||
int index = ourModalEntities.indexOf(modalEntity);
|
||||
LOG.assertTrue(index >= 0);
|
||||
ourModalEntities.remove(index);
|
||||
ourModalityStack.remove(index + 1);
|
||||
for (int i = 1; i < ourModalityStack.size(); i++) {
|
||||
((ModalityStateEx)ourModalityStack.get(i)).removeModality(modalEntity);
|
||||
}
|
||||
LOG.assertTrue(removed, modalEntity);
|
||||
LOG.assertTrue(!ourModalityStack.isEmpty());
|
||||
|
||||
TransactionGuardImpl guard = IdeaApplication.isLoaded() ? (TransactionGuardImpl)TransactionGuard.getInstance() : null;
|
||||
if (guard != null) {
|
||||
guard.leftModality(modalEntity);
|
||||
}
|
||||
|
||||
cleanupQueueForModal(modalEntity);
|
||||
ourQueueSkipCount = 0;
|
||||
requestFlush();
|
||||
}
|
||||
|
||||
private static void cleanupQueueForModal(@NotNull final Object modalEntity) {
|
||||
synchronized (LOCK) {
|
||||
for (Iterator<RunnableInfo> iterator = ourQueue.iterator(); iterator.hasNext(); ) {
|
||||
RunnableInfo runnableInfo = iterator.next();
|
||||
if (runnableInfo.modalityState instanceof ModalityStateEx) {
|
||||
ModalityStateEx stateEx = (ModalityStateEx)runnableInfo.modalityState;
|
||||
if (stateEx.contains(modalEntity)) {
|
||||
ourForcedFlushQueue.add(runnableInfo);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public static void leaveAllModals() {
|
||||
while (!ourModalEntities.isEmpty()) {
|
||||
@@ -298,17 +277,6 @@ public class LaterInvocator {
|
||||
@Nullable
|
||||
private static RunnableInfo getNextEvent(boolean remove) {
|
||||
synchronized (LOCK) {
|
||||
if (!ourForcedFlushQueue.isEmpty()) {
|
||||
final RunnableInfo toRun = remove ? ourForcedFlushQueue.remove(0) : ourForcedFlushQueue.get(0);
|
||||
if (!toRun.expired.value(null)) {
|
||||
return toRun;
|
||||
}
|
||||
else {
|
||||
toRun.callback.setDone();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ModalityState currentModality = getCurrentModalityState();
|
||||
|
||||
while (ourQueueSkipCount < ourQueue.size()) {
|
||||
|
||||
+41
-29
@@ -202,35 +202,6 @@ public class LaterInvocatorTest extends PlatformTestCase {
|
||||
});
|
||||
}
|
||||
|
||||
public void testRunQueuedRunnablesOnLeavingModality() {
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LaterInvocator.invokeLater(ENTER_MODAL, ModalityState.NON_MODAL);
|
||||
LaterInvocator.invokeLater(new MyRunnable("3"), ModalityState.NON_MODAL);
|
||||
flushSwingQueue();
|
||||
checkOrder(0);
|
||||
|
||||
final ModalityState modalityState = ModalityState.stateForComponent(myWindow1);
|
||||
LaterInvocator.invokeLater(new MyRunnable("1") {
|
||||
@Override
|
||||
public void run() {
|
||||
super.run();
|
||||
checkOrder(1);
|
||||
LaterInvocator.invokeLater(new MyRunnable("2"), modalityState);
|
||||
checkOrder(1);
|
||||
LaterInvocator.leaveModal(myWindow1);
|
||||
checkOrder(2);
|
||||
}
|
||||
}, modalityState);
|
||||
flushSwingQueue(); // let "1" run
|
||||
|
||||
flushSwingQueue(); // let "3" run
|
||||
checkOrder(3);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testStress() throws Exception {
|
||||
UIUtil.invokeAndWaitIfNeeded((Runnable)() -> {
|
||||
int N = 1000;
|
||||
@@ -551,4 +522,45 @@ public class LaterInvocatorTest extends PlatformTestCase {
|
||||
assertSame(modalityState1, ModalityState.current());
|
||||
});
|
||||
}
|
||||
|
||||
public void testNonNestedModalityState() { //happens with per-project modality
|
||||
Object modal1 = new Object();
|
||||
Object modal2 = new Object();
|
||||
UIUtil.invokeAndWaitIfNeeded((Runnable)() -> {
|
||||
LaterInvocator.enterModal(modal1); // [modal1]
|
||||
ModalityState ms_1 = ModalityState.current();
|
||||
ApplicationManager.getApplication().invokeLater(new MyRunnable("m1"), ms_1);
|
||||
|
||||
|
||||
LaterInvocator.enterModal(modal2); //[modal1, modal2]
|
||||
ModalityState ms_12 = ModalityState.current();
|
||||
assertNotSame(ms_1, ms_12);
|
||||
assertTrue(ms_12.dominates(ms_1));
|
||||
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
assertEmpty(myOrder);
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(new MyRunnable("m12"), ms_12);
|
||||
|
||||
|
||||
LaterInvocator.leaveModal(modal1); // [modal2]
|
||||
assertEmpty(myOrder);
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
assertOrderedEquals(myOrder, "m12");
|
||||
|
||||
ModalityState ms_2 = ModalityState.current();
|
||||
assertSame(ms_12, ms_2);
|
||||
assertTrue(ms_2.dominates(ms_1));
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(new MyRunnable("m1x"), ms_1);
|
||||
ApplicationManager.getApplication().invokeLater(new MyRunnable("m2"), ms_2);
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
assertOrderedEquals(myOrder, "m12", "m2");
|
||||
|
||||
|
||||
LaterInvocator.leaveModal(modal2); // NON_MODAL
|
||||
UIUtil.dispatchAllInvocationEvents();
|
||||
assertOrderedEquals(myOrder, "m12", "m2", "m1", "m1x");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user