/*
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.lwawt;
import sun.awt.SunGraphicsCallback;
import sun.java2d.pipe.Region;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.peer.ContainerPeer;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JComponent;
abstract class LWContainerPeer<T extends Container, D extends JComponent>
extends LWCanvasPeer<T, D> implements ContainerPeer {
List of child peers sorted by z-order from bottom-most to top-most.
/**
* List of child peers sorted by z-order from bottom-most to top-most.
*/
private final List<LWComponentPeer<?, ?>> childPeers = new LinkedList<>();
LWContainerPeer(final T target, final PlatformComponent platformComponent) {
super(target, platformComponent);
}
final void addChildPeer(final LWComponentPeer<?, ?> child) {
synchronized (getPeerTreeLock()) {
childPeers.add(childPeers.size(), child);
// TODO: repaint
}
}
final void removeChildPeer(final LWComponentPeer<?, ?> child) {
synchronized (getPeerTreeLock()) {
childPeers.remove(child);
}
// TODO: repaint
}
// Used by LWComponentPeer.setZOrder()
final void setChildPeerZOrder(final LWComponentPeer<?, ?> peer,
final LWComponentPeer<?, ?> above) {
synchronized (getPeerTreeLock()) {
childPeers.remove(peer);
int index = (above != null) ? childPeers.indexOf(above) : childPeers.size();
if (index >= 0) {
childPeers.add(index, peer);
} else {
// TODO: log
}
}
// TODO: repaint
}
// ---- PEER METHODS ---- //
/*
* Overridden in LWWindowPeer.
*/
@Override
public Insets getInsets() {
return new Insets(0, 0, 0, 0);
}
@Override
public final void beginValidate() {
// TODO: it seems that begin/endValidate() is only useful
// for heavyweight windows, when a batch movement for
// child windows occurs. That's why no-op
}
@Override
public final void endValidate() {
// TODO: it seems that begin/endValidate() is only useful
// for heavyweight windows, when a batch movement for
// child windows occurs. That's why no-op
}
@Override
public final void beginLayout() {
// Skip all painting till endLayout()
setLayouting(true);
}
@Override
public final void endLayout() {
setLayouting(false);
// Post an empty event to flush all the pending target paints
postPaintEvent(0, 0, 0, 0);
}
// ---- PEER NOTIFICATIONS ---- //
Returns a copy of the childPeer collection.
/**
* Returns a copy of the childPeer collection.
*/
@SuppressWarnings("unchecked")
final List<LWComponentPeer<?, ?>> getChildren() {
synchronized (getPeerTreeLock()) {
Object copy = ((LinkedList<?>) childPeers).clone();
return (List<LWComponentPeer<?, ?>>) copy;
}
}
@Override
final Region getVisibleRegion() {
return cutChildren(super.getVisibleRegion(), null);
}
Removes bounds of children above specific child from the region. If above
is null removes all bounds of children.
/**
* Removes bounds of children above specific child from the region. If above
* is null removes all bounds of children.
*/
final Region cutChildren(Region r, final LWComponentPeer<?, ?> above) {
boolean aboveFound = above == null;
for (final LWComponentPeer<?, ?> child : getChildren()) {
if (!aboveFound && child == above) {
aboveFound = true;
continue;
}
if (aboveFound) {
if(child.isVisible()){
final Rectangle cb = child.getBounds();
final Region cr = child.getRegion();
final Region tr = cr.getTranslatedRegion(cb.x, cb.y);
r = r.getDifference(tr.getIntersection(getContentSize()));
}
}
}
return r;
}
// ---- UTILITY METHODS ---- //
Finds a top-most visible component for the given point. The location is
specified relative to the peer's parent.
/**
* Finds a top-most visible component for the given point. The location is
* specified relative to the peer's parent.
*/
@Override
final LWComponentPeer<?, ?> findPeerAt(int x, int y) {
LWComponentPeer<?, ?> peer = super.findPeerAt(x, y);
final Rectangle r = getBounds();
// Translate to this container's coordinates to pass to children
x -= r.x;
y -= r.y;
if (peer != null && getContentSize().contains(x, y)) {
synchronized (getPeerTreeLock()) {
for (int i = childPeers.size() - 1; i >= 0; --i) {
LWComponentPeer<?, ?> p = childPeers.get(i).findPeerAt(x, y);
if (p != null) {
peer = p;
break;
}
}
}
}
return peer;
}
/*
* Called by the container when any part of this peer or child
* peers should be repainted
*/
@Override
final void repaintPeer(final Rectangle r) {
final Rectangle toPaint = getSize().intersection(r);
if (!isShowing() || toPaint.isEmpty()) {
return;
}
// First, post the PaintEvent for this peer
super.repaintPeer(toPaint);
// Second, handle all the children
// Use the straight order of children, so the bottom
// ones are painted first
repaintChildren(toPaint);
}
Paints all the child peers in the straight z-order, so the
bottom-most ones are painted first.
/**
* Paints all the child peers in the straight z-order, so the
* bottom-most ones are painted first.
*/
private void repaintChildren(final Rectangle r) {
final Rectangle content = getContentSize();
for (final LWComponentPeer<?, ?> child : getChildren()) {
final Rectangle childBounds = child.getBounds();
Rectangle toPaint = r.intersection(childBounds);
toPaint = toPaint.intersection(content);
toPaint.translate(-childBounds.x, -childBounds.y);
child.repaintPeer(toPaint);
}
}
Rectangle getContentSize() {
return getSize();
}
@Override
public void setEnabled(final boolean e) {
super.setEnabled(e);
for (final LWComponentPeer<?, ?> child : getChildren()) {
child.setEnabled(e && child.getTarget().isEnabled());
}
}
@Override
public void setBackground(final Color c) {
for (final LWComponentPeer<?, ?> child : getChildren()) {
if (!child.getTarget().isBackgroundSet()) {
child.setBackground(c);
}
}
super.setBackground(c);
}
@Override
public void setForeground(final Color c) {
for (final LWComponentPeer<?, ?> child : getChildren()) {
if (!child.getTarget().isForegroundSet()) {
child.setForeground(c);
}
}
super.setForeground(c);
}
@Override
public void setFont(final Font f) {
for (final LWComponentPeer<?, ?> child : getChildren()) {
if (!child.getTarget().isFontSet()) {
child.setFont(f);
}
}
super.setFont(f);
}
@Override
public final void paint(final Graphics g) {
super.paint(g);
SunGraphicsCallback.PaintHeavyweightComponentsCallback.getInstance()
.runComponents(getTarget().getComponents(), g,
SunGraphicsCallback.LIGHTWEIGHTS
| SunGraphicsCallback.HEAVYWEIGHTS);
}
@Override
public final void print(final Graphics g) {
super.print(g);
SunGraphicsCallback.PrintHeavyweightComponentsCallback.getInstance()
.runComponents(getTarget().getComponents(), g,
SunGraphicsCallback.LIGHTWEIGHTS
| SunGraphicsCallback.HEAVYWEIGHTS);
}
}