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
26package sun.lwawt;
27
28import sun.awt.SunGraphicsCallback;
29import sun.java2d.pipe.Region;
30
31import java.awt.Color;
32import java.awt.Container;
33import java.awt.Font;
34import java.awt.Graphics;
35import java.awt.Insets;
36import java.awt.Rectangle;
37import java.awt.peer.ContainerPeer;
38import java.util.LinkedList;
39import java.util.List;
40
41import javax.swing.JComponent;
42
43abstract 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
51    LWContainerPeer(final T target, final PlatformComponent platformComponent) {
52        super(target, platformComponent);
53    }
54
55    final void addChildPeer(final LWComponentPeer<?, ?> child) {
56        synchronized (getPeerTreeLock()) {
57            childPeers.add(childPeers.size(), child);
58            // TODO: repaint
59        }
60    }
61
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()
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
90    public Insets getInsets() {
91        return new Insets(0, 0, 0, 0);
92    }
93
94    @Override
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
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
109    public final void beginLayout() {
110        // Skip all painting till endLayout()
111        setLayouting(true);
112    }
113
114    @Override
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")
128    final List<LWComponentPeer<?, ?>> getChildren() {
129        synchronized (getPeerTreeLock()) {
130            Object copy = ((LinkedList<?>) childPeers).clone();
131            return (List<LWComponentPeer<?, ?>>) copy;
132        }
133    }
134
135    @Override
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     */
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
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
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     */
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
223    Rectangle getContentSize() {
224        return getSize();
225    }
226
227    @Override
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
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
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
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
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
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