1 /*
2  * Copyright (c) 2011, 2013, 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 
26 package sun.lwawt;
27 
28 import sun.awt.SunGraphicsCallback;
29 import sun.java2d.pipe.Region;
30 
31 import java.awt.Color;
32 import java.awt.Container;
33 import java.awt.Font;
34 import java.awt.Graphics;
35 import java.awt.Insets;
36 import java.awt.Rectangle;
37 import java.awt.peer.ContainerPeer;
38 import java.util.LinkedList;
39 import java.util.List;
40 
41 import javax.swing.JComponent;
42 
43 abstract class LWContainerPeer<T extends Container, D extends JComponent>
44         extends LWCanvasPeer<T, D> implements ContainerPeer {
45 
46     /**
47      * List of child peers sorted by z-order from bottom-most to top-most.
48      */
49     private final List<LWComponentPeer<?, ?>> childPeers = new LinkedList<>();
50 
LWContainerPeer(final T target, final PlatformComponent platformComponent)51     LWContainerPeer(final T target, final PlatformComponent platformComponent) {
52         super(target, platformComponent);
53     }
54 
addChildPeer(final LWComponentPeer<?, ?> child)55     final void addChildPeer(final LWComponentPeer<?, ?> child) {
56         synchronized (getPeerTreeLock()) {
57             childPeers.add(childPeers.size(), child);
58             // TODO: repaint
59         }
60     }
61 
removeChildPeer(final LWComponentPeer<?, ?> child)62     final void removeChildPeer(final LWComponentPeer<?, ?> child) {
63         synchronized (getPeerTreeLock()) {
64             childPeers.remove(child);
65         }
66         // TODO: repaint
67     }
68 
69     // Used by LWComponentPeer.setZOrder()
setChildPeerZOrder(final LWComponentPeer<?, ?> peer, final LWComponentPeer<?, ?> above)70     final void setChildPeerZOrder(final LWComponentPeer<?, ?> peer,
71                                   final LWComponentPeer<?, ?> above) {
72         synchronized (getPeerTreeLock()) {
73             childPeers.remove(peer);
74             int index = (above != null) ? childPeers.indexOf(above) : childPeers.size();
75             if (index >= 0) {
76                 childPeers.add(index, peer);
77             } else {
78                 // TODO: log
79             }
80         }
81         // TODO: repaint
82     }
83 
84     // ---- PEER METHODS ---- //
85 
86     /*
87      * Overridden in LWWindowPeer.
88      */
89     @Override
getInsets()90     public Insets getInsets() {
91         return new Insets(0, 0, 0, 0);
92     }
93 
94     @Override
beginValidate()95     public final void beginValidate() {
96         // TODO: it seems that begin/endValidate() is only useful
97         // for heavyweight windows, when a batch movement for
98         // child windows  occurs. That's why no-op
99     }
100 
101     @Override
endValidate()102     public final void endValidate() {
103         // TODO: it seems that begin/endValidate() is only useful
104         // for heavyweight windows, when a batch movement for
105         // child windows  occurs. That's why no-op
106     }
107 
108     @Override
beginLayout()109     public final void beginLayout() {
110         // Skip all painting till endLayout()
111         setLayouting(true);
112     }
113 
114     @Override
endLayout()115     public final void endLayout() {
116         setLayouting(false);
117 
118         // Post an empty event to flush all the pending target paints
119         postPaintEvent(0, 0, 0, 0);
120     }
121 
122     // ---- PEER NOTIFICATIONS ---- //
123 
124     /**
125      * Returns a copy of the childPeer collection.
126      */
127     @SuppressWarnings("unchecked")
getChildren()128     final List<LWComponentPeer<?, ?>> getChildren() {
129         synchronized (getPeerTreeLock()) {
130             Object copy = ((LinkedList<?>) childPeers).clone();
131             return (List<LWComponentPeer<?, ?>>) copy;
132         }
133     }
134 
135     @Override
getVisibleRegion()136     final Region getVisibleRegion() {
137         return cutChildren(super.getVisibleRegion(), null);
138     }
139 
140     /**
141      * Removes bounds of children above specific child from the region. If above
142      * is null removes all bounds of children.
143      */
cutChildren(Region r, final LWComponentPeer<?, ?> above)144     final Region cutChildren(Region r, final LWComponentPeer<?, ?> above) {
145         boolean aboveFound = above == null;
146         for (final LWComponentPeer<?, ?> child : getChildren()) {
147             if (!aboveFound && child == above) {
148                 aboveFound = true;
149                 continue;
150             }
151             if (aboveFound) {
152                 if(child.isVisible()){
153                     final Rectangle cb = child.getBounds();
154                     final Region cr = child.getRegion();
155                     final Region tr = cr.getTranslatedRegion(cb.x, cb.y);
156                     r = r.getDifference(tr.getIntersection(getContentSize()));
157                 }
158             }
159         }
160         return r;
161     }
162 
163     // ---- UTILITY METHODS ---- //
164 
165     /**
166      * Finds a top-most visible component for the given point. The location is
167      * specified relative to the peer's parent.
168      */
169     @Override
findPeerAt(int x, int y)170     final LWComponentPeer<?, ?> findPeerAt(int x, int y) {
171         LWComponentPeer<?, ?> peer = super.findPeerAt(x, y);
172         final Rectangle r = getBounds();
173         // Translate to this container's coordinates to pass to children
174         x -= r.x;
175         y -= r.y;
176         if (peer != null && getContentSize().contains(x, y)) {
177             synchronized (getPeerTreeLock()) {
178                 for (int i = childPeers.size() - 1; i >= 0; --i) {
179                     LWComponentPeer<?, ?> p = childPeers.get(i).findPeerAt(x, y);
180                     if (p != null) {
181                         peer = p;
182                         break;
183                     }
184                 }
185             }
186         }
187         return peer;
188     }
189 
190     /*
191     * Called by the container when any part of this peer or child
192     * peers should be repainted
193     */
194     @Override
repaintPeer(final Rectangle r)195     final void repaintPeer(final Rectangle r) {
196         final Rectangle toPaint = getSize().intersection(r);
197         if (!isShowing() || toPaint.isEmpty()) {
198             return;
199         }
200         // First, post the PaintEvent for this peer
201         super.repaintPeer(toPaint);
202         // Second, handle all the children
203         // Use the straight order of children, so the bottom
204         // ones are painted first
205         repaintChildren(toPaint);
206     }
207 
208     /**
209      * Paints all the child peers in the straight z-order, so the
210      * bottom-most ones are painted first.
211      */
repaintChildren(final Rectangle r)212     private void repaintChildren(final Rectangle r) {
213         final Rectangle content = getContentSize();
214         for (final LWComponentPeer<?, ?> child : getChildren()) {
215             final Rectangle childBounds = child.getBounds();
216             Rectangle toPaint = r.intersection(childBounds);
217             toPaint = toPaint.intersection(content);
218             toPaint.translate(-childBounds.x, -childBounds.y);
219             child.repaintPeer(toPaint);
220         }
221     }
222 
getContentSize()223     Rectangle getContentSize() {
224         return getSize();
225     }
226 
227     @Override
setEnabled(final boolean e)228     public void setEnabled(final boolean e) {
229         super.setEnabled(e);
230         for (final LWComponentPeer<?, ?> child : getChildren()) {
231             child.setEnabled(e && child.getTarget().isEnabled());
232         }
233     }
234 
235     @Override
setBackground(final Color c)236     public void setBackground(final Color c) {
237         for (final LWComponentPeer<?, ?> child : getChildren()) {
238             if (!child.getTarget().isBackgroundSet()) {
239                 child.setBackground(c);
240             }
241         }
242         super.setBackground(c);
243     }
244 
245     @Override
setForeground(final Color c)246     public void setForeground(final Color c) {
247         for (final LWComponentPeer<?, ?> child : getChildren()) {
248             if (!child.getTarget().isForegroundSet()) {
249                 child.setForeground(c);
250             }
251         }
252         super.setForeground(c);
253     }
254 
255     @Override
setFont(final Font f)256     public void setFont(final Font f) {
257         for (final LWComponentPeer<?, ?> child : getChildren()) {
258             if (!child.getTarget().isFontSet()) {
259                 child.setFont(f);
260             }
261         }
262         super.setFont(f);
263     }
264 
265     @Override
paint(final Graphics g)266     public final void paint(final Graphics g) {
267         super.paint(g);
268         SunGraphicsCallback.PaintHeavyweightComponentsCallback.getInstance()
269                 .runComponents(getTarget().getComponents(), g,
270                                SunGraphicsCallback.LIGHTWEIGHTS
271                                | SunGraphicsCallback.HEAVYWEIGHTS);
272     }
273 
274     @Override
print(final Graphics g)275     public final void print(final Graphics g) {
276         super.print(g);
277         SunGraphicsCallback.PrintHeavyweightComponentsCallback.getInstance()
278                 .runComponents(getTarget().getComponents(), g,
279                                SunGraphicsCallback.LIGHTWEIGHTS
280                                | SunGraphicsCallback.HEAVYWEIGHTS);
281     }
282 }
283