VJPanel.java revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* ident "%Z%%M% %I% %E% SMI"
*
* Copyright (c) 2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
/*
* Copyright (C) 1996 Active Software, Inc.
* All rights reserved.
*
* @(#) VJPanel.java 1.31 - last change made 08/25/97
*/
// Relief constants
/* BEGIN JSTYLED */
/* END JSTYLED */
// Alignment constants
// Drawing constants
private static final int labelpadx = 10;
private static final int labelipadx = 4;
private static final int labelpadtop = 2;
// Maker event
private static final int MARKER_EVENT = 83250;
// Multiply factor for darker color
private static double FACTOR = 0.85;
// request focus workaround for Windows
static boolean isMouseDown;
// click count adjustment
private static final int CLICK_TIMEOUT = 400;
private static final int CLICK_DISTANCE = 2;
private static int clickCount = 1;
private static long clickTime = 0;
private static long clickWhen = -1;
// Relief
private int relief;
// Border width
int borderWidth;
// Label for the upper border of the panel
private String borderLabel;
// Alignment for the borderLabel
private int labelAlignment;
// Insets between the border decoration and the child components
private Insets borderInsets;
//
// Event forwarding to groups.
//
// The MARKER_EVENT stuff is necessary because AWT is broken. For
// example, say a key is pressed in a textfield. All of the parents
// of the textfield get a chance at the event before the textfield's
// peer. If any of the parents returns true from handleEvent, then
// the peer never sees the event.
//
// VJPanel overrides postEvent instead of handleEvent. handleEvent
// would have been overridden if it we possible to return true from
// handleEvent and not screw up AWT. Since this is not the case, it
// becomes necessary to override postEvent instead of handleEvent,
// to ensure that all AWT event handling has taken place everywhere
// before the event is forwarded to the shadow (and from there to
// the group).
//
// The panel cannot return true from postEvent or else no one
// will ever see the event. Therefore, postEvent returns false,
// and the MARKER_EVENT stuff ensures that the event doesn't get
// delivered twice.
//
//
/**
* markEvent - Marks events that should be forwarded to the shadow.
*
* Returns true if the event has been marked, false otherwise.
*/
//
// Check for events that are already marked
//
while (e != null) {
if (e.id == MARKER_EVENT)
return false;
e = e.evt;
}
//
// Figure out the mgr to send the mesage to, and also figure
// out the target for the message.
//
messageTarget = mgr;
}
}
//
// If we found a mgr, then mark the event and return true.
// Otherwise, return false.
//
evt, true);
e = evt;
e = e.evt;
e.evt.x = e.x;
e.evt.y = e.y;
return true;
} else {
return false;
}
}
/**
* forwardEvent - Forwards marked events to the shadow
*/
// Find the marker event and remove it
p = e;
e = e.evt;
}
// Make sure we have a marked event
if (e.id != MARKER_EVENT) {
throw new Error(
/* JSTYLED */
}
// Need to untranslate the (x,y) for the event.
evt.x = e.x;
evt.y = e.y;
// We didn't hit comp on the way up the tree,
// so don't translate
evt.x = e.x;
evt.y = e.y;
break;
}
}
// Fix the click count
// Send the message
}
// Windows workaround: The location of most
// components gets totally
// screwed up on Windows. The solution is to
// use the location in the
// GBConstraints instead. This version of
// postEvent translates events
// according to the GBConstraints location variable.
// Fix the click count
fixClickCount(e);
VJPanel.isMouseDown = true;
VJPanel.isMouseDown = false;
boolean handled = doPostEvent(e);
if (marked)
VJPanel.forwardEvent(e, this);
return handled;
}
private boolean doPostEvent(Event e) {
boolean handled = false;
if (handleEvent(e)) {
handled = true;
} else {
translateEvent(e, this, parent);
handled = true;
}
}
}
} else {
}
return handled;
}
//
// This is a workaround for two different problems.
//
// The first problem is that on Motif, the
// click count sometimes does
// not work. Sometimes is does sort of work,
// but you have to double-
// click REALLY fast. This workaround adjusts
// the clickCount according
// to a reasonable click timeout.
//
// The second problem is that on Windows you can get double-clicks
// even if the second click is at a different x,y
// location than the first
// click. This workaround makes sure that
// if the clicks are far apart,
// then it isn't a double click.
//
return;
&& (d <= CLICK_DISTANCE)) {
clickCount++;
} else {
clickCount = 1;
}
if (d > CLICK_DISTANCE) {
}
}
}
}
private static void translateEvent(Event e,
boolean negate) {
// Translate the event using the location
// from the GridBagLayout,
// if available. This solves the location problem if you use
// GridBagLayout for all your containers.
if (c != null)
p = c.location;
if (p == null)
if (negate)
e.translate(-p.x, -p.y);
else
e.translate(p.x, p.y);
} else {
if (negate)
e.translate(-p.x, -p.y);
else
e.translate(p.x, p.y);
}
}
//
// Constructor
//
public VJPanel() {
borderLabel = null;
borderWidth = 2;
}
this();
}
this(relief);
}
}
//
// Children that are not visible should
// not be layed out. The reason
// for this is that layout managers ignore non-visible components,
// therefore non-visible components do not get reshaped.
//
// In the case of a non-visible, non-container component, there is
// no problem. But if you have a non-visible container, then the
// layout method should not be called on that container. But AWT
// ignores visibility and calls layout on
// all containers regardless.
//
// The problem with this is that a non-visible container will not
// have been reshaped when its parent was layed out. Therefore,
// calling layout on this container causes it to do a layout based
// on its own bogus size. This means that all the child components
// get reshaped and validated with incorrect sizes! If the
// non-visible container is later made
// visible, all of its components
// are already valid so they don't get layed out again. But these
// components have incorrect sizes.
//
// This workaround ensures that layout is not called on non-visible
// children of the container.
//
public void validate() {
layout();
// Unfortunately, we don't have access to the valid flag.
// Fortunately, it is okay to leave the component invalid.
//
// Components in an AWT application
// are invalid most of the time
// anyways, because if any child component invalidate, then
// all the parents are invalidated. And there are many
// situations where a child calls
// invalidate where you don't
// want to call validate again. So many components end up
// invalid all the time. This is okay, because
// it just means
// that if you do call validate, then everything will get
// layed out again.
// valid = true;
}
int ncomponents = countComponents();
for (int i = 0; i < ncomponents; i++) {
}
}
}
protected void validateTree() {
layout();
int ncomponents = countComponents();
for (int i = 0; i < ncomponents; ++i) {
}
}
}
}
// Workaround for idiotic JDK1.1 bug where if you add a
// component to a container that it is already in, then
// the component will be removed from the container!
//
// #ifdef JDK1.1
int index) {
}
// #endif
// Need to invalidate because changing
// from a flat relief to something
// else will cause the preferredSize to change.
invalidate();
repaint();
}
public int getRelief() {
return relief;
}
public void setBorderWidth(int borderWidth) {
if (borderWidth != this.borderWidth) {
this.borderWidth = borderWidth;
invalidate();
repaint();
}
}
public int getBorderWidth() {
return borderWidth;
}
borderLabel = label;
invalidate();
repaint();
}
public String getBorderLabel() {
return borderLabel;
}
public void setLabelAlignment(int alignment) {
repaint();
}
public int getLabelAlignment() {
return labelAlignment;
}
else
invalidate();
}
public Insets getBorderInsets() {
}
int h = getLabelAdjustedTop();
}
public Dimension minimumSize() {
Dimension d = super.minimumSize();
int w = getLabelAdjustedMinWidth();
if (w > d.width)
return d;
}
public Dimension preferredSize() {
Dimension d = super.preferredSize();
int w = getLabelAdjustedMinWidth();
if (w > d.width)
return d;
}
private int getBD() {
int bd = 0;
bd = borderWidth;
return bd;
}
private Insets getAdjustedInsets() {
else
return insets;
}
private int getLabelAdjustedTop() {
return 0;
int bd = borderWidth;
if (!isLabelInBorder())
}
return top;
}
private int getLabelAdjustedMinWidth() {
return 0;
int bd = borderWidth;
+ labelpadx + labelipadx);
}
return w;
}
private boolean isLabelInBorder() {
switch (relief) {
case Util.RELIEF_RAISED:
case Util.RELIEF_SUNKEN:
case Util.WIN95_RAISED:
case Util.WIN95_SUNKEN:
case Util.WIN95_FIELD_BORDER:
case Util.WIN95_WINDOW_BORDER:
return false;
case Util.RELIEF_GROOVE:
case Util.RELIEF_RIDGE:
case Util.BLACK_BORDER:
case Util.RELIEF_FLAT:
default:
return true;
}
}
g = getGraphics();
g.setColor(getBackground());
paint(g);
}
// XXX This workaround is needed for both
// Windows and Solaris to ensure
// all lightweight components contained
// within VJPanel are repainted
// correctly; For some reasons, VJPanel
// is entirely filled with
// the background color whenever update()
// is called. If only the
// components within the clip region
// of the "Graphics g" parameter
// is repainted, then the other lightweight
// components become
// invisible because they get painted
// over with the VJPanel background.
// The obvious suspect for filling
// the VJPanel background is the
// fillRect calls in update(), but
// the problem exists even when
// those fillRect calls are not executed. See bug 4074362.
g = getGraphics();
// end of workaround
super.paint(g);
int bd = borderWidth;
if (borderLabel != null) {
}
// Draw the border
switch (relief) {
case Util.RELIEF_FLAT:
case Util.RELIEF_RAISED:
case Util.RELIEF_SUNKEN:
case Util.RELIEF_RIDGE:
case Util.RELIEF_GROOVE:
case Util.WIN95_RAISED:
case Util.WIN95_SUNKEN:
case Util.BLACK_BORDER:
g.setColor(getBackground());
break;
case Util.WIN95_FIELD_BORDER:
case Util.WIN95_WINDOW_BORDER:
break;
}
int yoff = 0;
if (borderLabel != null) {
if (isLabelInBorder())
else
if (yoff < 0)
yoff = 0;
}
}
// Draw the label
if (borderLabel != null) {
int x, y, h;
switch (labelAlignment) {
case LEFT:
default:
break;
case CENTER:
break;
case RIGHT:
break;
}
y = labelpadtop + ascent;
if (isLabelInBorder() && bd > h) {
h = bd;
}
g.setColor(getBackground());
labelipadx, h);
g.setColor(getForeground());
}
}
//
// Workaround for Windows95 AWT bug: If you call
// request focus while
// the mouse is pressed, you get spurious
// mouse down events. Not only
// that, but the spurious events have
// clickCount set to 2, so you end
// up with spurious double clicks. On Windows95 the component
// automatically gets the focus when you press the mouse inside it.
// Therefore, it isn't necessary to call
// requestFocus at all if running
// on Windows and the mouse is down (and this avoids the bug).
//
public void requestFocus() {
super.requestFocus();
}
}