mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-107366 Messages.show... does not add an entity to modality state
This commit is contained in:
+40
@@ -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"/>
|
||||
|
||||
Reference in New Issue
Block a user