Better topmost window evaluation, ModalityHelper is extracted in a separate class. Some warnings have been eliminated.

This commit is contained in:
Denis Fokin
2013-10-04 16:31:44 +04:00
parent 2c4d4ee5b4
commit d096aecf66
2 changed files with 114 additions and 51 deletions
@@ -0,0 +1,86 @@
/*
* 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.openapi.wm.impl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.wm.IdeFrame;
import javax.swing.*;
import java.awt.*;
import java.lang.reflect.Method;
/**
* @author Denis Fokin
*/
public class ModalityHelper {
private static final Logger LOG = Logger.getInstance(ModalityHelper.class);
private static Method isModalBlockedMethod = null;
private static Method getModalBlockerMethod = null;
static {
Class [] noParams = new Class [] {};
try {
isModalBlockedMethod = Window.class.getDeclaredMethod("isModalBlocked", noParams);
getModalBlockerMethod = Window.class.getDeclaredMethod("getModalBlocker", noParams);
isModalBlockedMethod.setAccessible(true);
getModalBlockerMethod.setAccessible(true);
}
catch (NoSuchMethodException e) {
LOG.error(e);
}
}
public static boolean isModalBlocked (final Window window) {
boolean result = false;
try {
result = (Boolean)isModalBlockedMethod.invoke(window);
}
catch (Exception e) {
LOG.error(e);
}
return result;
}
public static JDialog getModalBlockerFor (final Window window) {
JDialog result = null;
try {
result = (JDialog)getModalBlockerMethod.invoke(window);
}
catch (Exception e) {
LOG.error(e);
}
return result;
}
public static JDialog getBlockerForFrame(final IdeFrame ideFrame) {
if (ideFrame == null) return null;
Component c = ideFrame.getComponent();
if (c == null) return null;
Window window = SwingUtilities.getWindowAncestor(c);
if (window == null) return null;
if (!isModalBlocked(window)) return null;
return getModalBlockerFor(window);
}
public static JDialog getBlockerForFocusedFrame() {
return getBlockerForFrame(IdeFocusManagerImpl.getGlobalInstance().getLastFocusedFrame());
}
}
@@ -22,7 +22,7 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.ui.mac.foundation.Foundation;
import com.intellij.openapi.wm.impl.ModalityHelper;
import com.intellij.ui.mac.foundation.ID;
import com.intellij.ui.mac.foundation.MacUtil;
import com.intellij.util.ui.UIUtil;
@@ -34,7 +34,6 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
@@ -67,7 +66,7 @@ public class MacMessagesImpl extends MacMessages {
processResult(documentRoot);
ID suppressState = invoke(invoke(alert, "suppressionButton"), "state");
resultsFromDocumentRoot.put(documentRoot, new MessageResult(returnCode.intValue(),
suppressState.intValue() == 1 ? true : false));
suppressState.intValue() == 1));
queuesFromDocumentRoot.get(windowFromId.get(contextInfo.longValue())).runFromQueue();
}
cfRelease(self);
@@ -198,34 +197,20 @@ public class MacMessagesImpl extends MacMessages {
private MacMessagesImpl() {}
private static Method isModalBlockedMethod = null;
private static Method getModalBlockerMethod = null;
static {
if (SystemInfo.isMac) {
final ID delegateClass = Foundation.allocateObjcClassPair(Foundation.getObjcClass("NSObject"), "NSAlertDelegate_");
if (!Foundation.addMethod(delegateClass, Foundation.createSelector("alertDidEnd:returnCode:contextInfo:"), SHEET_DID_END, "v*")) {
final ID delegateClass = allocateObjcClassPair(getObjcClass("NSObject"), "NSAlertDelegate_");
if (!addMethod(delegateClass, createSelector("alertDidEnd:returnCode:contextInfo:"), SHEET_DID_END, "v*")) {
throw new RuntimeException("Unable to add method to objective-c delegate class!");
}
if (!Foundation.addMethod(delegateClass, Foundation.createSelector("showSheet:"), SIMPLE_SHEET_PANEL, "v*")) {
if (!addMethod(delegateClass, createSelector("showSheet:"), SIMPLE_SHEET_PANEL, "v*")) {
throw new RuntimeException("Unable to add method to objective-c delegate class!");
}
if (!Foundation.addMethod(delegateClass, Foundation.createSelector("showVariableButtonsSheet:"), VARIABLE_BUTTONS_SHEET_PANEL, "v*")) {
if (!addMethod(delegateClass, createSelector("showVariableButtonsSheet:"), VARIABLE_BUTTONS_SHEET_PANEL, "v*")) {
throw new RuntimeException("Unable to add method to objective-c delegate class!");
}
Foundation.registerObjcClassPair(delegateClass);
registerObjcClassPair(delegateClass);
}
Class [] noParams = new Class [] {};
try {
isModalBlockedMethod = Window.class.getDeclaredMethod("isModalBlocked", noParams);
getModalBlockerMethod = Window.class.getDeclaredMethod("getModalBlocker", noParams);
}
catch (NoSuchMethodException e) {
LOG.error(e);
}
}
@Override
@@ -266,9 +251,6 @@ public class MacMessagesImpl extends MacMessages {
return showAlertDialog(title, defaultButton, alternateButton, otherButton, message, window, false, doNotAskOption);
}
final private static Object lock = new Object();
final private static HashMap<Window, Integer> blockedDocumentRoots = new HashMap<Window, Integer>();
@@ -669,24 +651,19 @@ public class MacMessagesImpl extends MacMessages {
}
}
@NotNull
private static Window getForemostWindow(final Window window) {
Window _window = null;
IdeFocusManager ideFocusManager = IdeFocusManager.getGlobalInstance();
Component focusOwner = IdeFocusManager.findInstance().getFocusOwner();
// Let's ask for a focused component first
if (focusOwner != null) {
_window = SwingUtilities.getWindowAncestor(focusOwner);
}
if (_window == null && window != null) {
focusOwner = window.getMostRecentFocusOwner();
if (focusOwner != null) {
_window = SwingUtilities.getWindowAncestor(focusOwner);
}
}
if (_window == null) {
focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
// Looks like ide lost focus, let's ask about the last focused component
focusOwner = ideFocusManager.getLastFocusedFor(ideFocusManager.getLastFocusedFrame());
if (focusOwner != null) {
_window = SwingUtilities.getWindowAncestor(focusOwner);
}
@@ -696,26 +673,26 @@ public class MacMessagesImpl extends MacMessages {
_window = WindowManager.getInstance().findVisibleFrame();
}
if (_window != null) {
synchronized (_window.getTreeLock()) {
try {
isModalBlockedMethod.setAccessible(true);
if ((Boolean)isModalBlockedMethod.invoke(_window, null)) {
getModalBlockerMethod.setAccessible(true);
_window = (Dialog)getModalBlockerMethod.invoke(_window, null);
}
}
catch (InvocationTargetException e) {
LOG.error(e);
}
catch (IllegalAccessException e) {
LOG.error(e);
}
if (_window == null && window != null) {
// It might be we just has not opened a frame yet.
// So let's ask AWT
focusOwner = window.getMostRecentFocusOwner();
if (focusOwner != null) {
_window = SwingUtilities.getWindowAncestor(focusOwner);
}
}
while (getWindowTitle(_window) == null) {
if (_window != null) {
// We have successfully found the window
// Let's check that we have not missed a blocker
if (ModalityHelper.isModalBlocked(_window)) {
_window = ModalityHelper.getModalBlockerFor(_window);
}
}
//Actually can, but not in this implementation. If you know a reasonable scenario, please ask Denis Fokin for the improvement.
LOG.assertTrue(getWindowTitle(_window) != null, "A window without a title should not be used for showing MacMessages");
while (_window != null && getWindowTitle(_window) == null) {
_window = _window.getOwner();
//At least our frame should have a title
}