]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/internal/awt/AwtDialogListener.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.utils.ui / src / org / simantics / utils / ui / internal / awt / AwtDialogListener.java
1 /*******************************************************************************
2  * Copyright (c) 2007 SAS Institute.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     SAS Institute - initial API and implementation
10  *******************************************************************************/
11 package org.simantics.utils.ui.internal.awt;
12
13 import java.awt.AWTEvent;
14 import java.awt.Dialog;
15 import java.awt.EventQueue;
16 import java.awt.Toolkit;
17 import java.awt.Window;
18 import java.awt.event.AWTEventListener;
19 import java.awt.event.ComponentEvent;
20 import java.awt.event.ComponentListener;
21 import java.awt.event.WindowEvent;
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.eclipse.swt.widgets.Display;
26
27 /**
28  * A listener that insures the proper modal behavior of Swing dialogs when running
29  * within a SWT environment. When initialized, it blocks and unblocks SWT input
30  * as modal Swing dialogs are shown and hidden. 
31  */
32 @SuppressWarnings({"rawtypes", "unchecked"})
33 class AwtDialogListener implements AWTEventListener, ComponentListener {
34     
35     // modalDialogs should be accessed only from the AWT thread, so no
36     // synchronization is needed. 
37     private final List modalDialogs = new ArrayList();
38     private final Display display;
39     
40     /**
41      * Registers this object as an AWT event listener so that Swing dialogs have the 
42      * proper modal behavior in the containing SWT environment. This is called automatically
43      * when you construct a {@link EmbeddedSwingComposite}, and it
44      * need not be called separately in that case.  
45      * @param shell 
46      */
47     AwtDialogListener(Display display) {
48         assert display != null;
49         
50         this.display = display;
51         Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.WINDOW_EVENT_MASK);
52     }
53     
54     private void handleRemovedDialog(Dialog awtDialog, boolean removeListener) {
55         assert awtDialog != null;
56         assert modalDialogs != null;
57         assert display != null;
58         assert EventQueue.isDispatchThread();    // On AWT event thread
59         
60         // System.out.println("Remove dialog: " + awtDialog);
61         if (removeListener) {
62             awtDialog.removeComponentListener(this);
63         }
64         // Note: there is no isModal() check here because the dialog might 
65         // have been changed from modal to non-modal after it was opened. In this case
66         // the currently visible dialog would still act modal and we'd need to unblock
67         // SWT here when it goes away.
68         if (modalDialogs.remove(awtDialog)) {
69             display.asyncExec(new Runnable() {
70                 public void run() {
71                     SwtInputBlocker.unblock();
72                 }
73             });            
74         }
75     }
76
77     private void handleAddedDialog(final Dialog awtDialog) {
78         assert awtDialog != null;
79         assert modalDialogs != null;
80         assert EventQueue.isDispatchThread();    // On AWT event thread
81         
82         // System.out.println("Add dialog: " + awtDialog);
83         if (modalDialogs.contains(awtDialog) || !awtDialog.isModal() || !awtDialog.isVisible()) {
84             return;
85         }
86         modalDialogs.add(awtDialog);
87         awtDialog.addComponentListener(this);
88         display.asyncExec(new Runnable() {
89             public void run() {
90                 SwtInputBlocker.block();
91             }
92         });        
93     }
94     
95     void requestFocus() {
96         // TODO: this does not always bring the dialog to the top 
97         // under some Linux desktops/window managers (e.g. metacity under GNOME).
98         EventQueue.invokeLater(new Runnable() {
99             public void run() {
100                 assert modalDialogs != null;
101                 
102                 int size = modalDialogs.size();
103                 if (size > 0) {
104                     final Dialog awtDialog = (Dialog)modalDialogs.get(size - 1);
105
106                     // In one case, a call to requestFocus() alone does not 
107                     // bring the AWT dialog to the top. This happens if the 
108                     // dialog is given a null parent frame. When opened, the dialog
109                     // can be hidden by the SWT window even when it obtains focus.
110                     // Calling toFront() solves the problem, but...
111                     //
112                     // There are still problems if the Metal look and feel is in use.
113                     // The SWT window will hide the dialog the first time it is 
114                     // selected. Once the dialog is brought back to the front by 
115                     // the user, there is no further problem. 
116                     //
117                     // Why? It looks like SWT is not being notified of lost focus when 
118                     // the Metal dialog first opens; subsequently, when focus is regained, the 
119                     // focus gain event is not posted to the SwtInputBlocker.  
120                     //
121                     // The workaround is to use Windows look and feel, rather than Metal.
122                     // System.out.println("Bringing to front");
123
124                     awtDialog.requestFocus();
125                     awtDialog.toFront();
126                 }
127             }
128         });
129     }
130
131     private void handleOpenedWindow(WindowEvent event) {
132         assert event != null;
133         assert EventQueue.isDispatchThread();    // On AWT event thread
134         
135         Window window = event.getWindow();
136         if (window instanceof Dialog) {
137             handleAddedDialog((Dialog)window);
138         }
139     }
140     
141     private void handleClosedWindow(WindowEvent event) {
142         assert event != null;
143         assert EventQueue.isDispatchThread();    // On AWT event thread
144         
145         // Dispose-based close
146         Window window = event.getWindow();
147         if (window instanceof Dialog) {
148             // Remove dialog and component listener
149             handleRemovedDialog((Dialog)window, true);
150         }
151     }
152
153     private void handleClosingWindow(WindowEvent event) {
154         assert event != null;
155         assert EventQueue.isDispatchThread();    // On AWT event thread
156         
157         // System-based close 
158         Window window = event.getWindow();
159         if (window instanceof Dialog) {
160             final Dialog dialog = (Dialog) window;
161             // Defer until later. Bad things happen if 
162             // handleRemovedDialog() is called directly from 
163             // this event handler. The Swing dialog does not close
164             // properly and its modality remains in effect.
165             EventQueue.invokeLater(new Runnable() {
166                 public void run() {
167                     // Remove dialog and component listener
168                     handleRemovedDialog(dialog, true);
169                 }
170             });
171         }
172     }
173     
174     public void eventDispatched(AWTEvent event) {
175         assert event != null;
176         assert EventQueue.isDispatchThread();    // On AWT event thread
177         
178         switch (event.getID()) {
179         case WindowEvent.WINDOW_OPENED:
180             handleOpenedWindow((WindowEvent)event);
181             break;
182             
183         case WindowEvent.WINDOW_CLOSED:
184             handleClosedWindow((WindowEvent)event);
185             break;
186
187         case WindowEvent.WINDOW_CLOSING:
188             handleClosingWindow((WindowEvent)event);
189             break;
190
191         default:
192             break;
193         }
194     }
195
196     public void componentHidden(ComponentEvent e) {
197         assert e != null;
198         assert EventQueue.isDispatchThread();    // On AWT event thread
199         
200         // System.out.println("Component hidden");
201         Object obj = e.getSource();
202         if (obj instanceof Dialog) {
203             // Remove dialog but keep listener in place so that we know if/when it is set visible
204             handleRemovedDialog((Dialog)obj, false);
205         }
206     }
207
208     public void componentShown(ComponentEvent e) {
209         assert e != null;
210         assert EventQueue.isDispatchThread();    // On AWT event thread
211         
212         // System.out.println("Component shown");
213         Object obj = e.getSource();
214         if (obj instanceof Dialog) {
215             handleAddedDialog((Dialog)obj);
216         }
217     }
218
219     public void componentResized(ComponentEvent e) {
220     }
221
222     public void componentMoved(ComponentEvent e) {
223     }
224         
225 }