1 /*
2  * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.awt;
26 
27 import java.awt.event.*;
28 
29 import sun.awt.AppContext;
30 
31 abstract class ModalEventFilter implements EventFilter {
32 
33     protected Dialog modalDialog;
34     protected boolean disabled;
35 
ModalEventFilter(Dialog modalDialog)36     protected ModalEventFilter(Dialog modalDialog) {
37         this.modalDialog = modalDialog;
38         disabled = false;
39     }
40 
getModalDialog()41     Dialog getModalDialog() {
42         return modalDialog;
43     }
44 
acceptEvent(AWTEvent event)45     public FilterAction acceptEvent(AWTEvent event) {
46         if (disabled || !modalDialog.isVisible()) {
47             return FilterAction.ACCEPT;
48         }
49         int eventID = event.getID();
50         if ((eventID >= MouseEvent.MOUSE_FIRST &&
51              eventID <= MouseEvent.MOUSE_LAST) ||
52             (eventID >= ActionEvent.ACTION_FIRST &&
53              eventID <= ActionEvent.ACTION_LAST) ||
54             eventID == WindowEvent.WINDOW_CLOSING)
55         {
56             Object o = event.getSource();
57             if (o instanceof sun.awt.ModalExclude) {
58                 // Exclude this object from modality and
59                 // continue to pump it's events.
60             } else if (o instanceof Component) {
61                 Component c = (Component)o;
62                 while ((c != null) && !(c instanceof Window)) {
63                     c = c.getParent_NoClientCode();
64                 }
65                 if (c != null) {
66                     return acceptWindow((Window)c);
67                 }
68             }
69         }
70         return FilterAction.ACCEPT;
71     }
72 
acceptWindow(Window w)73     protected abstract FilterAction acceptWindow(Window w);
74 
75     // When a modal dialog is hidden its modal filter may not be deleted from
76     // EventDispatchThread event filters immediately, so we need to mark the filter
77     // as disabled to prevent it from working. Simple checking for visibility of
78     // the modalDialog is not enough, as it can be hidden and then shown again
79     // with a new event pump and a new filter
disable()80     void disable() {
81         disabled = true;
82     }
83 
compareTo(ModalEventFilter another)84     int compareTo(ModalEventFilter another) {
85         Dialog anotherDialog = another.getModalDialog();
86         // check if modalDialog is from anotherDialog's hierarchy
87         //   or vice versa
88         Component c = modalDialog;
89         while (c != null) {
90             if (c == anotherDialog) {
91                 return 1;
92             }
93             c = c.getParent_NoClientCode();
94         }
95         c = anotherDialog;
96         while (c != null) {
97             if (c == modalDialog) {
98                 return -1;
99             }
100             c = c.getParent_NoClientCode();
101         }
102         // check if one dialog blocks (directly or indirectly) another
103         Dialog blocker = modalDialog.getModalBlocker();
104         while (blocker != null) {
105             if (blocker == anotherDialog) {
106                 return -1;
107             }
108             blocker = blocker.getModalBlocker();
109         }
110         blocker = anotherDialog.getModalBlocker();
111         while (blocker != null) {
112             if (blocker == modalDialog) {
113                 return 1;
114             }
115             blocker = blocker.getModalBlocker();
116         }
117         // compare modality types
118         return modalDialog.getModalityType().compareTo(anotherDialog.getModalityType());
119     }
120 
createFilterForDialog(Dialog modalDialog)121     static ModalEventFilter createFilterForDialog(Dialog modalDialog) {
122         switch (modalDialog.getModalityType()) {
123             case DOCUMENT_MODAL: return new DocumentModalEventFilter(modalDialog);
124             case APPLICATION_MODAL: return new ApplicationModalEventFilter(modalDialog);
125             case TOOLKIT_MODAL: return new ToolkitModalEventFilter(modalDialog);
126         }
127         return null;
128     }
129 
130     private static class ToolkitModalEventFilter extends ModalEventFilter {
131 
132         private AppContext appContext;
133 
ToolkitModalEventFilter(Dialog modalDialog)134         ToolkitModalEventFilter(Dialog modalDialog) {
135             super(modalDialog);
136             appContext = modalDialog.appContext;
137         }
138 
acceptWindow(Window w)139         protected FilterAction acceptWindow(Window w) {
140             if (w.isModalExcluded(Dialog.ModalExclusionType.TOOLKIT_EXCLUDE)) {
141                 return FilterAction.ACCEPT;
142             }
143             if (w.appContext != appContext) {
144                 return FilterAction.REJECT;
145             }
146             while (w != null) {
147                 if (w == modalDialog) {
148                     return FilterAction.ACCEPT_IMMEDIATELY;
149                 }
150                 w = w.getOwner();
151             }
152             return FilterAction.REJECT;
153         }
154     }
155 
156     private static class ApplicationModalEventFilter extends ModalEventFilter {
157 
158         private AppContext appContext;
159 
ApplicationModalEventFilter(Dialog modalDialog)160         ApplicationModalEventFilter(Dialog modalDialog) {
161             super(modalDialog);
162             appContext = modalDialog.appContext;
163         }
164 
acceptWindow(Window w)165         protected FilterAction acceptWindow(Window w) {
166             if (w.isModalExcluded(Dialog.ModalExclusionType.APPLICATION_EXCLUDE)) {
167                 return FilterAction.ACCEPT;
168             }
169             if (w.appContext == appContext) {
170                 while (w != null) {
171                     if (w == modalDialog) {
172                         return FilterAction.ACCEPT_IMMEDIATELY;
173                     }
174                     w = w.getOwner();
175                 }
176                 return FilterAction.REJECT;
177             }
178             return FilterAction.ACCEPT;
179         }
180     }
181 
182     private static class DocumentModalEventFilter extends ModalEventFilter {
183 
184         private Window documentRoot;
185 
DocumentModalEventFilter(Dialog modalDialog)186         DocumentModalEventFilter(Dialog modalDialog) {
187             super(modalDialog);
188             documentRoot = modalDialog.getDocumentRoot();
189         }
190 
acceptWindow(Window w)191         protected FilterAction acceptWindow(Window w) {
192             // application- and toolkit-excluded windows are blocked by
193             // document-modal dialogs from their child hierarchy
194             if (w.isModalExcluded(Dialog.ModalExclusionType.APPLICATION_EXCLUDE)) {
195                 Window w1 = modalDialog.getOwner();
196                 while (w1 != null) {
197                     if (w1 == w) {
198                         return FilterAction.REJECT;
199                     }
200                     w1 = w1.getOwner();
201                 }
202                 return FilterAction.ACCEPT;
203             }
204             while (w != null) {
205                 if (w == modalDialog) {
206                     return FilterAction.ACCEPT_IMMEDIATELY;
207                 }
208                 if (w == documentRoot) {
209                     return FilterAction.REJECT;
210                 }
211                 w = w.getOwner();
212             }
213             return FilterAction.ACCEPT;
214         }
215     }
216 }
217