mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
mac sheets emulation
This commit is contained in:
@@ -100,6 +100,8 @@ public abstract class DialogWrapper {
|
||||
|
||||
@NonNls public static final String FOCUSED_ACTION = "FocusedAction";
|
||||
|
||||
@NonNls private static final String NO_AUTORESIZE = "NoAutoResizeAndFit";
|
||||
|
||||
private static final KeyStroke SHOW_OPTION_KEYSTROKE = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
|
||||
InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);
|
||||
|
||||
@@ -771,6 +773,18 @@ public abstract class DialogWrapper {
|
||||
myPeer.toBack();
|
||||
}
|
||||
|
||||
protected boolean setAutoAdjustable(boolean autoAdjustable) {
|
||||
JRootPane rootPane = getRootPane();
|
||||
if (rootPane == null) return false;
|
||||
rootPane.putClientProperty(NO_AUTORESIZE, autoAdjustable? null : Boolean.TRUE);
|
||||
return true;
|
||||
}
|
||||
//true by default
|
||||
public boolean isAutoAdjustable() {
|
||||
JRootPane rootPane = getRootPane();
|
||||
return rootPane == null || rootPane.getClientProperty(NO_AUTORESIZE) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose the wrapped and releases all resources allocated be the wrapper to help
|
||||
* more effecient garbage collection. You should never invoke this method twice or
|
||||
@@ -793,7 +807,7 @@ public abstract class DialogWrapper {
|
||||
// if rootPane = null, dialog has already been disposed
|
||||
if (rootPane != null) {
|
||||
unregisterKeyboardActions(rootPane);
|
||||
if (myActualSize != null) {
|
||||
if (myActualSize != null && isAutoAdjustable()) {
|
||||
setSize(myActualSize.width, myActualSize.height);
|
||||
}
|
||||
myPeer.dispose();
|
||||
@@ -1102,7 +1116,7 @@ public abstract class DialogWrapper {
|
||||
myErrorText = new ErrorText();
|
||||
myErrorText.setVisible(false);
|
||||
|
||||
final JPanel root = new JPanel(new BorderLayout());
|
||||
final JPanel root = new JPanel(createRootLayout());
|
||||
//{
|
||||
// @Override
|
||||
// public void paint(Graphics g) {
|
||||
@@ -1168,6 +1182,10 @@ public abstract class DialogWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
LayoutManager createRootLayout() {
|
||||
return new BorderLayout();
|
||||
}
|
||||
|
||||
private static void installEnterHook(JComponent root) {
|
||||
new AnAction() {
|
||||
@Override
|
||||
|
||||
@@ -18,17 +18,21 @@ package com.intellij.openapi.ui;
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.ui.mac.MacMessages;
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.PairFunction;
|
||||
import com.intellij.util.execution.ParametersListUtil;
|
||||
@@ -44,8 +48,10 @@ import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Messages {
|
||||
public static final int OK = 0;
|
||||
@@ -138,6 +144,10 @@ public class Messages {
|
||||
&& !DialogWrapper.isMultipleModalDialogs();
|
||||
}
|
||||
|
||||
public static boolean isMacSheetEmulation() {
|
||||
return SystemInfo.isMac && !Registry.is("ide.mac.message.dialogs.as.sheets");
|
||||
}
|
||||
|
||||
public static int showDialog(Project project, String message, String title, String moreInfo, String[] options, int defaultOptionIndex, int focusedOptionIndex, Icon icon) {
|
||||
if (isApplicationInUnitTestOrHeadless()) {
|
||||
return ourTestImplementation.show(message);
|
||||
@@ -944,6 +954,7 @@ public class Messages {
|
||||
protected int myDefaultOptionIndex;
|
||||
protected int myFocusedOptionIndex;
|
||||
protected Icon myIcon;
|
||||
private MyBorderLayout myLayout;
|
||||
|
||||
public MessageDialog(@Nullable Project project, String message, String title, String[] options, int defaultOptionIndex, @Nullable Icon icon, boolean canBeParent) {
|
||||
this(project, message, title, options, defaultOptionIndex, -1, icon, canBeParent);
|
||||
@@ -1003,6 +1014,9 @@ public class Messages {
|
||||
|
||||
protected void _init(String title, String message, String[] options, int defaultOptionIndex, int focusedOptionIndex, @Nullable Icon icon, @Nullable DoNotAskOption doNotAskOption) {
|
||||
setTitle(title);
|
||||
if (isMacSheetEmulation()) {
|
||||
setUndecorated(true);
|
||||
}
|
||||
myMessage = message;
|
||||
myOptions = options;
|
||||
myDefaultOptionIndex = defaultOptionIndex;
|
||||
@@ -1061,6 +1075,90 @@ public class Messages {
|
||||
return doCreateCenterPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
LayoutManager createRootLayout() {
|
||||
return isMacSheetEmulation() ? myLayout = new MyBorderLayout() : super.createRootLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispose() {
|
||||
if (isMacSheetEmulation()) {
|
||||
animate();
|
||||
} else {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if (isMacSheetEmulation()) {
|
||||
setInitialLocationCallback(new Computable<Point>() {
|
||||
@Override
|
||||
public Point compute() {
|
||||
JRootPane rootPane = SwingUtilities.getRootPane(getWindow().getParent());
|
||||
if (rootPane == null) {
|
||||
rootPane = SwingUtilities.getRootPane(getWindow().getOwner());
|
||||
}
|
||||
|
||||
Point p = rootPane.getLocationOnScreen();
|
||||
p.x += (rootPane.getWidth() - getWindow().getWidth()) / 2;
|
||||
return p;
|
||||
}
|
||||
});
|
||||
animate();
|
||||
if (SystemInfo.isJavaVersionAtLeast("1.7")) {
|
||||
try {
|
||||
Method method = Class.forName("java.awt.Window").getDeclaredMethod("setOpacity", float.class);
|
||||
if (method != null) method.invoke(getPeer().getWindow(), .8f);
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
setAutoAdjustable(false);
|
||||
setSize(getPreferredSize().width, 0);//initial state before animation, zero height
|
||||
}
|
||||
super.show();
|
||||
}
|
||||
|
||||
private void animate() {
|
||||
final int height = getPreferredSize().height;
|
||||
final int frameCount = 10;
|
||||
final boolean toClose = isShowing();
|
||||
|
||||
|
||||
final AtomicInteger i = new AtomicInteger(-1);
|
||||
final Alarm animator = new Alarm(myDisposable);
|
||||
final Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int state = i.addAndGet(1);
|
||||
|
||||
double linearProgress = (double)state / frameCount;
|
||||
if (toClose) {
|
||||
linearProgress = 1 - linearProgress;
|
||||
}
|
||||
myLayout.myPhase = (1 - Math.cos(Math.PI * linearProgress)) / 2;
|
||||
Window window = getPeer().getWindow();
|
||||
Rectangle bounds = window.getBounds();
|
||||
bounds.height = (int)(height * myLayout.myPhase);
|
||||
|
||||
window.setBounds(bounds);
|
||||
|
||||
if (state == 0 && !toClose && window.getOwner() instanceof IdeFrame) {
|
||||
WindowManager.getInstance().requestUserAttention((IdeFrame)window.getOwner(), true);
|
||||
}
|
||||
|
||||
if (state < frameCount) {
|
||||
animator.addRequest(this, 10);
|
||||
}
|
||||
else if (toClose) {
|
||||
MessageDialog.super.dispose();
|
||||
}
|
||||
}
|
||||
};
|
||||
animator.addRequest(runnable, 10, ModalityState.stateForComponent(getRootPane()));
|
||||
}
|
||||
|
||||
protected JComponent doCreateCenterPanel() {
|
||||
JPanel panel = new JPanel(new BorderLayout(15, 0));
|
||||
if (myIcon != null) {
|
||||
@@ -1105,6 +1203,33 @@ public class Messages {
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyBorderLayout extends BorderLayout {
|
||||
private double myPhase = 0;//it varies from 0 (hidden state) to 1 (fully visible)
|
||||
|
||||
private MyBorderLayout() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layoutContainer(Container target) {
|
||||
final Dimension realSize = target.getSize();
|
||||
target.setSize(target.getPreferredSize());
|
||||
|
||||
super.layoutContainer(target);
|
||||
|
||||
target.setSize(realSize);
|
||||
|
||||
synchronized (target.getTreeLock()) {
|
||||
int yShift = (int)((1 - myPhase) * target.getPreferredSize().height);
|
||||
Component[] components = target.getComponents();
|
||||
for (Component component : components) {
|
||||
Point point = component.getLocation();
|
||||
point.y -= yShift;
|
||||
component.setLocation(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void installHyperlinkSupport(JTextPane messageComponent) {
|
||||
configureMessagePaneUi(messageComponent, "<html></html>");
|
||||
}
|
||||
|
||||
@@ -127,4 +127,6 @@ public abstract class WindowManager {
|
||||
* @return <code>true</code> if full screen mode is supported in current OS.
|
||||
*/
|
||||
public abstract boolean isFullScreenSupportedInCurrentOS();
|
||||
|
||||
public abstract void requestUserAttention(@NotNull IdeFrame frame, boolean critical);
|
||||
}
|
||||
|
||||
+41
-27
@@ -112,6 +112,15 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
|
||||
window = focusedWindow;
|
||||
}
|
||||
}
|
||||
if (window == null) {
|
||||
IdeFrame[] frames = myWindowManager.getAllProjectFrames();
|
||||
for (IdeFrame frame : frames) {
|
||||
if (frame instanceof IdeFrameImpl && ((IdeFrameImpl)frame).isActive()) {
|
||||
window = (IdeFrameImpl)frame;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Window owner;
|
||||
@@ -648,32 +657,34 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
|
||||
myFocusTrackback = new FocusTrackback(getDialogWrapper(), getParent(), true);
|
||||
|
||||
final DialogWrapper dialogWrapper = getDialogWrapper();
|
||||
|
||||
pack();
|
||||
|
||||
Dimension packedSize = getSize();
|
||||
Dimension minSize = getMinimumSize();
|
||||
setSize(Math.max(packedSize.width, minSize.width), Math.max(packedSize.height, minSize.height));
|
||||
|
||||
setSize((int)(getWidth() * dialogWrapper.getHorizontalStretch()), (int)(getHeight() * dialogWrapper.getVerticalStretch()));
|
||||
|
||||
// Restore dialog's size and location
|
||||
|
||||
myDimensionServiceKey = dialogWrapper.getDimensionKey();
|
||||
boolean isAutoAdjustable = dialogWrapper.isAutoAdjustable();
|
||||
Point location = null;
|
||||
if (isAutoAdjustable) {
|
||||
pack();
|
||||
|
||||
if (myDimensionServiceKey != null) {
|
||||
final Project projectGuess = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(this));
|
||||
location = DimensionService.getInstance().getLocation(myDimensionServiceKey, projectGuess);
|
||||
Dimension size = DimensionService.getInstance().getSize(myDimensionServiceKey, projectGuess);
|
||||
if (size != null) {
|
||||
myInitialSize = new Dimension(size);
|
||||
_setSizeForLocation(myInitialSize.width, myInitialSize.height, location);
|
||||
Dimension packedSize = getSize();
|
||||
Dimension minSize = getMinimumSize();
|
||||
setSize(Math.max(packedSize.width, minSize.width), Math.max(packedSize.height, minSize.height));
|
||||
|
||||
setSize((int)(getWidth() * dialogWrapper.getHorizontalStretch()), (int)(getHeight() * dialogWrapper.getVerticalStretch()));
|
||||
|
||||
// Restore dialog's size and location
|
||||
|
||||
myDimensionServiceKey = dialogWrapper.getDimensionKey();
|
||||
|
||||
if (myDimensionServiceKey != null) {
|
||||
final Project projectGuess = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(this));
|
||||
location = DimensionService.getInstance().getLocation(myDimensionServiceKey, projectGuess);
|
||||
Dimension size = DimensionService.getInstance().getSize(myDimensionServiceKey, projectGuess);
|
||||
if (size != null) {
|
||||
myInitialSize = new Dimension(size);
|
||||
_setSizeForLocation(myInitialSize.width, myInitialSize.height, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (myInitialSize == null) {
|
||||
myInitialSize = getSize();
|
||||
if (myInitialSize == null) {
|
||||
myInitialSize = getSize();
|
||||
}
|
||||
}
|
||||
|
||||
if (location == null) {
|
||||
@@ -687,10 +698,11 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
|
||||
setLocationRelativeTo(getOwner());
|
||||
}
|
||||
|
||||
final Rectangle bounds = getBounds();
|
||||
ScreenUtil.fitToScreen(bounds);
|
||||
setBounds(bounds);
|
||||
|
||||
if (isAutoAdjustable) {
|
||||
final Rectangle bounds = getBounds();
|
||||
ScreenUtil.fitToScreen(bounds);
|
||||
setBounds(bounds);
|
||||
}
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowActivated(WindowEvent e) {
|
||||
@@ -1052,7 +1064,9 @@ public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTra
|
||||
@Override
|
||||
@SuppressWarnings({"RefusedBequest"})
|
||||
public void componentResized(ComponentEvent e) {
|
||||
UIUtil.adjustWindowToMinimumSize(getWindow());
|
||||
if (getDialogWrapper().isAutoAdjustable()) {
|
||||
UIUtil.adjustWindowToMinimumSize(getWindow());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.openapi.wm.impl.CommandProcessor;
|
||||
import com.intellij.openapi.wm.impl.DesktopLayout;
|
||||
import com.intellij.openapi.wm.impl.IdeFrameImpl;
|
||||
import com.intellij.ui.AppIcon;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -41,6 +42,13 @@ public abstract class WindowManagerEx extends WindowManager {
|
||||
|
||||
public abstract IdeFrameImpl getFrame(@Nullable Project project);
|
||||
|
||||
@Override
|
||||
public void requestUserAttention(@NotNull IdeFrame frame, boolean critical) {
|
||||
Project project = frame.getProject();
|
||||
if (project != null)
|
||||
AppIcon.getInstance().requestAttention(project, critical);
|
||||
}
|
||||
|
||||
public abstract IdeFrameImpl allocateFrame(Project project);
|
||||
|
||||
public abstract void releaseFrame(IdeFrameImpl frame);
|
||||
|
||||
Reference in New Issue
Block a user