--- /dev/null 2014-07-07 11:17:24.879339622 +0400 +++ new/test/java/awt/event/helpers/lwcomponents/LWComponent.java 2014-07-08 15:16:26.000000000 +0400 @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2001, 2014, 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. + * + * 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 test.java.awt.event.helpers.lwcomponents; + +import java.io.*; +import java.awt.*; +import java.awt.event.*; + +/** + * This is experimental - The idea is to subclass all the LW components + * from LWComponent to provide for some common capabilities. The main + * capability to be provided is the status rectangles as done for LWButton. + * In particular the Focus and MouseOver rectangles are generically + * useful, while other rectangles might be useful to other components.

+ * + * To implement that, here is the idea ... borrowed from Win32 ... Each + * of the LW components has both a client and non-client region. We + * call paintNC to paint the non-client region (Focus and MouseOver + * rectangles), and the subclass might be permitted to implement paintNC + * but for now they aren't.

+ * + * Then the paint{Enabled,Disabled} methods are called as appropriate. + * Note that paintDisabled is implemented in LWComponent to call paintEnabled + * then stipple over the top of it.

+ * + * So it is paintEnabled that the component should implement. This method + * needs to know the dimensions of the client area (getClientRegion?) and + * the Graphics needs to have it's clip region set appropriately.

+ * + * KVETCHING: Kvetch is a Yiddish word which means, basically, + * to complain very precisely. The LWComponent family tracks various pieces + * of information over time that are used to check closely for correct behavior + * in some circumstances. The method kvetch is where this code lives + * and is intended to check a broad range of conditions.

+ * + * To turn off specific kvetch's, one simply specifies a System property + * as in this table:

+ * + * + * + * + * + * + * + * + *
Property nameValueDiscussion
javasoft.awtsqe.lw.IGNORE_FOCUS_KVETCHtrue or falseSpecify whether the hasFocus kvetch is checked.

+ * + * XXX To implement - specifying colors. NCBackground, + * FocusRectColor, MouseOverColor are the threee colors. paintNC + * fills the NC region with NCBackground, and then pains the two + * colors as appropriate. There needs to be methods to get/specify + * these colors.

+ * + * XXX To implement - Specifying the component name and toString(). + * The subclass should only give the base class name, and a method + * in LWComponent should construct a name from that. For toString() + * there needs to be a small amount of infrastructure built.

+ */ + +public abstract class LWComponent extends Component { + + protected static Color ncBackgroundColor; + protected static Color focusColor; + protected static Color focusWrongColor; + protected static Color mouseOverColor; + + static { + ncBackgroundColor = Color.white; + focusColor = Color.black; + focusWrongColor = Color.magenta; + mouseOverColor = Color.blue; + } + + /** + * Flag indicating whether our records indicate that the component + * should have focus. + */ + protected boolean _shouldHaveFocus = false; + protected boolean _shouldBeShowing = false; + + protected boolean mouseB1Pressed = false; + protected boolean mouseB2Pressed = false; + protected boolean mouseB3Pressed = false; + protected boolean mouseInside = false; + + protected static boolean tracingOn = false; + protected static PrintStream traceOutput = null; + + // Uncommenting these lines turns on tracing for the package. + // static { + // tracingOn = true; + // traceOutput = System.err; + // } + + public LWComponent() { + enableEvents(AWTEvent.MOUSE_EVENT_MASK + /*| AWTEvent.MOUSE_MOTION_EVENT_MASK*/ + | AWTEvent.FOCUS_EVENT_MASK + | AWTEvent.COMPONENT_EVENT_MASK); + } + + /** + * Print out an error message. + * @param msg the message + */ + public static void errorMsg(String msg) { + System.err.println("ERROR: " + msg); + } + + /** + * Print out a tracing message + * @param msg the message + */ + public static void traceMsg(String msg) { + if (LWComponent.tracingOn) { + LWComponent.traceOutput.println(msg); + } + } + + ///////////////////////////////////////////// + /////// FLAGS FOR IGNORING KVETCH's ///////// + ///////////////////////////////////////////// + + static boolean bIgnFocus = false; + + static { + // Initialize the kvetch ignoring flags here. + String ignFocus = System.getProperty("javasoft.awtsqe.lw.IGNORE_FOCUS_KVETCH", + "false"); + bIgnFocus = ignFocus.trim().toLowerCase().equals("true"); + } + + /** + * Check the shoulds and return a string indicating which + * do not match the components actual state. + * + * @return the string indicating which do not match the components actual state + */ + public String kvetch() { + String ret = this.toString(); + boolean errors = false; + + if (!bIgnFocus) { + if (hasFocus()) { + if (!shouldHaveFocus()) { + ret += "\nERROR: hasFocus indicates we have Focus, when we shouldn't."; + errors = true; + } + } else { + if (shouldHaveFocus()) { + ret += "\nERROR: (see bug#4233658) hasFocus does not indicate we have Focus, when we should."; + errors = true; + } + } + } + + if (errors) { + return ret; + } else { + return null; + } + } + + /** + * Check the shoulds and return a string indicating which + * do not match the components actual state. Prints the output + * to the given PrintStream. + * @param out The PrintStream to print to. + */ + public void kvetch(PrintStream out) { + if (out != null) { + String s = kvetch(); + if (s != null) { + LWComponent.errorMsg(s); + } + } + } + + /** + * Turn on tracing for the LWComponent family. + * @param out the output stream + */ + public static void startTracing(PrintStream out) { + tracingOn = true; + traceOutput = out; + } + + /** + * Turn off tracing for the LWComponent family. + */ + public static void stopTracing() { tracingOn = false; traceOutput = null; } + + /** + * Indicate whether it is believed the component should have focus. + * @return {@code true} if the component should have focus + */ + public boolean shouldHaveFocus() { return _shouldHaveFocus; } + + /** + * Indicate whether it is believed the component should be showing. + * @return {@code true} if the component should be showing + */ + public boolean shouldBeShowing() { return _shouldBeShowing; } + + @Override + protected void processFocusEvent(FocusEvent e) { + super.processFocusEvent(e); + LWComponent.traceMsg("processFocusEvent " + e.toString()); + switch (e.getID()) { + case FocusEvent.FOCUS_GAINED: + _shouldHaveFocus = true; + repaint(); + break; + case FocusEvent.FOCUS_LOST: + _shouldHaveFocus = false; + repaint(); + break; + } + } + + @Override + protected void processComponentEvent(ComponentEvent e) { + super.processComponentEvent(e); + LWComponent.traceMsg("processComponentEvent " + e.toString()); + switch (e.getID()) { + case ComponentEvent.COMPONENT_MOVED: break; + case ComponentEvent.COMPONENT_RESIZED: break; + case ComponentEvent.COMPONENT_SHOWN: _shouldBeShowing = true; break; + case ComponentEvent.COMPONENT_HIDDEN: _shouldBeShowing = false; break; + } + } + + @Override + protected void processMouseEvent(MouseEvent e) { + int mod = e.getModifiers(); + super.processMouseEvent(e); + LWComponent.traceMsg("processMouseEvent " + e.toString()); + switch (e.getID()) { + case MouseEvent.MOUSE_PRESSED: + if ((mod & MouseEvent.BUTTON1_MASK) != 0) { + if (mouseB1Pressed) { + errorMsg("ERROR: MOUSE_PRESSED for B1 when already pressed, on " + + this.toString()); + } + mouseB1Pressed = true; + break; + } + if ((mod & MouseEvent.BUTTON2_MASK) != 0) { + if (mouseB2Pressed) { + errorMsg("ERROR: MOUSE_PRESSED for B2 when already pressed, on " + + this.toString()); + } + mouseB2Pressed = true; + break; + } + if ((mod & MouseEvent.BUTTON3_MASK) != 0) { + if (mouseB3Pressed) { + errorMsg("ERROR: MOUSE_PRESSED for B3 when already pressed, on " + + this.toString()); + } + mouseB3Pressed = true; + break; + } + repaint(); + break; + case MouseEvent.MOUSE_RELEASED: + if ((mod & MouseEvent.BUTTON1_MASK) != 0) { + if (!mouseB1Pressed) { + errorMsg("ERROR: MOUSE_RELEASED for B1 when not pressed, on " + + this.toString()); + } + mouseB1Pressed = false; + break; + } + if ((mod & MouseEvent.BUTTON2_MASK) != 0) { + if (!mouseB2Pressed) { + errorMsg("ERROR: MOUSE_RELEASED for B2 when not pressed, on " + + this.toString()); + } + mouseB2Pressed = false; + break; + } + if ((mod & MouseEvent.BUTTON3_MASK) != 0) { + if (!mouseB3Pressed) { + errorMsg("ERROR: MOUSE_RELEASED for B3 when not pressed, on " + + this.toString()); + } + mouseB3Pressed = false; + break; + } + repaint(); + break; + case MouseEvent.MOUSE_CLICKED: + break; + case MouseEvent.MOUSE_ENTERED: + if (mouseInside) { + errorMsg("ERROR: MOUSE_ENTERED when mouse already inside component, on " + + this.toString()); + } + mouseInside = true; + repaint(); + break; + case MouseEvent.MOUSE_EXITED: + if (!mouseInside) { + errorMsg("ERROR: MOUSE_EXITED when mouse not inside component, on " + + this.toString()); + } + mouseInside = false; + repaint(); + break; + case MouseEvent.MOUSE_MOVED: + break; + case MouseEvent.MOUSE_DRAGGED: + break; + } + } + + public Point getClientLocation() { + return new Point(5, 5); + } + + public Dimension getClientSize() { + Dimension dim = getSize(); + dim.width -= 10; + dim.height -= 10; + return dim; + } + + public Rectangle getClientBounds() { + Dimension dim = getClientSize(); + return new Rectangle(5, 5, dim.width, dim.height); + } + + public int getClientX() { return 5; } + public int getClientY() { return 5; } + + /** + * Set the color used for painting the non-client area of the component. + * The default for this is Color.white. + * + * @param c The new color to use. + */ + public void setNonClientColor(Color c) { + LWComponent.ncBackgroundColor = c; + } + + /** + * Handle painting for the component. + */ + @Override + public void paint(Graphics g) { + Dimension dim = getSize(); + + kvetch(System.err); + + Color saveColor = g.getColor(); + super.paint(g); + + // ------------------- Paint the background ----------------- + + // In jdk 1.2 (pre-release) there was a bug using clearRect + // to paint the background of a lightweight. + //g.clearRect(0, 0, dim.width, dim.height); + g.setColor(getBackground()); + g.fillRect(0, 0, dim.width, dim.height); + + // ------------------- Paint the non-client area ------------ + + g.setColor(ncBackgroundColor); + // x y width height + g.fillRect(0, 0, dim.width, 5); + g.fillRect(0, 5, 5, dim.height - 10); + g.fillRect(dim.width - 5, 5, 5, dim.height - 10); + g.fillRect(0, dim.height - 5, dim.width, 5); + + if (shouldHaveFocus() || hasFocus()) { + g.setColor(shouldHaveFocus() && hasFocus() + ? focusColor + : focusWrongColor); + g.drawRect(1, 1, dim.width - 3, dim.height - 3); + } + + if (mouseInside) { + g.setColor(mouseOverColor); + g.drawRect(3, 3, dim.width - 7, dim.height - 7); + } + + // ------------------- Paint disabledness, if true ----------- + + if (!isEnabled()) { + g.setColor(getBackground()); + Dimension size = getSize(); + int borderThickness = 0; + int startX = borderThickness; + int startY = borderThickness; + int endX = startX + size.width - 2 * borderThickness - 2; + int endY = startY + size.height - 2 * borderThickness - 2; + int x, y; + for (y = startY; y <= endY; y += 1) { + for (x = startX + (y % 2); x <= endX; x += 2) { + g.fillRect(x, y, 1, 1); + } // x + } // y + } + + g.setColor(saveColor); + } + + /** + * Restricts the Graphics to be within the "client area" of the + * component. Recall that the LWComponent series of components has + * a "non-client area" of 5 pixels wide in which it draws two + * status rectangles showing mouse-over and has-focus status.

+ * + * Child classes of LWComponent are to call {@code restrictGraphicsToClientArea} + * at the beginning of their {@code paint} method, and then call + * {@code unrestrictGraphicsFromClientArea} afterwards.

+ * + * In order to make those paint methods as convenient as possible, these + * two methods make it appear as if the Graphics available to the + * component is slightly smaller than it really is, by the amount + * used in the non-client area (5 pixel wide border).

+ * + * @param g The Graphics to restrict. + */ + public void restrictGraphicsToClientArea(Graphics g) { + Dimension dim = getSize(); + g.translate(5, 5); + g.setClip(0, 0, dim.width - 10, dim.height - 10); + } + + /** + * Undo the restriction done in restrictGraphicsToClientArea. + * + * @param g The Graphics to unrestrict. + */ + public void unrestrictGraphicsFromClientArea(Graphics g) { + g.translate(-5, -5); + Dimension dim = getSize(); + g.setClip(0, 0, dim.width, dim.height); + } + +}