dialogs: showAndAndGetOk() for notifiyng when focus is settled after the show
[fedora-idea.git] / platform / platform-impl / src / com / intellij / openapi / ui / impl / DialogWrapperPeerImpl.java
blobc6355f45387789e9dc6f96fe858d21a9cc5c6a4a
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.openapi.ui.impl;
18 import com.intellij.ide.DataManager;
19 import com.intellij.ide.IdeEventQueue;
20 import com.intellij.ide.impl.TypeSafeDataProviderAdapter;
21 import com.intellij.ide.ui.UISettings;
22 import com.intellij.openapi.Disposable;
23 import com.intellij.openapi.actionSystem.*;
24 import com.intellij.openapi.application.Application;
25 import com.intellij.openapi.application.ApplicationManager;
26 import com.intellij.openapi.application.impl.LaterInvocator;
27 import com.intellij.openapi.command.CommandProcessor;
28 import com.intellij.openapi.command.CommandProcessorEx;
29 import com.intellij.openapi.diagnostic.Logger;
30 import com.intellij.openapi.project.DumbAware;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.ui.DialogWrapper;
33 import com.intellij.openapi.ui.DialogWrapperDialog;
34 import com.intellij.openapi.ui.DialogWrapperPeer;
35 import com.intellij.openapi.ui.TestableUi;
36 import com.intellij.openapi.ui.popup.StackingPopupDispatcher;
37 import com.intellij.openapi.util.*;
38 import com.intellij.openapi.util.registry.Registry;
39 import com.intellij.openapi.wm.FocusCommand;
40 import com.intellij.openapi.wm.IdeFocusManager;
41 import com.intellij.openapi.wm.KeyEventProcessor;
42 import com.intellij.openapi.wm.WindowManager;
43 import com.intellij.openapi.wm.ex.WindowManagerEx;
44 import com.intellij.openapi.wm.impl.IdeFrameImpl;
45 import com.intellij.openapi.wm.impl.IdeGlassPaneImpl;
46 import com.intellij.ui.AppUIUtil;
47 import com.intellij.ui.FocusTrackback;
48 import com.intellij.ui.ScreenUtil;
49 import com.intellij.ui.SpeedSearchBase;
50 import com.intellij.ui.popup.StackingPopupDispatcherImpl;
51 import com.intellij.util.ui.UIUtil;
52 import org.jetbrains.annotations.NonNls;
53 import org.jetbrains.annotations.NotNull;
54 import org.jetbrains.annotations.Nullable;
56 import javax.swing.*;
57 import java.awt.*;
58 import java.awt.event.*;
59 import java.awt.image.BufferStrategy;
60 import java.lang.ref.WeakReference;
61 import java.lang.reflect.Field;
62 import java.lang.reflect.Method;
63 import java.util.ArrayList;
64 import java.util.List;
65 import java.util.Map;
67 public class DialogWrapperPeerImpl extends DialogWrapperPeer implements FocusTrackbackProvider {
68 private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.ui.DialogWrapper");
70 private DialogWrapper myWrapper;
71 private MyDialog myDialog;
72 private boolean myCanBeParent = true;
74 * Default dialog's actions.
76 private WindowManagerEx myWindowManager;
77 private final java.util.List<Runnable> myDisposeActions = new ArrayList<Runnable>();
78 private Project myProject;
80 private ActionCallback myWindowFocusedCallback = new ActionCallback("DialogFocusedCallback");
81 private ActionCallback myTypeAheadDone = new ActionCallback("DialogTypeAheadDone");
83 /**
84 * Creates modal <code>DialogWrapper</code>. The currently active window will be the dialog's parent.
86 * @param project parent window for the dialog will be calculated based on focused window for the
87 * specified <code>project</code>. This parameter can be <code>null</code>. In this case parent window
88 * will be suggested based on current focused window.
89 * @param canBeParent specifies whether the dialog can be parent for other windows. This parameter is used
90 * by <code>WindowManager</code>.
92 protected DialogWrapperPeerImpl(DialogWrapper wrapper, Project project, boolean canBeParent) {
93 myWrapper = wrapper;
94 myWindowManager = null;
95 Application application = ApplicationManager.getApplication();
96 if (application != null && application.hasComponent(WindowManager.class)) {
97 myWindowManager = (WindowManagerEx)WindowManager.getInstance();
100 Window window = null;
101 if (myWindowManager != null) {
103 if (project == null) {
104 project = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext());
107 myProject = project;
109 window = myWindowManager.suggestParentWindow(project);
110 if (window == null) {
111 Window focusedWindow = myWindowManager.getMostRecentFocusedWindow();
112 if (focusedWindow instanceof IdeFrameImpl) {
113 window = focusedWindow;
118 Window owner;
119 if (window != null) {
120 owner = window;
122 else {
123 owner = JOptionPane.getRootFrame();
126 createDialog(owner, canBeParent);
129 protected DialogWrapperPeerImpl(DialogWrapper wrapper, boolean canBeParent) {
130 this(wrapper, (Project)null, canBeParent);
134 * @param parent parent component whicg is used to canculate heavy weight window ancestor.
135 * <code>parent</code> cannot be <code>null</code> and must be showing.
137 protected DialogWrapperPeerImpl(DialogWrapper wrapper, @NotNull Component parent, boolean canBeParent) {
138 myWrapper = wrapper;
139 if (!parent.isShowing() && parent != JOptionPane.getRootFrame()) {
140 throw new IllegalArgumentException("parent must be showing: " + parent);
142 myWindowManager = null;
143 Application application = ApplicationManager.getApplication();
144 if (application != null && application.hasComponent(WindowManager.class)) {
145 myWindowManager = (WindowManagerEx)WindowManager.getInstance();
148 Window owner = parent instanceof Window ? (Window)parent : (Window)SwingUtilities.getAncestorOfClass(Window.class, parent);
149 if (!(owner instanceof Dialog) && !(owner instanceof Frame)) {
150 owner = JOptionPane.getRootFrame();
152 createDialog(owner, canBeParent);
155 public DialogWrapperPeerImpl(final DialogWrapper wrapper, final boolean canBeParent, final boolean tryToolkitModal) {
156 myWrapper = wrapper;
157 myWindowManager = null;
158 Application application = ApplicationManager.getApplication();
159 if (application != null && application.hasComponent(WindowManager.class)) {
160 myWindowManager = (WindowManagerEx)WindowManager.getInstance();
162 if (UIUtil.hasJdk6Dialogs()) {
163 createDialog(null, canBeParent);
164 if (tryToolkitModal) {
165 UIUtil.setToolkitModal(myDialog);
168 else {
169 createDialog(JOptionPane.getRootFrame(), canBeParent);
173 public void setUndecorated(boolean undecorated) {
174 myDialog.setUndecorated(undecorated);
177 public void addMouseListener(MouseListener listener) {
178 myDialog.addMouseListener(listener);
181 public void addMouseListener(MouseMotionListener listener) {
182 myDialog.addMouseMotionListener(listener);
185 public void addKeyListener(KeyListener listener) {
186 myDialog.addKeyListener(listener);
189 private void createDialog(Window owner, boolean canBeParent) {
190 if (owner instanceof Frame) {
191 myDialog = new MyDialog((Frame)owner, myWrapper, myProject, myWindowFocusedCallback, myTypeAheadDone);
193 else {
194 myDialog = new MyDialog((Dialog)owner, myWrapper, myProject, myWindowFocusedCallback, myTypeAheadDone);
196 myDialog.setModal(true);
197 myCanBeParent = canBeParent;
202 public void toFront() {
203 myDialog.toFront();
206 public void toBack() {
207 myDialog.toBack();
210 protected void dispose() {
211 LOG.assertTrue(EventQueue.isDispatchThread(), "Access is allowed from event dispatch thread only");
212 for (Runnable runnable : myDisposeActions) {
213 runnable.run();
215 myDisposeActions.clear();
216 final JRootPane root = myDialog.getRootPane();
218 Runnable disposer = new Runnable() {
219 public void run() {
220 myDialog.dispose();
221 myProject = null;
223 if (myWindowManager == null) {
224 myDialog.dispose();
226 else {
227 myWindowManager.hideDialog(myDialog, myProject);
231 SwingUtilities.invokeLater(new Runnable() {
232 public void run() {
233 if (myDialog != null && root != null) {
234 myDialog.remove(root);
241 if (EventQueue.isDispatchThread()) {
242 disposer.run();
244 else {
245 SwingUtilities.invokeLater(disposer);
249 private boolean isProgressDialog() {
250 return myWrapper.isModalProgress();
253 @Nullable
254 public Container getContentPane() {
255 return getRootPane() != null ? myDialog.getContentPane() : null;
259 * @see javax.swing.JDialog#validate
261 public void validate() {
262 myDialog.validate();
266 * @see javax.swing.JDialog#repaint
268 public void repaint() {
269 myDialog.repaint();
272 public Window getOwner() {
273 return myDialog.getOwner();
276 public Window getWindow() {
277 return myDialog;
280 public JRootPane getRootPane() {
281 return myDialog.getRootPane();
284 public Dimension getSize() {
285 return myDialog.getSize();
288 public String getTitle() {
289 return myDialog.getTitle();
293 * @see java.awt.Window#pack
295 public void pack() {
296 myDialog.pack();
299 public void setIconImages(final List<Image> image) {
300 UIUtil.updateDialogIcon(myDialog, image);
303 public void setAppIcons() {
304 setIconImages(AppUIUtil.getAppIconImages());
307 public Dimension getPreferredSize() {
308 return myDialog.getPreferredSize();
311 public void setModal(boolean modal) {
312 myDialog.setModal(modal);
315 public boolean isVisible() {
316 return myDialog.isVisible();
319 public boolean isShowing() {
320 return myDialog.isShowing();
323 public void setSize(int width, int height) {
324 myDialog.setSize(width, height);
327 public void setTitle(String title) {
328 myDialog.setTitle(title);
331 public void isResizable() {
332 myDialog.isResizable();
335 public void setResizable(boolean resizable) {
336 myDialog.setResizable(resizable);
339 public Point getLocation() {
340 return myDialog.getLocation();
343 public void setLocation(Point p) {
344 myDialog.setLocation(p);
347 public void setLocation(int x, int y) {
348 myDialog.setLocation(x, y);
351 public ActionCallback show() {
352 final ActionCallback result = new ActionCallback();
354 LOG.assertTrue(EventQueue.isDispatchThread(), "Access is allowed from event dispatch thread only");
356 final AnCancelAction anCancelAction = new AnCancelAction();
357 final JRootPane rootPane = getRootPane();
358 anCancelAction.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0)), rootPane);
359 myDisposeActions.add(new Runnable() {
360 public void run() {
361 anCancelAction.unregisterCustomShortcutSet(rootPane);
365 if (!myCanBeParent && myWindowManager != null) {
366 myWindowManager.doNotSuggestAsParent(myDialog);
369 final CommandProcessorEx commandProcessor =
370 ApplicationManager.getApplication() != null ? (CommandProcessorEx)CommandProcessor.getInstance() : null;
371 final boolean appStarted = commandProcessor != null;
373 if (myDialog.isModal() && !isProgressDialog()) {
375 if (ApplicationManager.getApplication() != null) {
376 if (ApplicationManager.getApplication().getCurrentWriteAction(null) != null) {
377 LOG.warn(
378 "Showing of a modal dialog inside write-action may be dangerous and resulting in unpredictable behavior! Current modalityState=" + ModalityState.current(), new Exception());
382 if (appStarted) {
383 commandProcessor.enterModal();
384 LaterInvocator.enterModal(myDialog);
388 if (appStarted) {
389 hidePopupsIfNeeded();
392 try {
393 myDialog.show();
395 finally {
396 if (myDialog.isModal() && !isProgressDialog()) {
397 if (appStarted) {
398 commandProcessor.leaveModal();
399 LaterInvocator.leaveModal(myDialog);
403 myDialog.getFocusManager().doWhenFocusSettlesDown(new Runnable() {
404 public void run() {
405 result.setDone();
410 return result;
413 //[kirillk] for now it only deals with the TaskWindow under Mac OS X: modal dialogs are shown behind JBPopup
415 //hopefully this whole code will go away
416 private void hidePopupsIfNeeded() {
417 if (!SystemInfo.isMac) return;
419 StackingPopupDispatcherImpl.getInstance().hidePersistentPopups();
420 myDisposeActions.add(new Runnable() {
421 public void run() {
422 StackingPopupDispatcherImpl.getInstance().restorePersistentPopups();
427 public FocusTrackback getFocusTrackback() {
428 return myDialog.getFocusTrackback();
431 private class AnCancelAction extends AnAction implements DumbAware {
432 public void update(AnActionEvent e) {
433 Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
434 e.getPresentation().setEnabled(false);
435 if (focusOwner instanceof JComponent && SpeedSearchBase.hasActiveSpeedSearch((JComponent)focusOwner)) {
436 return;
439 if (StackingPopupDispatcher.getInstance().isPopupFocused()) return;
441 if (focusOwner instanceof JTree) {
442 JTree tree = (JTree)focusOwner;
443 if (!tree.isEditing()) {
444 e.getPresentation().setEnabled(true);
447 else if (focusOwner instanceof JTable) {
448 JTable table = (JTable)focusOwner;
449 if (!table.isEditing()) {
450 e.getPresentation().setEnabled(true);
455 public void actionPerformed(AnActionEvent e) {
456 myWrapper.doCancelAction(e.getInputEvent());
461 private static class MyDialog extends JDialog implements DialogWrapperDialog, DataProvider, FocusTrackback.Provider, TestableUi {
462 private final WeakReference<DialogWrapper> myDialogWrapper;
464 * Initial size of the dialog. When the dialog is being closed and
465 * current size of the dialog is not equals to the initial sizethen the
466 * current (changed) size is stored in the <code>DimensionService</code>.
468 private Dimension myInitialSize;
469 private String myDimensionServiceKey;
470 private boolean myOpened = false;
472 private FocusTrackback myFocusTrackback;
473 private MyDialog.MyWindowListener myWindowListener;
474 private MyDialog.MyComponentListener myComponentListener;
476 private final WeakReference<Project> myProject;
477 private ActionCallback myFocusedCallback;
478 private ActionCallback myTypeAheadDone;
480 public MyDialog(Dialog owner, DialogWrapper dialogWrapper, Project project, ActionCallback focused, ActionCallback typeAheadDone) {
481 super(owner);
482 myDialogWrapper = new WeakReference<DialogWrapper>(dialogWrapper);
483 myProject = project != null ? new WeakReference<Project>(project) : null;
484 initDialog(focused, typeAheadDone);
487 public MyDialog(Frame owner, DialogWrapper dialogWrapper, Project project, ActionCallback focused, ActionCallback typeAheadDone) {
488 super(owner);
489 myDialogWrapper = new WeakReference<DialogWrapper>(dialogWrapper);
490 myProject = project != null ? new WeakReference<Project>(project) : null;
491 initDialog(focused, typeAheadDone);
494 private void initDialog(ActionCallback focused, ActionCallback typeAheadDone) {
495 myFocusedCallback = focused;
496 myTypeAheadDone = typeAheadDone;
498 final long typeAhead = getDialogWrapper().getTypeAheadTimeoutMs();
499 if (typeAhead <= 0) {
500 myTypeAheadDone.setDone();
503 setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
504 myWindowListener = new MyWindowListener();
505 addWindowListener(myWindowListener);
506 myComponentListener = new MyComponentListener();
507 addComponentListener(myComponentListener);
510 public void putInfo(Map<String, String> info) {
511 info.put("dialog", getTitle());
514 public FocusTrackback getFocusTrackback() {
515 return myFocusTrackback;
518 public DialogWrapper getDialogWrapper() {
519 return myDialogWrapper.get();
522 public void centerInParent() {
523 setLocationRelativeTo(getOwner());
526 public Object getData(String dataId) {
527 final DialogWrapper wrapper = myDialogWrapper.get();
528 if (wrapper instanceof DataProvider) {
529 return ((DataProvider)wrapper).getData(dataId);
531 else if (wrapper instanceof TypeSafeDataProvider) {
532 TypeSafeDataProviderAdapter adapter = new TypeSafeDataProviderAdapter((TypeSafeDataProvider)wrapper);
533 return adapter.getData(dataId);
535 return null;
538 public void setSize(int width, int height) {
539 Point location = getLocation();
540 Rectangle rect = new Rectangle(location.x, location.y, width, height);
541 ScreenUtil.fitToScreen(rect);
542 if (location.x != rect.x || location.y != rect.y) {
543 setLocation(rect.x, rect.y);
546 super.setSize(rect.width, rect.height);
549 public void setBounds(int x, int y, int width, int height) {
550 Rectangle rect = new Rectangle(x, y, width, height);
551 ScreenUtil.fitToScreen(rect);
552 super.setBounds(rect.x, rect.y, rect.width, rect.height);
555 public void setBounds(Rectangle r) {
556 ScreenUtil.fitToScreen(r);
557 super.setBounds(r);
560 protected JRootPane createRootPane() {
561 return new DialogRootPane();
564 public void show() {
565 myFocusTrackback = new FocusTrackback(myDialogWrapper, this, true);
567 final DialogWrapper dialogWrapper = getDialogWrapper();
569 pack();
570 setSize((int)(getWidth() * dialogWrapper.getHorizontalStretch()), (int)(getHeight() * dialogWrapper.getVerticalStretch()));
572 // Restore dialog's size and location
574 myDimensionServiceKey = dialogWrapper.getDimensionKey();
575 Point location = null;
577 if (myDimensionServiceKey != null) {
578 final Project projectGuess = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(this));
579 location = DimensionService.getInstance().getLocation(myDimensionServiceKey, projectGuess);
580 Dimension size = DimensionService.getInstance().getSize(myDimensionServiceKey, projectGuess);
581 if (size != null) {
582 myInitialSize = (Dimension)size.clone();
583 setSize(myInitialSize);
587 if (myInitialSize == null) {
588 myInitialSize = getSize();
591 if (location == null) {
592 location = dialogWrapper.getInitialLocation();
595 if (location != null) {
596 setLocation(location);
598 else {
599 setLocationRelativeTo(getOwner());
602 final Rectangle bounds = getBounds();
603 ScreenUtil.fitToScreen(bounds);
604 setBounds(bounds);
606 addWindowListener(new WindowAdapter() {
607 public void windowActivated(final WindowEvent e) {
608 final DialogWrapper wrapper = getDialogWrapper();
609 if (wrapper != null && myFocusTrackback != null) {
610 myFocusTrackback.registerFocusComponent(new FocusTrackback.ComponentQuery() {
611 public Component getComponent() {
612 return wrapper.getPreferredFocusedComponent();
618 public void windowDeactivated(final WindowEvent e) {
619 if (!isModal()) {
620 final Ref<IdeFocusManager> focusManager = new Ref<IdeFocusManager>(null);
621 if (myProject != null && myProject.get() != null && !myProject.get().isDisposed()) {
622 focusManager.set(getFocusManager());
623 focusManager.get().doWhenFocusSettlesDown(new Runnable() {
624 public void run() {
625 disposeFocusTrackbackIfNoChildWindowFocused(focusManager.get());
629 else {
630 disposeFocusTrackbackIfNoChildWindowFocused(focusManager.get());
636 if (Registry.is("actionSystem.fixLostTyping")) {
637 final IdeEventQueue queue = IdeEventQueue.getInstance();
638 if (queue != null) {
639 queue.getKeyEventDispatcher().resetState();
642 if (myProject != null) {
643 Project project = myProject.get();
644 if (project != null && !project.isDisposed() && project.isInitialized()) {
645 IdeFocusManager.findInstanceByComponent(this).requestFocus(new MyFocusCommand(dialogWrapper), true);
650 super.show();
653 private IdeFocusManager getFocusManager() {
654 if (myProject != null && myProject.get() != null && !myProject.get().isDisposed()) {
655 return IdeFocusManager.getInstance(myProject.get());
656 } else {
657 return IdeFocusManager.findInstance();
661 private void disposeFocusTrackbackIfNoChildWindowFocused(@Nullable IdeFocusManager focusManager) {
662 if (myFocusTrackback == null) return;
664 final DialogWrapper wrapper = myDialogWrapper.get();
665 if (wrapper == null || !wrapper.isShowing()) {
666 myFocusTrackback.dispose();
667 return;
670 if (focusManager != null) {
671 final Component c = focusManager.getFocusedDescendantFor(wrapper.getContentPane());
672 if (c == null) {
673 myFocusTrackback.dispose();
676 else {
677 final Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
678 if (owner == null || !SwingUtilities.isDescendingFrom(owner, wrapper.getContentPane())) {
679 myFocusTrackback.dispose();
684 @Deprecated
685 public void hide() {
686 super.hide();
687 if (myFocusTrackback != null && !(myFocusTrackback.isSheduledForRestore() || myFocusTrackback.isWillBeSheduledForRestore())) {
688 myFocusTrackback.setWillBeSheduledForRestore();
689 IdeFocusManager mgr = getFocusManager();
690 Runnable r = new Runnable() {
691 public void run() {
692 myFocusTrackback.restoreFocus();
693 myFocusTrackback = null;
696 mgr.doWhenFocusSettlesDown(r);
700 public void dispose() {
701 if (isShowing()) {
702 hide();
705 if (myWindowListener != null) {
706 myWindowListener.saveSize();
707 removeWindowListener(myWindowListener);
708 myWindowListener = null;
710 if (myComponentListener != null) {
711 removeComponentListener(myComponentListener);
712 myComponentListener = null;
715 if (myFocusTrackback != null && !(myFocusTrackback.isSheduledForRestore() || myFocusTrackback.isWillBeSheduledForRestore())) {
716 myFocusTrackback.dispose();
717 myFocusTrackback = null;
721 final BufferStrategy strategy = getBufferStrategy();
722 if (strategy != null) {
723 try {
724 Method method = strategy.getClass().getMethod("dispose"); // added in JDK 1.6 so cannot call directly
725 method.invoke(strategy);
727 catch (Exception ex) {
728 // ignore
731 super.dispose();
734 if (rootPane != null) { // Workaround for bug in native code to hold rootPane
735 try {
736 Field field = rootPane.getClass().getDeclaredField("glassPane");
737 field.setAccessible(true);
738 field.set(rootPane, null);
740 field = rootPane.getClass().getDeclaredField("contentPane");
741 field.setAccessible(true);
742 field.set(rootPane, null);
743 rootPane = null;
745 field = Window.class.getDeclaredField("windowListener");
746 field.setAccessible(true);
747 field.set(this, null);
749 catch (Exception e) {
753 // http://bugs.sun.com/view_bug.do?bug_id=6614056
754 try {
755 final Field field = Dialog.class.getDeclaredField("modalDialogs");
756 field.setAccessible(true);
757 final List<?> list = (List<?>)field.get(null);
758 list.remove(this);
760 catch (final Exception ex) {
764 @Override
765 public Component getMostRecentFocusOwner() {
766 if (!myOpened) {
767 final DialogWrapper wrapper = getDialogWrapper();
768 if (wrapper != null) {
769 JComponent toFocus = wrapper.getPreferredFocusedComponent();
770 if (toFocus != null) {
771 return toFocus;
775 return super.getMostRecentFocusOwner();
778 @Override
779 public void paint(Graphics g) {
780 UIUtil.applyRenderingHints(g);
781 super.paint(g);
784 private class MyWindowListener extends WindowAdapter {
785 public void windowClosing(WindowEvent e) {
786 DialogWrapper dialogWrapper = getDialogWrapper();
787 if (dialogWrapper.shouldCloseOnCross()) {
788 dialogWrapper.doCancelAction(e);
792 public void windowClosed(WindowEvent e) {
793 saveSize();
796 public void saveSize() {
797 if (myDimensionServiceKey != null &&
798 myInitialSize != null &&
799 myOpened) { // myInitialSize can be null only if dialog is disposed before first showing
800 final Project projectGuess = PlatformDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(MyDialog.this));
802 // Save location
803 Point location = getLocation();
804 DimensionService.getInstance().setLocation(myDimensionServiceKey, location, projectGuess);
805 // Save size
806 Dimension size = getSize();
807 if (!myInitialSize.equals(size)) {
808 DimensionService.getInstance().setSize(myDimensionServiceKey, size, projectGuess);
810 myOpened = false;
814 public void windowOpened(final WindowEvent e) {
815 SwingUtilities.invokeLater(new Runnable() {
816 public void run() {
817 myOpened = true;
818 final DialogWrapper activeWrapper = getActiveWrapper();
819 if (activeWrapper == null) {
820 myFocusedCallback.setRejected();
821 myTypeAheadDone.setRejected();
822 return;
825 JComponent toFocus = activeWrapper.getPreferredFocusedComponent();
826 if (toFocus == null) {
827 toFocus = getRootPane().getDefaultButton();
830 moveMousePointerOnButton(getRootPane().getDefaultButton());
831 setupSelectionOnPreferredComponent(toFocus);
833 if (toFocus != null) {
834 final JComponent toRequest = toFocus;
835 SwingUtilities.invokeLater(new Runnable() {
836 public void run() {
837 IdeFocusManager.findInstanceByComponent(e.getWindow()).requestFocus(toRequest, true);
838 notifyFocused(activeWrapper);
841 } else {
842 notifyFocused(activeWrapper);
848 private void notifyFocused(DialogWrapper wrapper) {
849 myFocusedCallback.setDone();
850 final long timeout = wrapper.getTypeAheadTimeoutMs();
851 if (timeout > 0) {
852 SimpleTimer.getInstance().setUp(new EdtRunnable() {
853 public void runEdt() {
854 myTypeAheadDone.setDone();
856 }, timeout);
860 private DialogWrapper getActiveWrapper() {
861 DialogWrapper activeWrapper = getDialogWrapper();
862 if (activeWrapper == null || !activeWrapper.isShowing()) {
863 return null;
866 return activeWrapper;
869 private void moveMousePointerOnButton(final JButton button) {
870 Application application = ApplicationManager.getApplication();
871 if (application != null && application.hasComponent(UISettings.class)) {
872 if (button != null && UISettings.getInstance().MOVE_MOUSE_ON_DEFAULT_BUTTON) {
873 Point p = button.getLocationOnScreen();
874 Rectangle r = button.getBounds();
875 try {
876 Robot robot = new Robot();
877 robot.mouseMove(p.x + r.width / 2, p.y + r.height / 2);
879 catch (AWTException exc) {
880 exc.printStackTrace();
887 private class MyComponentListener extends ComponentAdapter {
888 @SuppressWarnings({"RefusedBequest"})
889 public void componentResized(ComponentEvent e) {
890 final JRootPane pane = getRootPane();
891 if (pane == null) return;
892 final Dimension minSize = pane.getMinimumSize();
893 final Dimension size = pane.getSize();
894 final Dimension winSize = getSize();
895 if (minSize.width > size.width) {
896 winSize.width += minSize.width - size.width;
898 if (minSize.height > size.height) {
899 winSize.height += minSize.height - size.height;
902 if (!winSize.equals(getSize())) {
903 SwingUtilities.invokeLater(new Runnable() {
904 public void run() {
905 if (isShowing()) {
906 setSize(winSize);
914 private class DialogRootPane extends JRootPane implements DataProvider {
916 private final boolean myGlassPaneIsSet;
918 private DialogRootPane() {
919 setGlassPane(new IdeGlassPaneImpl(this));
920 myGlassPaneIsSet = true;
923 @Override
924 public void setGlassPane(final Component glass) {
925 if (myGlassPaneIsSet) {
926 LOG.warn("Setting of glass pane for DialogWrapper is prohibited", new Exception());
927 return;
930 super.setGlassPane(glass);
933 public Object getData(@NonNls String dataId) {
934 final DialogWrapper wrapper = myDialogWrapper.get();
935 return PlatformDataKeys.UI_DISPOSABLE.is(dataId) ? wrapper.getDisposable() : null;
940 private class MyFocusCommand extends FocusCommand implements KeyEventProcessor {
942 private Context myContextOnFinish;
943 private ArrayList<KeyEvent> myEvents = new ArrayList<KeyEvent>();
944 private DialogWrapper myWrapper;
946 private MyFocusCommand(DialogWrapper wrapper) {
947 myWrapper = getDialogWrapper();
949 Disposer.register(wrapper.getDisposable(), new Disposable() {
950 public void dispose() {
951 if (!myTypeAheadDone.isProcessed()) {
952 myTypeAheadDone.setDone();
955 flushEvents();
960 public ActionCallback run() {
961 return myTypeAheadDone;
964 @Override
965 public KeyEventProcessor getProcessor() {
966 return this;
969 public Boolean dispatch(KeyEvent e, Context context) {
970 if (myWrapper == null || myTypeAheadDone.isProcessed()) return null;
972 myEvents.addAll(context.getQueue());
973 context.getQueue().clear();
975 if (isToDipatchToDialogNow(e)) {
976 return false;
977 } else {
978 myEvents.add(e);
979 return true;
983 private boolean isToDipatchToDialogNow(KeyEvent e) {
984 return e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_ESCAPE || e.getKeyCode() == KeyEvent.VK_TAB;
987 public void finish(Context context) {
988 myContextOnFinish = context;
991 private void flushEvents() {
992 if (myWrapper.isToDispatchTypeAhead() && myContextOnFinish != null) {
993 myContextOnFinish.dispatch(myEvents);
999 private static void setupSelectionOnPreferredComponent(final JComponent component) {
1000 if (component instanceof JTextField) {
1001 JTextField field = (JTextField)component;
1002 String text = field.getText();
1003 if (text != null && field.getClientProperty(HAVE_INITIAL_SELECTION) == null) {
1004 field.setSelectionStart(0);
1005 field.setSelectionEnd(text.length());
1008 else if (component instanceof JComboBox) {
1009 JComboBox combobox = (JComboBox)component;
1010 combobox.getEditor().selectAll();
1014 public void setContentPane(JComponent content) {
1015 myDialog.setContentPane(content);
1018 public void centerInParent() {
1019 myDialog.centerInParent();