1 /*
   2  * Copyright (c) 2014, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.awt.*;
  25 import java.awt.event.*;
  26 import java.awt.geom.Area;
  27 import java.awt.geom.Rectangle2D;
  28 import java.awt.image.BufferedImage;
  29 import java.security.SecureRandom;
  30 
  31 
  32 /*
  33  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
  34  */
  35 public abstract class Common {
  36 
  37     ExtendedRobot robot;
  38     Class<? extends Frame> windowClass;
  39     Frame background;
  40     BufferedImage foreground;
  41     Window window;
  42     Container componentsContainer;
  43 
  44     float opacity = 1.0f;
  45     static final int STATIC_STEP = 30;
  46     static final int STATIC_WIDTH = 25;
  47     static final int STATIC_BLOCKS = 30;
  48     static final Color BG_COLOR = Color.BLUE;
  49     static final Color FG_COLOR = Color.RED;
  50     static final int delay = 1000;
  51     static final SecureRandom random = new SecureRandom();
  52     static final int dl = 100;
  53     static final Class[] WINDOWS_TO_TEST = { Window.class, Frame.class, Dialog.class };
  54 
  55     public Common(Class windowClass, float opacity) throws Exception{
  56         this.opacity = opacity;
  57         robot = new ExtendedRobot();
  58         this.windowClass = windowClass;
  59         EventQueue.invokeAndWait(this::initBackgroundFrame);
  60         EventQueue.invokeAndWait(this::initGUI);
  61     }
  62 
  63     public Common(Class windowClass) throws Exception{
  64         this(windowClass, 1.0f);
  65     }
  66 
  67     void drag (int fromX, int fromY, int toX, int toY) throws Exception {
  68         robot.mouseMove(fromX, fromY);
  69         robot.waitForIdle(delay);
  70         robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
  71         robot.waitForIdle(delay);
  72         robot.glide(toX, toY);
  73         robot.waitForIdle(delay);
  74         robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
  75     }
  76 
  77     public void doTest() throws Exception {
  78         robot.waitForIdle(delay);
  79     };
  80 
  81     public void dispose() {
  82         window.dispose();
  83         background.dispose();
  84     }
  85 
  86     public abstract void applyShape();
  87 
  88     public void applyDynamicShape() {
  89         final Area a = new Area();
  90         Dimension size = window.getSize();
  91         for (int x = 0; x < 3; x++) {
  92             for (int y = 0; y < 3; y++) {
  93                 a.add(new Area(new Rectangle2D.Double(
  94                         x * size.getWidth() / 17*6, y * size.getHeight() / 17*6,
  95                         size.getWidth() / 17*5, size.getHeight() / 17*5)));
  96             }
  97         }
  98         window.setShape(a);
  99     }
 100 
 101     public void applyStaticShape() {
 102         final Area a = new Area();
 103         for (int x = 0; x < STATIC_BLOCKS; x++) {
 104             for (int y = 0; y < STATIC_BLOCKS; y++) {
 105                 a.add(new Area(new Rectangle2D.Float(
 106                         x*STATIC_STEP, y*STATIC_STEP,
 107                         STATIC_WIDTH, STATIC_WIDTH)));
 108             }
 109         }
 110         window.setShape(a);
 111     }
 112 
 113     public BufferedImage getForegroundWindow() throws Exception {
 114         final BufferedImage f[] = new BufferedImage[1];
 115         EventQueue.invokeAndWait( () -> {
 116             f[0] = new BufferedImage(window.getWidth(),
 117                     window.getHeight(), BufferedImage.TYPE_INT_RGB);
 118             window.printAll(f[0].createGraphics());
 119         });
 120         robot.waitForIdle(delay);
 121         return f[0];
 122     }
 123 
 124     public static void checkTranslucencyMode(GraphicsDevice.WindowTranslucency mode) {
 125         if (!GraphicsEnvironment
 126                 .getLocalGraphicsEnvironment()
 127                 .getDefaultScreenDevice()
 128                 .isWindowTranslucencySupported(mode))
 129             throw new RuntimeException(mode+" translucency mode isn't supported");
 130     }
 131 
 132     public void applyAppDragNResizeSupport() {
 133         MouseAdapter m = new MouseAdapter() {
 134 
 135             private Point dragOrigin = null;
 136             private Dimension origSize = null;
 137             private Point origLoc = null;
 138             private boolean left = false;
 139             private boolean top = false;
 140             private boolean bottom = false;
 141             private boolean right = false;
 142 
 143             public void mousePressed(MouseEvent e) {
 144                 dragOrigin = e.getLocationOnScreen();
 145                 origSize = window.getSize();
 146                 origLoc = window.getLocationOnScreen();
 147                 right = (origLoc.x + window.getWidth() - dragOrigin.x) < 5;
 148                 left = !right && dragOrigin.x - origLoc.x < 5;
 149                 bottom = (origLoc.y + window.getHeight() - dragOrigin.y) < 5;
 150                 top = !bottom && dragOrigin.y - origLoc.y < 5;
 151             }
 152 
 153             public void mouseReleased(MouseEvent e) { resize(e); }
 154             public void mouseDragged(MouseEvent e) { resize(e); }
 155 
 156             void resize(MouseEvent e) {
 157                 Point dragDelta = e.getLocationOnScreen();
 158                 dragDelta.translate(-dragOrigin.x, -dragOrigin.y);
 159                 Point newLoc = new Point(origLoc);
 160                 newLoc.translate(dragDelta.x, dragDelta.y);
 161                 Dimension newSize = new Dimension(origSize);
 162                 if (left || right) {
 163                     newSize.width += right ? dragDelta.x : -dragDelta.x;
 164                 }
 165                 if (top || bottom) {
 166                     newSize.height += bottom ? dragDelta.y : -dragDelta.y;
 167                 }
 168                 if (right || (top || bottom) && !left) {
 169                     newLoc.x = origLoc.x;
 170                 }
 171                 if (bottom || (left || right) && !top) {
 172                     newLoc.y = origLoc.y;
 173                 }
 174                 window.setBounds(newLoc.x, newLoc.y, newSize.width, newSize.height);
 175             }
 176         };
 177         for (Component comp : window.getComponents()) {
 178             comp.addMouseListener(m);
 179             comp.addMouseMotionListener(m);
 180         }
 181 
 182         window.addMouseListener(m);
 183         window.addMouseMotionListener(m);
 184     }
 185 
 186     public void checkTranslucentShape() throws Exception {
 187         foreground = getForegroundWindow();
 188         Point[] points = new Point[4];
 189 
 190         Dimension size = window.getSize();
 191         Point location = window.getLocationOnScreen();
 192 
 193         points[0] = new Point(20, 20);
 194         points[1] = new Point(20, size.height-20);
 195         points[2] = new Point(size.width-20, 20);
 196         points[3] = new Point(size.width-20, size.height-20);
 197 
 198         for (Point p : points){
 199             p.translate(location.x, location.y);
 200             Color actual = robot.getPixelColor(p.x, p.y);
 201             if (actual.equals(BG_COLOR)|| actual.equals(FG_COLOR))
 202                 throw new RuntimeException("Error in point "+p+": "+actual+" equals to foreground or background color");
 203             else
 204                 System.out.println("OK with foreground point "+p);
 205         }
 206     }
 207 
 208     public void checkStaticShape() throws Exception {
 209         Point[] points = new Point[4];
 210 
 211         Dimension size = window.getSize();
 212         int xFactor = (int) Math.floor(size.getWidth()/STATIC_STEP)-1;
 213         int yFactor = (int) Math.floor(size.getHeight()/STATIC_STEP)-1;
 214 
 215         // background
 216         points[0] = new Point((STATIC_STEP+STATIC_WIDTH)/2, (STATIC_STEP+STATIC_WIDTH)/2);
 217         points[1] = new Point(STATIC_STEP*xFactor+(STATIC_STEP+STATIC_WIDTH)/2, STATIC_STEP*yFactor+(STATIC_STEP+STATIC_WIDTH)/2);
 218         points[2] = new Point((STATIC_STEP+STATIC_WIDTH)/2, STATIC_STEP*yFactor+(STATIC_STEP+STATIC_WIDTH)/2);
 219         points[3] = new Point(STATIC_STEP*xFactor+(STATIC_STEP+STATIC_WIDTH)/2, (STATIC_STEP+STATIC_WIDTH)/2);
 220         checkShape(points, true);
 221 
 222         // foreground
 223         if (opacity < 1.0f){
 224             checkTranslucentShape();
 225         } else {
 226             points[0] = new Point((STATIC_WIDTH) / 2, (STATIC_WIDTH) / 2);
 227             points[1] = new Point(STATIC_STEP * xFactor + (STATIC_WIDTH) / 2, STATIC_STEP * yFactor + (STATIC_WIDTH) / 2);
 228             points[2] = new Point((STATIC_WIDTH) / 2, STATIC_STEP * yFactor + (STATIC_WIDTH) / 2);
 229             points[3] = new Point(STATIC_STEP * xFactor + (STATIC_WIDTH) / 2, (STATIC_WIDTH) / 2);
 230             checkShape(points, false);
 231         }
 232     }
 233 
 234     public void checkDynamicShape() throws Exception {
 235         Point[] points = new Point[4];
 236 
 237         Dimension size = window.getSize();
 238 
 239         int blockSizeX = (int) (size.getWidth() / 17);
 240         int blockSizeY = (int) (size.getHeight() / 17);
 241 
 242         // background
 243         points[0] = new Point((int) (blockSizeX * 5.5), (int) (blockSizeY * 5.5));
 244         points[1] = new Point((int) (size.getWidth() - blockSizeX * 5.5), (int) (size.getHeight() - blockSizeY * 5.5));
 245         points[2] = new Point((int) (blockSizeX * 5.5), (int) (size.getHeight() - blockSizeY * 5.5));
 246         points[3] = new Point((int) (size.getWidth() - blockSizeX * 5.5), (int) (blockSizeY * 5.5));
 247         checkShape(points, true);
 248 
 249         // foreground
 250         if (opacity < 1.0f){
 251             checkTranslucentShape();
 252         } else {
 253             points[0] = new Point(3 * blockSizeX, 3 * blockSizeY);
 254             points[1] = new Point(14 * blockSizeX, 14 * blockSizeY);
 255             points[2] = new Point(3 * blockSizeX, 14 * blockSizeY);
 256             points[3] = new Point(14 * blockSizeX, 3 * blockSizeY);
 257             checkShape(points, false);
 258         }
 259     }
 260 
 261     public void checkShape(Point[] points, boolean areBackgroundPoints) throws Exception {
 262 
 263         Point location = window.getLocationOnScreen();
 264 
 265         for (Point p : points) {
 266             p.translate(location.x, location.y);
 267             if (areBackgroundPoints) {
 268                 if (!robot.getPixelColor(p.x, p.y).equals(BG_COLOR))
 269                     throw new RuntimeException("Background point " + p + " color " + robot.getPixelColor(p.x, p.y) +
 270                             " does not equal to background color " + BG_COLOR);
 271                 else
 272                     System.out.println("OK with background point " + p);
 273             } else {
 274                 if (robot.getPixelColor(p.x, p.y).equals(BG_COLOR))
 275                     throw new RuntimeException("Foreground point " + p +
 276                             " equals to background color " + BG_COLOR);
 277                 else
 278                     System.out.println("OK with foreground point " + p);
 279             }
 280         }
 281     }
 282 
 283     public void initBackgroundFrame() {
 284         background = new Frame();
 285         background.setUndecorated(true);
 286         background.setBackground(BG_COLOR);
 287         background.setSize(500, 500);
 288         background.setLocation(dl, dl);
 289         background.setVisible(true);
 290     }
 291 
 292     public void initGUI() {
 293         if (windowClass.equals(Frame.class)) {
 294             window = new Frame();
 295             ((Frame) window).setUndecorated(true);
 296         } else  if (windowClass.equals(Dialog.class)) {
 297             window = new Dialog(background);
 298             ((Dialog) window).setUndecorated(true);
 299         } else {
 300             window = new Window(background);
 301         }
 302 
 303         window.setBackground(FG_COLOR);
 304         componentsContainer = new Panel();
 305         window.add(componentsContainer, BorderLayout.CENTER);
 306         window.setLocation(2 * dl, 2 * dl);
 307         window.setSize(255, 255);
 308         if (opacity < 1.0f)
 309             window.setOpacity(opacity);
 310         window.addComponentListener(new ComponentAdapter() {
 311             public void componentResized(ComponentEvent e) {
 312                 applyShape();
 313             }
 314         });
 315         applyShape();
 316         window.setVisible(true);
 317         applyAppDragNResizeSupport();
 318         window.toFront();
 319     }
 320 }