1. /*
  2. * @(#)Dialog.java 1.62 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt;
  8. import java.awt.peer.DialogPeer;
  9. import java.awt.event.*;
  10. import java.io.ObjectOutputStream;
  11. import java.io.ObjectInputStream;
  12. import java.io.IOException;
  13. import sun.awt.AxBridgeHelper;
  14. /**
  15. * A Dialog is a top-level window with a title and a border
  16. * that is typically used to take some form of input from the user.
  17. *
  18. * The size of the dialog includes any area designated for the
  19. * border. The dimensions of the border area can be obtained
  20. * using the <code>getInsets</code> method, however, since
  21. * these dimensions are platform-dependent, a valid insets
  22. * value cannot be obtained until the dialog is made displayable
  23. * by either calling <code>pack</code> or <code>show</code>.
  24. * Since the border area is included in the overall size of the
  25. * dialog, the border effectively obscures a portion of the dialog,
  26. * constraining the area available for rendering and/or displaying
  27. * subcomponents to the rectangle which has an upper-left corner
  28. * location of <code>(insets.left, insets.top)</code>, and has a size of
  29. * <code>width - (insets.left + insets.right)</code> by
  30. * <code>height - (insets.top + insets.bottom)</code>.
  31. * <p>
  32. * The default layout for a dialog is BorderLayout.
  33. * <p>
  34. * A dialog must have either a frame or another dialog defined as its
  35. * owner when it's constructed. When the owner window of a visible dialog
  36. * is hidden or minimized, the dialog will automatically be hidden
  37. * from the user. When the owner window is subsequently re-opened, then
  38. * the dialog is made visible to the user again.
  39. * <p>
  40. * A dialog can be either modeless (the default) or modal. A modal
  41. * dialog is one which blocks input to all other toplevel windows
  42. * in the app context, except for any windows created with the dialog
  43. * as their owner.
  44. * <p>
  45. * Dialogs are capable of generating the following window events:
  46. * WindowOpened, WindowClosing, WindowClosed, WindowActivated,
  47. * WindowDeactivated.
  48. *
  49. * @see WindowEvent
  50. * @see Window#addWindowListener
  51. *
  52. * @version 1.62, 11/29/01
  53. * @author Sami Shaio
  54. * @author Arthur van Hoff
  55. * @since JDK1.0
  56. */
  57. public class Dialog extends Window {
  58. static {
  59. /* ensure that the necessary native libraries are loaded */
  60. Toolkit.loadLibraries();
  61. initIDs();
  62. }
  63. /**
  64. * A dialog's resizable property. Will be true
  65. * if the Dialog is to be resizable, otherwise
  66. * it will be false.
  67. *
  68. * @serial
  69. * @see setResizable()
  70. */
  71. boolean resizable = true;
  72. /**
  73. * Will be true if the Dialog is modal,
  74. * otherwise the dialog will be modeless.
  75. * A modal Dialog grabs all the input to
  76. * the owner frame from the user.
  77. *
  78. * @serial
  79. * @see isModal()
  80. * @see setModal()
  81. */
  82. boolean modal;
  83. /**
  84. * Specifies the title of the Dialog.
  85. * This field can be null.
  86. *
  87. * @serial
  88. * @see getTitle()
  89. * @see setTitle()
  90. */
  91. String title;
  92. private transient boolean keepBlocking = false;
  93. private static final String base = "dialog";
  94. private static int nameCounter = 0;
  95. /*
  96. * JDK 1.1 serialVersionUID
  97. */
  98. private static final long serialVersionUID = 5920926903803293709L;
  99. /**
  100. * Constructs an initially invisible, non-modal Dialog with
  101. * an empty title and the specified owner frame.
  102. * @param owner the owner of the dialog
  103. * @exception java.lang.IllegalArgumentException if <code>owner</code>
  104. * is <code>null</code>
  105. * @see Component#setSize
  106. * @see Component#setVisible
  107. */
  108. public Dialog(Frame owner) {
  109. this(owner, "", false);
  110. }
  111. /**
  112. * Constructs an initially invisible Dialog with an empty title,
  113. * the specified owner frame and modality.
  114. * @param owner the owner of the dialog
  115. * @param modal if true, dialog blocks input to other app windows when shown
  116. * @exception java.lang.IllegalArgumentException if <code>owner</code>
  117. * is <code>null</code>
  118. */
  119. public Dialog(Frame owner, boolean modal) {
  120. this(owner, "", modal);
  121. }
  122. /**
  123. * Constructs an initially invisible, non-modal Dialog with
  124. * the specified owner frame and title.
  125. * @param owner the owner of the dialog
  126. * @param title the title of the dialog. A <code>null</code> value
  127. * will be accepted without causing a NullPointerException
  128. * to be thrown.
  129. * @exception java.lang.IllegalArgumentException if <code>owner</code>
  130. * is <code>null</code>
  131. * @see Component#setSize
  132. * @see Component#setVisible
  133. */
  134. public Dialog(Frame owner, String title) {
  135. this(owner, title, false);
  136. }
  137. /**
  138. * Constructs an initially invisible Dialog with the
  139. * specified owner frame, title, and modality.
  140. * @param owner the owner of the dialog
  141. * @param title the title of the dialog. A <code>null</code> value
  142. * will be accepted without causing a NullPointerException
  143. * to be thrown.
  144. * @param modal if true, dialog blocks input to other app windows when shown
  145. * @exception java.lang.IllegalArgumentException if <code>owner</code>
  146. * is <code>null</code>
  147. * @see Component#setSize
  148. * @see Component#setVisible
  149. */
  150. public Dialog(Frame owner, String title, boolean modal) {
  151. super(owner);
  152. this.title = title;
  153. this.modal = modal;
  154. }
  155. /**
  156. * Constructs an initially invisible, non-modal Dialog with
  157. * an empty title and the specified owner dialog.
  158. * @param owner the owner of the dialog
  159. * @exception java.lang.IllegalArgumentException if <code>owner</code>
  160. * is <code>null</code>
  161. * @since JDK1.2
  162. */
  163. public Dialog(Dialog owner) {
  164. this(owner, "", false);
  165. }
  166. /**
  167. * Constructs an initially invisible, non-modal Dialog
  168. * with the specified owner dialog and title.
  169. * @param owner the owner of the dialog
  170. * @param title the title of the dialog. A <code>null</code> value
  171. * will be accepted without causing a NullPointerException
  172. * to be thrown.
  173. * @exception java.lang.IllegalArgumentException if <code>owner</code>
  174. * is <code>null</code>
  175. * @since JDK1.2
  176. */
  177. public Dialog(Dialog owner, String title) {
  178. this(owner, title, false);
  179. }
  180. /**
  181. * Constructs an initially invisible Dialog with the
  182. * specified owner dialog, title, and modality.
  183. * @param owner the owner of the dialog
  184. * @param title the title of the dialog. A <code>null</code> value
  185. * will be accepted without causing a NullPointerException to
  186. * be thrown.
  187. * @param modal if true, dialog blocks input to other app windows when shown
  188. * @exception java.lang.IllegalArgumentException if <code>owner</code>
  189. * is <code>null</code>
  190. * @since JDK1.2
  191. */
  192. public Dialog(Dialog owner, String title, boolean modal) {
  193. super(owner);
  194. this.title = title;
  195. this.modal = modal;
  196. }
  197. /**
  198. * Construct a name for this component. Called by getName() when the
  199. * name is null.
  200. */
  201. String constructComponentName() {
  202. synchronized (getClass()) {
  203. return base + nameCounter++;
  204. }
  205. }
  206. /**
  207. * Makes this Dialog displayable by connecting it to
  208. * a native screen resource. Making a dialog displayable will
  209. * cause any of its children to be made displayable.
  210. * This method is called internally by the toolkit and should
  211. * not be called directly by programs.
  212. * @see Component#isDisplayable
  213. * @see #removeNotify
  214. */
  215. public void addNotify() {
  216. synchronized (getTreeLock()) {
  217. if (parent != null && parent.getPeer() == null) {
  218. parent.addNotify();
  219. }
  220. if (peer == null) {
  221. peer = getToolkit().createDialog(this);
  222. }
  223. super.addNotify();
  224. }
  225. }
  226. /**
  227. * Indicates whether the dialog is modal.
  228. * When a modal Dialog is made visible, user input will be
  229. * blocked to the other windows in the app context, except for
  230. * any windows created with this dialog as their owner.
  231. *
  232. * @return <code>true</code> if this dialog window is modal;
  233. * <code>false</code> otherwise.
  234. * @see java.awt.Dialog#setModal
  235. */
  236. public boolean isModal() {
  237. return modal;
  238. }
  239. /**
  240. * Specifies whether this dialog should be modal.
  241. * @see java.awt.Dialog#isModal
  242. * @since JDK1.1
  243. */
  244. public void setModal(boolean b) {
  245. this.modal = b;
  246. }
  247. /**
  248. * Gets the title of the dialog. The title is displayed in the
  249. * dialog's border.
  250. * @return the title of this dialog window. The title may be
  251. * <code>null</code>.
  252. * @see java.awt.Dialog#setTitle
  253. */
  254. public String getTitle() {
  255. return title;
  256. }
  257. /**
  258. * Sets the title of the Dialog.
  259. * @param title the title displayed in the dialog's border
  260. * @see #getTitle
  261. */
  262. public synchronized void setTitle(String title) {
  263. this.title = title;
  264. DialogPeer peer = (DialogPeer)this.peer;
  265. if (peer != null) {
  266. peer.setTitle(title);
  267. }
  268. }
  269. /**
  270. * @return true if we actually showed, false if we just called toFront()
  271. */
  272. private boolean conditionalShow() {
  273. boolean retval;
  274. synchronized (getTreeLock()) {
  275. if (peer == null) {
  276. addNotify();
  277. }
  278. validate();
  279. if (visible) {
  280. toFront();
  281. retval = false;
  282. } else {
  283. visible = retval = true;
  284. peer.show(); // now guaranteed never to block
  285. }
  286. }
  287. if (retval && (state & OPENED) == 0) {
  288. postWindowEvent(WindowEvent.WINDOW_OPENED);
  289. state |= OPENED;
  290. }
  291. return retval;
  292. }
  293. /**
  294. * Makes the Dialog visible. If the dialog and/or its owner
  295. * are not yet displayable, both are made displayable. The
  296. * dialog will be validated prior to being made visible.
  297. * If the dialog is already visible, this will bring the dialog
  298. * to the front.
  299. * <p>
  300. * If the dialog is modal and is not already visible, this call will
  301. * not return until the dialog is hidden by calling <code>hide</code> or
  302. * <code>dispose</code>. It is permissible to show modal dialogs from
  303. * the event dispatching thread because the toolkit will ensure that
  304. * another event pump runs while the one which invoked this method
  305. * is blocked.
  306. * @see Component#hide
  307. * @see Component#isDisplayable
  308. * @see Component#validate
  309. * @see java.awt.Dialog#isModal
  310. */
  311. private EventQueue tempEQ = null;
  312. private AxBridgeHelper axbHelper = null;
  313. public void show() {
  314. if (!isModal()) {
  315. conditionalShow();
  316. } else {
  317. // Set this variable before calling conditionalShow(). That
  318. // way, if the Dialog is hidden right after being shown, we
  319. // won't mistakenly block this thread.
  320. keepBlocking = true;
  321. if (conditionalShow()) {
  322. // We have two mechanisms for blocking: 1. If we're on the
  323. // EventDispatchThread, start a new event pump. 2. If we're
  324. // on any other thread, call wait() on the treelock.
  325. //
  326. // if we are calling from windows activex thread
  327. // we need to create a message loop for the activex
  328. // container to avoid blocking
  329. if (Toolkit.getEventQueue().isDispatchThread()) {
  330. EventDispatchThread dispatchThread =
  331. (EventDispatchThread) Thread.currentThread();
  332. /*
  333. * pump events, filter out input events for
  334. * component not belong to our modal dialog.
  335. *
  336. * we already disabled other components in native code
  337. * but because the event is posted from a different
  338. * thread so it's possible that there are some events
  339. * for other component already posted in the queue
  340. * before we decide do modal show.
  341. */
  342. dispatchThread.pumpEventsForComponent(new Conditional() {
  343. public boolean evaluate() {
  344. return keepBlocking;
  345. }
  346. }, (Component)this);
  347. return;
  348. }
  349. if (peer.getClass().getName().equals(
  350. "sun.awt.windows.WDialogPeer")) {
  351. axbHelper = new AxBridgeHelper();
  352. EventDispatchThread stoppedEDT = null;
  353. if (axbHelper.isAppMainThread()) {
  354. stoppedEDT = (EventDispatchThread)
  355. AxBridgeHelper.isNewDispatchThreadNeeded();
  356. if (stoppedEDT != null) {
  357. tempEQ = new EventQueue();
  358. stoppedEDT.getEventQueue().push(tempEQ);
  359. }
  360. axbHelper.nativeModalWait();
  361. return;
  362. }
  363. axbHelper = null;
  364. }
  365. synchronized (getTreeLock()) {
  366. while (keepBlocking) {
  367. try {
  368. getTreeLock().wait();
  369. } catch (InterruptedException e) {
  370. break;
  371. }
  372. }
  373. }
  374. }
  375. }
  376. }
  377. private void hideAndDisposeHandler() {
  378. if (keepBlocking) {
  379. synchronized (getTreeLock()) {
  380. keepBlocking = false;
  381. EventQueue.invokeLater(new Runnable(){ public void run() {} });
  382. if (peer.getClass().getName().equals("sun.awt.windows.WDialogPeer")) {
  383. // XXX: synchronize?
  384. if (tempEQ != null) {
  385. tempEQ.pop();
  386. tempEQ = null;
  387. }
  388. if (axbHelper != null) {
  389. axbHelper.nativeModalNotify();
  390. axbHelper = null;
  391. }
  392. }
  393. getTreeLock().notifyAll();
  394. }
  395. }
  396. }
  397. /**
  398. * Hides the Dialog and then causes show() to return if it is currently
  399. * blocked.
  400. */
  401. public void hide() {
  402. super.hide();
  403. hideAndDisposeHandler();
  404. }
  405. /**
  406. * Disposes the Dialog and then causes show() to return if it is currently
  407. * blocked.
  408. */
  409. public void dispose() {
  410. super.dispose();
  411. hideAndDisposeHandler();
  412. }
  413. /**
  414. * Indicates whether this dialog is resizable by the user.
  415. * @return <code>true</code> if the user can resize the dialog;
  416. * <code>false</code> otherwise.
  417. * @see java.awt.Dialog#setResizable
  418. */
  419. public boolean isResizable() {
  420. return resizable;
  421. }
  422. /**
  423. * Sets whether this dialog is resizable by the user.
  424. * @param resizable <code>true</code> if the user can
  425. * resize this dialog; <code>false</code> otherwise.
  426. * @see java.awt.Dialog#isResizable
  427. */
  428. public void setResizable(boolean resizable) {
  429. boolean testvalid = false;
  430. synchronized (this) {
  431. this.resizable = resizable;
  432. DialogPeer peer = (DialogPeer)this.peer;
  433. if (peer != null) {
  434. peer.setResizable(resizable);
  435. testvalid = true;
  436. }
  437. }
  438. // On some platforms, changing the resizable state affects
  439. // the insets of the Dialog. If we could, we'd call invalidate()
  440. // from the peer, but we need to guarantee that we're not holding
  441. // the Dialog lock when we call invalidate().
  442. if (testvalid && valid) {
  443. invalidate();
  444. }
  445. }
  446. /**
  447. * Returns the parameter string representing the state of this
  448. * dialog window. This string is useful for debugging.
  449. * @return the parameter string of this dialog window.
  450. */
  451. protected String paramString() {
  452. String str = super.paramString() + (modal ? ",modal" : ",modeless");
  453. if (title != null) {
  454. str += ",title=" + title;
  455. }
  456. return str;
  457. }
  458. /**
  459. * Initialize JNI field and method IDs
  460. */
  461. private static native void initIDs();
  462. }