IDEA-107366 Messages.show... does not add an entity to modality state

This commit is contained in:
Denis Fokin
2013-05-24 19:53:47 +04:00
parent 248746452f
commit 324d12891c
4 changed files with 400 additions and 289 deletions
@@ -0,0 +1,40 @@
/*
* Copyright 2000-2013 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.internal.validation;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.ui.Messages;
/**
* @author Denis Fokin
*/
public class TestMacMessagesSequencesAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
for (int i=0;i<10;i++){
final int k = i;
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
Messages.showDialog("Message # " + k, "Title of " + k, new String[] { "Option one", "Option two" }, 0, Messages.getQuestionIcon());
}
});
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -17,7 +17,6 @@ package com.intellij.ui.mac;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
@@ -26,13 +25,16 @@ import com.intellij.ui.FocusTrackback;
import com.intellij.ui.mac.foundation.Foundation;
import com.intellij.ui.mac.foundation.ID;
import com.intellij.ui.mac.foundation.MacUtil;
import com.intellij.util.PairFunction;
import com.intellij.util.ui.UIUtil;
import com.sun.jna.Callback;
import org.jetbrains.annotations.Nullable;
import sun.awt.SunToolkit;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.lang.reflect.Method;
import java.util.HashMap;
import static com.intellij.ui.mac.foundation.Foundation.*;
@@ -42,34 +44,19 @@ import static com.intellij.ui.mac.foundation.Foundation.*;
public class MacMessagesImpl extends MacMessages {
private static final Logger LOG = Logger.getInstance("#com.intellij.ui.mac.MacMessages");
private static final HashMap<Window, Integer> resultsFromDocumentRoot = new HashMap<Window, Integer> ();
private static final HashMap<Window, MacMessagesQueue<Runnable>> queuesFromDocumentRoot =
new HashMap<Window, MacMessagesQueue<Runnable>>();
private static final Callback SHEET_DID_END = new Callback() {
public void callback(ID self, String selector, ID alert, ID returnCode, ID contextInfo) {
String fakeDialogTitle = toStringViaUTF8(contextInfo);
Window[] windows = Window.getWindows();
ID suppressState = invoke(invoke(alert, "suppressionButton"), "state");
for (Window window : windows) {
if (window instanceof JFrame) {
JFrame frame = (JFrame)window;
JRootPane rootPane = frame.getRootPane();
if (rootPane.getClientProperty(MacUtil.MAC_NATIVE_WINDOW_SHOWING) == Boolean.TRUE &&
fakeDialogTitle.equals(rootPane.getClientProperty(MAC_SHEET_ID))) {
processResult(rootPane, returnCode.intValue(), suppressState.intValue());
break;
}
}
else if (window instanceof JDialog) {
JDialog dialog = (JDialog)window;
JRootPane rootPane = dialog.getRootPane();
if (rootPane.getClientProperty(MacUtil.MAC_NATIVE_WINDOW_SHOWING) == Boolean.TRUE &&
fakeDialogTitle.equals(rootPane.getClientProperty(MAC_SHEET_ID))) {
processResult(rootPane, returnCode.intValue(), suppressState.intValue());
}
}
}
cfRelease(self);
synchronized (lock) {
Window documentRoot = windowFromId.get(contextInfo.longValue());
processResult(documentRoot);
resultsFromDocumentRoot.put(documentRoot, returnCode.intValue());
queuesFromDocumentRoot.get(windowFromId.get(contextInfo.longValue())).runFromQueue();
}
}
};
@@ -78,7 +65,6 @@ public class MacMessagesImpl extends MacMessages {
ID title = invoke(params, "objectAtIndex:", 0);
ID message = invoke(params, "objectAtIndex:", 1);
ID focusedWindow = invoke(params, "objectAtIndex:", 2);
ID fakeId = invoke(params, "objectAtIndex:", 3);
ID alertStyle = invoke(params, "objectAtIndex:", 4);
ID doNotAskText = invoke(params, "objectAtIndex:", 5);
int defaultOptionIndex = Integer.parseInt(toStringViaUTF8(invoke(params, "objectAtIndex:", 6)));
@@ -90,11 +76,11 @@ public class MacMessagesImpl extends MacMessages {
invoke(alert, "setMessageText:", title);
invoke(alert, "setInformativeText:", message);
if ("error".equals(toStringViaUTF8(alertStyle))) {
invoke(alert, "setAlertStyle:", 2); // NSCriticalAlertStyle = 2
}
final ID buttonEnumerator = invoke(buttons, "objectEnumerator");
while (true) {
final ID button = invoke(buttonEnumerator, "nextObject");
@@ -103,20 +89,20 @@ public class MacMessagesImpl extends MacMessages {
}
if (defaultOptionIndex != -1) {
invoke(invoke(alert, "window"), "setDefaultButtonCell:",
invoke(invoke(alert, "window"), "setDefaultButtonCell:",
invoke(invoke(invoke(alert, "buttons"), "objectAtIndex:", defaultOptionIndex), "cell"));
}
// it seems like asking for focus will cause java to go and query focus owner too, which may cause dead locks on main-thread
//if (focusedOptionIndex != -1) {
// invoke(invoke(alert, "window"), "makeFirstResponder:",
// invoke(invoke(alert, "window"), "makeFirstResponder:",
// invoke(invoke(alert, "buttons"), "objectAtIndex:", focusedOptionIndex));
//} else {
// int count = invoke(buttons, "count").intValue();
// invoke(invoke(alert, "window"), "makeFirstResponder:",
// invoke(invoke(alert, "window"), "makeFirstResponder:",
// invoke(invoke(alert, "buttons"), "objectAtIndex:", count == 1 ? 0 : 1));
//}
String doNotAsk = toStringViaUTF8(doNotAskText);
if (!"-1".equals(doNotAsk)) {
invoke(alert, "setShowsSuppressionButton:", 1);
@@ -125,7 +111,7 @@ public class MacMessagesImpl extends MacMessages {
}
invoke(alert, "beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:", focusedWindow, self,
createSelector("alertDidEnd:returnCode:contextInfo:"), fakeId);
createSelector("alertDidEnd:returnCode:contextInfo:"), focusedWindow);
}
};
@@ -137,7 +123,6 @@ public class MacMessagesImpl extends MacMessages {
ID alternateText = invoke(params, "objectAtIndex:", 3);
ID message = invoke(params, "objectAtIndex:", 4);
ID focusedWindow = invoke(params, "objectAtIndex:", 5);
ID fakeId = invoke(params, "objectAtIndex:", 6);
ID alertStyle = invoke(params, "objectAtIndex:", 7);
ID doNotAskText = invoke(params, "objectAtIndex:", 8);
ID doNotAskChecked = invoke(params, "objectAtIndex:", 9);
@@ -154,15 +139,14 @@ public class MacMessagesImpl extends MacMessages {
// it seems like asking for focus will cause java to go and query focus owner too, which may cause dead locks on main-thread
//ID window = invoke(alert, "window");
//invoke(window, "makeFirstResponder:",
//invoke(window, "makeFirstResponder:",
// invoke(invoke(alert, "buttons"), "objectAtIndex:", alternateExist ? 2 : otherExist ? 1 : 0));
// it is impossible to override ESCAPE key behavior -> key should be named "Cancel" to be bound to ESC
//
////it is impossible to override ESCAPE key behavior -> key should be named "Cancel" to be bound to ESC
//if (!alternateExist) {
//invoke(invoke(invoke(alert, "buttons"), "objectAtIndex:", 1), "setKeyEquivalent:", nsString("\\e"));
// invoke(invoke(invoke(alert, "buttons"), "objectAtIndex:", 1), "setKeyEquivalent:", nsString("\\e"));
//}
String doNotAsk = toStringViaUTF8(doNotAskText);
if (!"-1".equals(doNotAsk)) {
invoke(alert, "setShowsSuppressionButton:", 1);
@@ -171,23 +155,33 @@ public class MacMessagesImpl extends MacMessages {
}
invoke(alert, "beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo:", focusedWindow, self,
createSelector("alertDidEnd:returnCode:contextInfo:"), fakeId);
createSelector("alertDidEnd:returnCode:contextInfo:"), focusedWindow);
}
};
private static void processResult(JRootPane rootPane, int returnCode, int suppressDialog) {
rootPane.putClientProperty(MAC_SHEET_RESULT, returnCode);
rootPane.putClientProperty(MAC_SHEET_SUPPRESS, suppressDialog == 1 ? Boolean.TRUE : Boolean.FALSE);
rootPane.putClientProperty(MAC_SHEET_ID, null);
rootPane.putClientProperty(MacUtil.MAC_NATIVE_WINDOW_SHOWING, null);
private static void processResult(Window w) {
synchronized (lock) {
if (!blockedDocumentRoots.keySet().contains(w)) {
throw new RuntimeException("Window should be in th list.");
}
int openedSheetsForWindow = blockedDocumentRoots.get(w);
if (openedSheetsForWindow < 1) {
throw new RuntimeException("We should have at least one window in the list");
}
if (openedSheetsForWindow == 1) {
// The last sheet
blockedDocumentRoots.remove(w);
} else {
blockedDocumentRoots.put(w, openedSheetsForWindow - 1);
}
}
}
private static final String MAC_SHEET_RESULT = "mac_sheet_result";
private static final String MAC_SHEET_SUPPRESS = "mac_sheet_suppress";
private static final String MAC_SHEET_ID = "mac_sheet_id";
private MacMessagesImpl() {
}
private MacMessagesImpl() {}
static {
if (SystemInfo.isMac) {
@@ -242,165 +236,174 @@ public class MacMessagesImpl extends MacMessages {
return showAlertDialog(title, defaultButton, alternateButton, otherButton, message, window, false, doNotAskOption);
}
public int showMessageDialog(final String title, final String message, final String[] buttons, final boolean errorStyle,
@Nullable Window window, final int defaultOptionIndex,
final int focusedOptionIndex, @Nullable final DialogWrapper.DoNotAskOption doNotAskDialogOption) {
return doForWindowAndTitle(new PairFunction<Pair<Window, String>, JRootPane, Integer>() {
@Override
public Integer fun(Pair<Window, String> windowAndTitle, JRootPane pane) {
String _windowTitle = windowAndTitle.getSecond();
Window _window = windowAndTitle.getFirst();
final ID focusedWindow = MacUtil.findWindowForTitle(_windowTitle);
if (focusedWindow != null) {
String fakeTitle = null;
final FocusTrackback[] focusTrackback = {new FocusTrackback(new Object(), _window, true)};
ID pool = invoke("NSAutoreleasePool", "new");
try {
final ID delegate = invoke(Foundation.getObjcClass("NSAlertDelegate_"), "new");
cfRetain(delegate);
final private static Object lock = new Object();
fakeTitle = String.format("MacSheetDialog-%d", delegate.intValue());
final private static HashMap<Window, Integer> blockedDocumentRoots = new HashMap<Window, Integer>();
final ID buttonsArray = invoke("NSMutableArray", "array");
for (String s : buttons) {
ID s1 = nsString(UIUtil.removeMnemonic(s));
invoke(buttonsArray, "addObject:", s1);
cfRelease(s1);
final private static HashMap<Long, Window> windowFromId = new HashMap<Long, Window>();
public static void pumpEventsDocumentExclusively (Window documentRoot) {
Integer messageNumber = blockedDocumentRoots.get(documentRoot);
EventQueue theQueue = documentRoot.getToolkit().getSystemEventQueue();
AWTEvent event;
do {
try {
event = theQueue.getNextEvent();
boolean eventOk = true;
if (event instanceof InputEvent) {
final Object s = event.getSource();
if (s instanceof Component) {
Component c = (Component)s;
Window w = findDocumentRoot(c);
if (w == documentRoot) {
eventOk = false;
((InputEvent)event).consume();
}
}
}
ID paramsArray = invoke("NSArray", "arrayWithObjects:", nsString(title),
if (eventOk) {
Class<?>[] paramString = new Class<?>[1];
paramString[0] = AWTEvent.class;
Method method = theQueue.getClass().getDeclaredMethod("dispatchEvent",paramString);
method.setAccessible(true);
method.invoke(theQueue, event);
}
}
catch (Throwable e) {
LOG.error(e);
}
}
while (isBlockedDocumentRoot(documentRoot, messageNumber));
}
private static boolean isBlockedDocumentRoot(Window documentRoot, Integer messageNumber) {
synchronized (lock) {
return messageNumber.equals(blockedDocumentRoots.get(documentRoot));
}
}
private static Window findDocumentRoot (final Component c) {
Window w = SunToolkit.getContainingWindow(c);
synchronized (c.getTreeLock()) {
while (w.getOwner() != null) {
w = w.getOwner();
}
}
return w;
}
private static void startModal(final Window w, ID windowId) {
synchronized (lock) {
windowFromId.put(windowId.longValue(), w);
if (blockedDocumentRoots.keySet().contains(w)) {
blockedDocumentRoots.put(w, blockedDocumentRoots.get(w) + 1);
} else {
blockedDocumentRoots.put(w, 1);
}
}
pumpEventsDocumentExclusively(w);
}
public int showMessageDialog(final String title, final String message, final String[] buttons, final boolean errorStyle,
@Nullable Window window, final int defaultOptionIndex,
final int focusedOptionIndex, @Nullable final DialogWrapper.DoNotAskOption doNotAskDialogOption) {
Window documentRoot = getDocumetnRootFromWindow(window);
String documentRootTitle;
documentRootTitle = getdocumentRootTitle(documentRoot);
final ID focusedWindow = MacUtil.findWindowForTitle(documentRootTitle);
if (focusedWindow != null) {
final FocusTrackback[] focusTrackback = {new FocusTrackback(new Object(), documentRoot, true)};
final ID delegate = invoke(Foundation.getObjcClass("NSAlertDelegate_"), "new");
invoke(delegate, "autorelease");
cfRetain(delegate);
final ID buttonsArray = invoke("NSMutableArray", "array");
for (String s : buttons) {
ID s1 = nsString(UIUtil.removeMnemonic(s));
invoke(buttonsArray, "addObject:", s1);
cfRelease(s1);
}
final ID paramsArray = invoke("NSArray", "arrayWithObjects:", nsString(title),
// replace % -> %% to avoid formatted parameters (causes SIGTERM)
nsString(StringUtil.stripHtml(message == null ? "" : message, true).replace("%", "%%")),
focusedWindow, nsString(fakeTitle), nsString(errorStyle ? "error" : "-1"),
focusedWindow, nsString(""), nsString(errorStyle ? "error" : "-1"),
nsString(doNotAskDialogOption == null || !doNotAskDialogOption.canBeHidden()
// TODO: state=!doNotAsk.shouldBeShown()
? "-1"
: doNotAskDialogOption.getDoNotShowMessage()),
nsString(Integer.toString(defaultOptionIndex)),
: doNotAskDialogOption.getDoNotShowMessage()),
nsString(Integer.toString(defaultOptionIndex)),
nsString(Integer.toString(focusedOptionIndex)), buttonsArray,
nsString(doNotAskDialogOption != null && !doNotAskDialogOption.isToBeShown() ? "checked" : "-1"), null);
IdeFocusManager.getGlobalInstance().setTypeaheadEnabled(false);
IdeFocusManager.getGlobalInstance().setTypeaheadEnabled(false);
invoke(delegate, "performSelectorOnMainThread:withObject:waitUntilDone:",
Foundation.createSelector("showVariableButtonsSheet:"), paramsArray, false);
}
finally {
invoke(pool, "release");
}
if (fakeTitle != null) {
pane.putClientProperty(MacUtil.MAC_NATIVE_WINDOW_SHOWING, Boolean.TRUE);
pane.putClientProperty(MAC_SHEET_ID, fakeTitle);
MacUtil.startModal(pane);
IdeFocusManager.getGlobalInstance().setTypeaheadEnabled(true);
Integer code = (Integer)pane.getClientProperty(MAC_SHEET_RESULT) - 1000; // see NSAlertFirstButtonReturn for more info
boolean suppress = Boolean.TRUE == pane.getClientProperty(MAC_SHEET_SUPPRESS);
final int cancelCode = buttons.length - 1;
if (doNotAskDialogOption != null && doNotAskDialogOption.canBeHidden()) {
if (cancelCode != code || doNotAskDialogOption.shouldSaveOptionsOnCancel()) {
doNotAskDialogOption.setToBeShown(!suppress, code);
}
}
pane.putClientProperty(MAC_SHEET_RESULT, null);
pane.putClientProperty(MAC_SHEET_SUPPRESS, null);
if (focusTrackback[0] != null &&
!(focusTrackback[0].isSheduledForRestore() || focusTrackback[0].isWillBeSheduledForRestore())) {
focusTrackback[0].setWillBeSheduledForRestore();
IdeFocusManager mgr = IdeFocusManager.findInstanceByComponent(_window);
Runnable r = new Runnable() {
public void run() {
if (focusTrackback[0] != null) focusTrackback[0].restoreFocus();
focusTrackback[0] = null;
}
};
mgr.doWhenFocusSettlesDown(r);
}
return code;
}
runOrPostponeForWindow(documentRoot, new Runnable() {
@Override
public void run() {
invoke(delegate, "performSelectorOnMainThread:withObject:waitUntilDone:",
createSelector("showVariableButtonsSheet:"), paramsArray, false);
}
});
return -1;
startModal(documentRoot, focusedWindow);
IdeFocusManager.getGlobalInstance().setTypeaheadEnabled(true);
if (focusTrackback[0] != null &&
!(focusTrackback[0].isSheduledForRestore() || focusTrackback[0].isWillBeSheduledForRestore())) {
focusTrackback[0].setWillBeSheduledForRestore();
IdeFocusManager mgr = IdeFocusManager.findInstanceByComponent(documentRoot);
Runnable r = new Runnable() {
public void run() {
if (focusTrackback[0] != null) focusTrackback[0].restoreFocus();
focusTrackback[0] = null;
}
};
mgr.doWhenFocusSettlesDown(r);
}
}, window);
return convertReturnCodeFromNativeMessageDialog(documentRoot);
}
return -1;
}
private static int doForWindowAndTitle(PairFunction<Pair<Window, String>, JRootPane, Integer> fun, @Nullable Window window) {
LOG.assertTrue(SwingUtilities.isEventDispatchThread());
private static int convertReturnCodeFromNativeMessageDialog(Window documentRoot) {
return resultsFromDocumentRoot.remove(documentRoot) - 1000;
}
JRootPane pane = null;
String _windowTitle = null;
Window _window = window == null ? KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow() : window;
if (_window == null) {
Component focusOwner = IdeFocusManager.findInstance().getFocusOwner();
if (focusOwner != null) {
_window = SwingUtilities.getWindowAncestor(focusOwner);
}
if (_window == null) {
_window = WindowManager.getInstance().findVisibleFrame();
}
private static String getdocumentRootTitle(Window documentRoot) {
String documentRootTitle;
if (documentRoot instanceof Frame) {
documentRootTitle = ((Frame)documentRoot).getTitle();
} else if (documentRoot instanceof Dialog) {
documentRootTitle = ((Dialog)documentRoot).getTitle();
} else {
throw new RuntimeException("The window is not a frame and not a dialog!");
}
LOG.assertTrue(_window != null);
if (!_window.isShowing()) {
Container parent = _window.getParent();
if (parent != null && parent instanceof Window) {
_window = (Window)parent;
}
if (!_window.isShowing()) {
Component focusOwner = IdeFocusManager.findInstance().getFocusOwner();
if (focusOwner != null) {
_window = SwingUtilities.getWindowAncestor(focusOwner);
}
}
}
LOG.assertTrue(_window.isShowing(), "Window MUST BE showing in screen!");
if (_window instanceof JFrame) {
JFrame frame = (JFrame)_window;
pane = frame.getRootPane();
_windowTitle = frame.getTitle();
}
else if (_window instanceof JDialog) {
JDialog dialog = (JDialog)_window;
pane = dialog.getRootPane();
_windowTitle = dialog.getTitle();
}
if (_windowTitle == null) {
_window = SwingUtilities.getWindowAncestor(_window);
if (_window instanceof JFrame) {
JFrame frame = (JFrame)_window;
pane = frame.getRootPane();
_windowTitle = frame.getTitle();
}
else if (_window instanceof JDialog) {
JDialog dialog = (JDialog)_window;
pane = dialog.getRootPane();
_windowTitle = dialog.getTitle();
}
}
LOG.assertTrue(_windowTitle != null && _windowTitle.length() > 0 && pane != null, "Window MUST have a title and a root pane!");
return fun.fun(Pair.create(_window, _windowTitle), pane);
return documentRootTitle;
}
public static int showAlertDialog(final String title,
@@ -408,137 +411,140 @@ public class MacMessagesImpl extends MacMessages {
@Nullable final String alternateText,
@Nullable final String otherText,
final String message,
@Nullable Window window,
@Nullable Window window ,
final boolean errorStyle,
@Nullable final DialogWrapper.DoNotAskOption doNotAskDialogOption) {
return doForWindowAndTitle(new PairFunction<Pair<Window, String>, JRootPane, Integer>() {
@Override
public Integer fun(Pair<Window, String> windowAndTitle, JRootPane pane) {
String _windowTitle = windowAndTitle.getSecond();
Window _window = windowAndTitle.getFirst();
final ID focusedWindow = MacUtil.findWindowForTitle(_windowTitle);
if (focusedWindow != null) {
String fakeTitle = null;
Window documentRoot = getDocumetnRootFromWindow(window);
String documentRootTitle = getdocumentRootTitle(documentRoot);
final FocusTrackback[] focusTrackback = {new FocusTrackback(new Object(), _window, true)};
final ID focusedWindow = MacUtil.findWindowForTitle(documentRootTitle);
ID pool = invoke("NSAutoreleasePool", "new");
try {
final ID delegate = invoke(Foundation.getObjcClass("NSAlertDelegate_"), "new");
cfRetain(delegate);
ID pool = invoke("NSAutoreleasePool", "new");
try {
fakeTitle = String.format("MacSheetDialog-%d", delegate.intValue());
final ID delegate = invoke(Foundation.getObjcClass("NSAlertDelegate_"), "new");
cfRetain(delegate);
ID paramsArray = invoke("NSArray", "arrayWithObjects:", nsString(title), nsString(UIUtil.removeMnemonic(defaultText)),
final ID paramsArray = invoke("NSArray", "arrayWithObjects:", nsString(title), nsString(UIUtil.removeMnemonic(defaultText)),
nsString(otherText == null ? "-1" : UIUtil.removeMnemonic(otherText)),
nsString(alternateText == null ? "-1" : UIUtil.removeMnemonic(alternateText)),
// replace % -> %% to avoid formatted parameters (causes SIGTERM)
nsString(StringUtil.stripHtml(message == null ? "" : message, true).replace("%", "%%")),
focusedWindow, nsString(fakeTitle), nsString(errorStyle ? "error" : "-1"),
focusedWindow, nsString(""), nsString(errorStyle ? "error" : "-1"),
nsString(doNotAskDialogOption == null || !doNotAskDialogOption.canBeHidden()
// TODO: state=!doNotAsk.shouldBeShown()
? "-1"
: doNotAskDialogOption.getDoNotShowMessage()),
nsString(doNotAskDialogOption != null && !doNotAskDialogOption.isToBeShown() ? "checked" : "-1"), null);
IdeFocusManager.getGlobalInstance().setTypeaheadEnabled(false);
invoke(delegate, "performSelectorOnMainThread:withObject:waitUntilDone:",
Foundation.createSelector("showSheet:"), paramsArray, false);
}
finally {
invoke(pool, "release");
}
if (fakeTitle != null) {
pane.putClientProperty(MacUtil.MAC_NATIVE_WINDOW_SHOWING, Boolean.TRUE);
pane.putClientProperty(MAC_SHEET_ID, fakeTitle);
MacUtil.startModal(pane);
IdeFocusManager.getGlobalInstance().setTypeaheadEnabled(true);
Integer result = (Integer)pane.getClientProperty(MAC_SHEET_RESULT);
boolean suppress = Boolean.TRUE == pane.getClientProperty(MAC_SHEET_SUPPRESS);
IdeFocusManager.getGlobalInstance().setTypeaheadEnabled(false);
// DEFAULT = 1
// ALTERNATE = 0
// OTHER = -1 (cancel)
int cancelCode = 1;
int code;
if (alternateText != null) {
// DEFAULT = 0
// ALTERNATE = 1
// CANCEL = 2
cancelCode = 2;
runOrPostponeForWindow(documentRoot, new Runnable() {
@Override
public void run() {
invoke(delegate, "performSelectorOnMainThread:withObject:waitUntilDone:",
Foundation.createSelector("showSheet:"), paramsArray, false);
}
});
startModal(documentRoot, focusedWindow);
IdeFocusManager.getGlobalInstance().setTypeaheadEnabled(true);
if (result == null) result = 2;
switch (result) {
case 1:
code = 0;
break;
case 0:
code = 1;
break;
case -1: // cancel
default:
code = 2;
break;
}
}
else {
// DEFAULT = 0
// CANCEL = 1
}
finally {
invoke(pool, "release");
}
return convertRetunCodeFromNativeAlertDialog(documentRoot, alternateText);
cancelCode = 1;
}
if (result == null) result = -1;
private static int convertRetunCodeFromNativeAlertDialog(Window documentRoot, String alternateText) {
Integer result = resultsFromDocumentRoot.remove(documentRoot);
switch (result) {
case 1:
code = 0;
break;
case -1: // cancel
default:
code = 1;
break;
}
}
// DEFAULT = 1
// ALTERNATE = 0
// OTHER = -1 (cancel)
if (doNotAskDialogOption != null && doNotAskDialogOption.canBeHidden()) {
if (cancelCode != code || doNotAskDialogOption.shouldSaveOptionsOnCancel()) {
doNotAskDialogOption.setToBeShown(!suppress, code);
}
}
int cancelCode = 1;
int code;
if (alternateText != null) {
// DEFAULT = 0
// ALTERNATE = 1
// CANCEL = 2
pane.putClientProperty(MAC_SHEET_RESULT, null);
pane.putClientProperty(MAC_SHEET_SUPPRESS, null);
cancelCode = 2;
if (focusTrackback[0] != null &&
!(focusTrackback[0].isSheduledForRestore() || focusTrackback[0].isWillBeSheduledForRestore())) {
focusTrackback[0].setWillBeSheduledForRestore();
if (result == null) result = 2;
IdeFocusManager mgr = IdeFocusManager.findInstanceByComponent(_window);
Runnable r = new Runnable() {
public void run() {
if (focusTrackback[0] != null) focusTrackback[0].restoreFocus();
focusTrackback[0] = null;
}
};
mgr.doWhenFocusSettlesDown(r);
}
switch (result) {
case 1:
code = 0;
break;
case 0:
code = 1;
break;
case -1: // cancel
default:
code = 2;
break;
}
}
else {
// DEFAULT = 0
// CANCEL = 1
return code;
}
cancelCode = 1;
if (result == null) result = -1;
switch (result) {
case 1:
code = 0;
break;
case -1: // cancel
default:
code = 1;
break;
}
}
return code;
}
private static void runOrPostponeForWindow(Window documentRoot, Runnable task) {
synchronized (lock) {
MacMessagesQueue<Runnable> queue = queuesFromDocumentRoot.get(documentRoot);
if (queue == null) {
queue = new MacMessagesQueue<Runnable>();
queuesFromDocumentRoot.put(documentRoot, queue);
}
queue.runOrEnqueue(task);
}
}
private static Window getDocumetnRootFromWindow(Window window) {
if (window == null) {
Window _window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
if (_window == null) {
Component focusOwner = IdeFocusManager.findInstance().getFocusOwner();
if (focusOwner != null) {
_window = SwingUtilities.getWindowAncestor(focusOwner);
}
return -1;
if (_window == null) {
_window = WindowManager.getInstance().findVisibleFrame();
}
}
}, window);
window = _window;
}
return findDocumentRoot(window);
}
public static int showMessageDialog(String title,
@@ -0,0 +1,49 @@
/*
* Copyright 2000-2013 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.ui.mac;
import java.util.LinkedList;
/**
* @author Denis Fokin
*/
class MacMessagesQueue<T extends Runnable> {
private boolean waitingForAppKit = false;
private LinkedList<Runnable> queueModel = new LinkedList<Runnable>();
synchronized void runOrEnqueue (final T runnable) {
if (waitingForAppKit) {
enqueue(runnable);
} else {
runnable.run();
waitingForAppKit = true;
}
}
private void enqueue (final T runnable) {
queueModel.add(runnable);
}
synchronized void runFromQueue () {
if (!queueModel.isEmpty()) {
queueModel.remove().run();
waitingForAppKit = true;
} else {
waitingForAppKit = false;
}
}
}
@@ -1,3 +1,18 @@
<!--
~ Copyright 2000-2013 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.
-->
<component>
<actions>
@@ -578,6 +593,7 @@
<action id="UiInspector" internal="true" class="com.intellij.internal.inspector.UiInspectorAction" text="UI Inspector"/>
<action id="ShowSplash" internal="true" class="com.intellij.ui.ShowSplashAction" text="Show Splash" />
<action id="ValidationTest" internal="true" class="com.intellij.internal.validation.TestDialogWithValidationAction" text="Validation Dialog Test" />
<action id="MacMessagesSequencesTest" internal="true" class="com.intellij.internal.validation.TestMacMessagesSequencesAction" text="Test Mac Messages Sequences" />
<action id="MacMessagesTest" internal="true" class="com.intellij.internal.validation.TestMacMessagesAction" text="Test Mac Messages" />
<action id="TreeExpandAll" internal="true" class="com.intellij.internal.tree.ExpandAll" text="Expand Tree" />
<action id="UIDefaults" internal="true" class="com.intellij.ui.ShowUIDefaultsAction" text="LaF Defaults"/>