1 /*
   2  * Copyright (c) 2014, 2018, 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     public void doTest() throws Exception {
  68         robot.waitForIdle(delay);
  69     };
  70 
  71     public void dispose() {
  72         window.dispose();
  73         background.dispose();
  74     }
  75 
  76     public abstract void applyShape();
  77 
  78     public void applyDynamicShape() {
  79         final Area a = new Area();
  80         Dimension size = window.getSize();
  81         for (int x = 0; x < 3; x++) {
  82             for (int y = 0; y < 3; y++) {
  83                 a.add(new Area(new Rectangle2D.Double(
  84                         x * size.getWidth() / 17*6, y * size.getHeight() / 17*6,
  85                         size.getWidth() / 17*5, size.getHeight() / 17*5)));
  86             }
  87         }
  88         window.setShape(a);
  89     }
  90 
  91     public void applyStaticShape() {
  92         final Area a = new Area();
  93         for (int x = 0; x < STATIC_BLOCKS; x++) {
  94             for (int y = 0; y < STATIC_BLOCKS; y++) {
  95                 a.add(new Area(new Rectangle2D.Float(
  96                         x*STATIC_STEP, y*STATIC_STEP,
  97                         STATIC_WIDTH, STATIC_WIDTH)));
  98             }
  99         }
 100         window.setShape(a);
 101     }
 102 
 103     public BufferedImage getForegroundWindow() throws Exception {
 104         final BufferedImage f[] = new BufferedImage[1];
 105         EventQueue.invokeAndWait( () -> {
 106             f[0] = new BufferedImage(window.getWidth(),
 107                     window.getHeight(), BufferedImage.TYPE_INT_RGB);
 108             window.printAll(f[0].createGraphics());
 109         });
 110         robot.waitForIdle(delay);
 111         return f[0];
 112     }
 113 
 114     public static boolean checkTranslucencyMode(GraphicsDevice.WindowTranslucency mode) {
 115 
 116         if (!GraphicsEnvironment
 117                 .getLocalGraphicsEnvironment()
 118                 .getDefaultScreenDevice()
 119                 .isWindowTranslucencySupported(mode)){
 120             System.out.println(mode+" translucency mode isn't supported");
 121             return false;
 122         } else {
 123             return true;
 124         }
 125 
 126     }
 127 
 128     public void applyAppDragNResizeSupport() {
 129         MouseAdapter m = new MouseAdapter() {
 130 
 131             private Point dragOrigin = null;
 132             private Dimension origSize = null;
 133             private Point origLoc = null;
 134             private boolean left = false;
 135             private boolean top = false;
 136             private boolean bottom = false;
 137             private boolean right = false;
 138 
 139             public void mousePressed(MouseEvent e) {
 140                 dragOrigin = e.getLocationOnScreen();
 141                 origSize = window.getSize();
 142                 origLoc = window.getLocationOnScreen();
 143                 right = (origLoc.x + window.getWidth() - dragOrigin.x) < 5;
 144                 left = !right && dragOrigin.x - origLoc.x < 5;
 145                 bottom = (origLoc.y + window.getHeight() - dragOrigin.y) < 5;
 146                 top = !bottom && dragOrigin.y - origLoc.y < 5;
 147             }
 148 
 149             public void mouseReleased(MouseEvent e) { resize(e); }
 150             public void mouseDragged(MouseEvent e) { resize(e); }
 151 
 152             void resize(MouseEvent e) {
 153                 Point dragDelta = e.getLocationOnScreen();
 154                 dragDelta.translate(-dragOrigin.x, -dragOrigin.y);
 155                 Point newLoc = new Point(origLoc);
 156                 newLoc.translate(dragDelta.x, dragDelta.y);
 157                 Dimension newSize = new Dimension(origSize);
 158                 if (left || right) {
 159                     newSize.width += right ? dragDelta.x : -dragDelta.x;
 160                 }
 161                 if (top || bottom) {
 162                     newSize.height += bottom ? dragDelta.y : -dragDelta.y;
 163                 }
 164                 if (right || (top || bottom) && !left) {
 165                     newLoc.x = origLoc.x;
 166                 }
 167                 if (bottom || (left || right) && !top) {
 168                     newLoc.y = origLoc.y;
 169                 }
 170                 window.setBounds(newLoc.x, newLoc.y, newSize.width, newSize.height);
 171             }
 172         };
 173         for (Component comp : window.getComponents()) {
 174             comp.addMouseListener(m);
 175             comp.addMouseMotionListener(m);
 176         }
 177 
 178         window.addMouseListener(m);
 179         window.addMouseMotionListener(m);
 180     }
 181 
 182     public void checkTranslucentShape() throws Exception {
 183         foreground = getForegroundWindow();
 184         Point[] points = new Point[4];
 185 
 186         Dimension size = window.getSize();
 187         Point location = window.getLocationOnScreen();
 188 
 189         points[0] = new Point(20, 20);
 190         points[1] = new Point(20, size.height-20);
 191         points[2] = new Point(size.width-20, 20);
 192         points[3] = new Point(size.width-20, size.height-20);
 193 
 194         for (Point p : points){
 195             p.translate(location.x, location.y);
 196             Color actual = robot.getPixelColor(p.x, p.y);
 197             if (actual.equals(BG_COLOR)|| actual.equals(FG_COLOR))
 198                 throw new RuntimeException("Error in point "+p+": "+actual+" equals to foreground or background color");
 199             else
 200                 System.out.println("OK with foreground point "+p);
 201         }
 202     }
 203 
 204     public void checkStaticShape() throws Exception {
 205         Point[] points = new Point[4];
 206 
 207         Dimension size = window.getSize();
 208         int xFactor = (int) Math.floor(size.getWidth()/STATIC_STEP)-1;
 209         int yFactor = (int) Math.floor(size.getHeight()/STATIC_STEP)-1;
 210 
 211         // background
 212         points[0] = new Point((STATIC_STEP+STATIC_WIDTH)/2, (STATIC_STEP+STATIC_WIDTH)/2);
 213         points[1] = new Point(STATIC_STEP*xFactor+(STATIC_STEP+STATIC_WIDTH)/2, STATIC_STEP*yFactor+(STATIC_STEP+STATIC_WIDTH)/2);
 214         points[2] = new Point((STATIC_STEP+STATIC_WIDTH)/2, STATIC_STEP*yFactor+(STATIC_STEP+STATIC_WIDTH)/2);
 215         points[3] = new Point(STATIC_STEP*xFactor+(STATIC_STEP+STATIC_WIDTH)/2, (STATIC_STEP+STATIC_WIDTH)/2);
 216         checkShape(points, true);
 217 
 218         // foreground
 219         if (opacity < 1.0f){
 220             checkTranslucentShape();
 221         } else {
 222             points[0] = new Point((STATIC_WIDTH) / 2, (STATIC_WIDTH) / 2);
 223             points[1] = new Point(STATIC_STEP * xFactor + (STATIC_WIDTH) / 2, STATIC_STEP * yFactor + (STATIC_WIDTH) / 2);
 224             points[2] = new Point((STATIC_WIDTH) / 2, STATIC_STEP * yFactor + (STATIC_WIDTH) / 2);
 225             points[3] = new Point(STATIC_STEP * xFactor + (STATIC_WIDTH) / 2, (STATIC_WIDTH) / 2);
 226             checkShape(points, false);
 227         }
 228     }
 229 
 230     public void checkDynamicShape() throws Exception {
 231         Point[] points = new Point[4];
 232 
 233         Dimension size = window.getSize();
 234 
 235         int blockSizeX = (int) (size.getWidth() / 17);
 236         int blockSizeY = (int) (size.getHeight() / 17);
 237 
 238         // background
 239         points[0] = new Point((int) (blockSizeX * 5.5), (int) (blockSizeY * 5.5));
 240         points[1] = new Point((int) (size.getWidth() - blockSizeX * 5.5), (int) (size.getHeight() - blockSizeY * 5.5));
 241         points[2] = new Point((int) (blockSizeX * 5.5), (int) (size.getHeight() - blockSizeY * 5.5));
 242         points[3] = new Point((int) (size.getWidth() - blockSizeX * 5.5), (int) (blockSizeY * 5.5));
 243         checkShape(points, true);
 244 
 245         // foreground
 246         if (opacity < 1.0f){
 247             checkTranslucentShape();
 248         } else {
 249             points[0] = new Point(3 * blockSizeX, 3 * blockSizeY);
 250             points[1] = new Point(14 * blockSizeX, 14 * blockSizeY);
 251             points[2] = new Point(3 * blockSizeX, 14 * blockSizeY);
 252             points[3] = new Point(14 * blockSizeX, 3 * blockSizeY);
 253             checkShape(points, false);
 254         }
 255     }
 256 
 257     public void checkShape(Point[] points, boolean areBackgroundPoints) throws Exception {
 258 
 259         Point location = window.getLocationOnScreen();
 260 
 261         for (Point p : points) {
 262             p.translate(location.x, location.y);
 263             if (areBackgroundPoints) {
 264                 if (!similarColors(robot.getPixelColor(p.x, p.y), BG_COLOR))
 265                     throw new RuntimeException("Background point " + p + " color " + robot.getPixelColor(p.x, p.y) +
 266                             " does not equal to background color " + BG_COLOR);
 267                 else
 268                     System.out.println("OK with background point " + p);
 269             } else {
 270                 if (similarColors(robot.getPixelColor(p.x, p.y), BG_COLOR))
 271                     throw new RuntimeException("Foreground point " + p +
 272                             " equals to background color " + BG_COLOR);
 273                 else
 274                     System.out.println("OK with foreground point " + p);
 275             }
 276         }
 277     }
 278 
 279     public static boolean similarColors(final Color c1, final Color c2) {
 280         if((Math.abs(c1.getRed() - c2.getRed()) < 40) &&
 281            (Math.abs(c1.getBlue() - c2.getBlue()) < 40) &&
 282            (Math.abs(c1.getGreen() - c2.getGreen()) < 40)) {
 283                 return true;
 284         }
 285         else {
 286             return false;
 287         }
 288     }
 289 
 290     public void initBackgroundFrame() {
 291         background = new Frame();
 292         background.setUndecorated(true);
 293         background.setBackground(BG_COLOR);
 294         background.setSize(500, 500);
 295         background.setLocation(dl, dl);
 296         background.setVisible(true);
 297     }
 298 
 299     public void initGUI() {
 300         if (windowClass.equals(Frame.class)) {
 301             window = new Frame();
 302             ((Frame) window).setUndecorated(true);
 303         } else  if (windowClass.equals(Dialog.class)) {
 304             window = new Dialog(background);
 305             ((Dialog) window).setUndecorated(true);
 306         } else {
 307             window = new Window(background);
 308         }
 309 
 310         window.setBackground(FG_COLOR);
 311         componentsContainer = new Panel();
 312         window.add(componentsContainer, BorderLayout.CENTER);
 313         window.setLocation(2 * dl, 2 * dl);
 314         window.setSize(255, 255);
 315         if (opacity < 1.0f)
 316             window.setOpacity(opacity);
 317         window.addComponentListener(new ComponentAdapter() {
 318             public void componentResized(ComponentEvent e) {
 319                 applyShape();
 320             }
 321         });
 322         applyShape();
 323         window.setVisible(true);
 324         applyAppDragNResizeSupport();
 325         window.toFront();
 326     }
 327 }