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 */
25package java.awt;
26
27import java.awt.event.*;
28
29import sun.awt.AppContext;
30
31abstract class ModalEventFilter implements EventFilter {
32
33    protected Dialog modalDialog;
34    protected boolean disabled;
35
36    protected ModalEventFilter(Dialog modalDialog) {
37        this.modalDialog = modalDialog;
38        disabled = false;
39    }
40
41    Dialog getModalDialog() {
42        return modalDialog;
43    }
44
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
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
80    void disable() {
81        disabled = true;
82    }
83
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
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
134        ToolkitModalEventFilter(Dialog modalDialog) {
135            super(modalDialog);
136            appContext = modalDialog.appContext;
137        }
138
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
160        ApplicationModalEventFilter(Dialog modalDialog) {
161            super(modalDialog);
162            appContext = modalDialog.appContext;
163        }
164
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
186        DocumentModalEventFilter(Dialog modalDialog) {
187            super(modalDialog);
188            documentRoot = modalDialog.getDocumentRoot();
189        }
190
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