/* * Copyright (c) 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. */ import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.*; import java.awt.geom.Area; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.security.SecureRandom; public abstract class Common { ExtendedRobot robot; Class<? extends JFrame> windowClass; JFrame background; BufferedImage foreground; Window window; volatile boolean gradientBackgroundEnabled = false; volatile int gradientWidth = 255; volatile int gradientHeight = 255; float opacity = 1.0f; float perPixelTranslucency = 1.0f; static Color BG_COLOR = Color.BLUE; static Color FG_COLOR = Color.RED; static final int delay = 1000; static final SecureRandom random = new SecureRandom(); static final int dl = 100; static final Class[] WINDOWS_TO_TEST = { JWindow.class, JFrame.class, JDialog.class }; volatile int clicked; public Common(Class windowClass, float opacity, float perPixelTranslucency, boolean gradient) throws Exception { this.gradientBackgroundEnabled = gradient; this.perPixelTranslucency = perPixelTranslucency; this.opacity = opacity; robot = new ExtendedRobot(); this.windowClass = windowClass; EventQueue.invokeAndWait(this::initBackgroundFrame); EventQueue.invokeAndWait(this::initGUI); } public Common(Class windowClass) throws Exception { this(windowClass, 1.0f, 1.0f, false); } public Common(Class windowClass, boolean gradient) throws Exception { this(windowClass, 1.0f, 1.0f, gradient); } public abstract void doTest() throws Exception; public void dispose() { window.dispose(); background.dispose(); } public void applyShape() {}; public void applyDynamicShape() { final Area a = new Area(); Dimension size = window.getSize(); for (int x = 0; x < 3; x++) { for (int y = 0; y < 3; y++) { a.add(new Area(new Rectangle2D.Double( x * size.getWidth() / 17*6, y * size.getHeight() / 17*6, size.getWidth() / 17*5, size.getHeight() / 17*5))); } } window.setShape(a); } public BufferedImage getForegroundWindow() throws Exception { final BufferedImage f[] = new BufferedImage[1]; EventQueue.invokeAndWait( () -> { f[0] = new BufferedImage(window.getWidth(), window.getHeight(), BufferedImage.TYPE_INT_RGB); window.printAll(f[0].createGraphics()); }); robot.waitForIdle(delay); return f[0]; } public static boolean checkTranslucencyMode(GraphicsDevice.WindowTranslucency mode) { if (!GraphicsEnvironment .getLocalGraphicsEnvironment() .getDefaultScreenDevice() .isWindowTranslucencySupported(mode)){ System.out.println(mode+" translucency mode isn't supported"); return false; } else { return true; } } public void applyAppDragNResizeSupport() { MouseAdapter m = new MouseAdapter() { private Point dragOrigin = null; private Dimension origSize = null; private Point origLoc = null; private boolean left = false; private boolean top = false; private boolean bottom = false; private boolean right = false; public void mousePressed(MouseEvent e) { dragOrigin = e.getLocationOnScreen(); origSize = window.getSize(); origLoc = window.getLocationOnScreen(); right = (origLoc.x + window.getWidth() - dragOrigin.x) < 5; left = !right && dragOrigin.x - origLoc.x < 5; bottom = (origLoc.y + window.getHeight() - dragOrigin.y) < 5; top = !bottom && dragOrigin.y - origLoc.y < 5; } public void mouseReleased(MouseEvent e) { resize(e); } public void mouseDragged(MouseEvent e) { resize(e); } void resize(MouseEvent e) { Point dragDelta = e.getLocationOnScreen(); dragDelta.translate(-dragOrigin.x, -dragOrigin.y); Point newLoc = new Point(origLoc); newLoc.translate(dragDelta.x, dragDelta.y); Dimension newSize = new Dimension(origSize); if (left || right) { newSize.width += right ? dragDelta.x : -dragDelta.x; } if (top || bottom) { newSize.height += bottom ? dragDelta.y : -dragDelta.y; } if (right || (top || bottom) && !left) { newLoc.x = origLoc.x; } if (bottom || (left || right) && !top) { newLoc.y = origLoc.y; } window.setBounds(newLoc.x, newLoc.y, newSize.width, newSize.height); } }; for (Component comp : window.getComponents()) { comp.addMouseListener(m); comp.addMouseMotionListener(m); } window.addMouseListener(m); window.addMouseMotionListener(m); } public void checkTranslucentShape() throws Exception { foreground = getForegroundWindow(); Point[] points = new Point[4]; Dimension size = window.getSize(); Point location = window.getLocationOnScreen(); points[0] = new Point(20, 20); points[1] = new Point(20, size.height-20); points[2] = new Point(size.width-20, 20); points[3] = new Point(size.width-20, size.height-20); for (Point p : points){ p.translate(location.x, location.y); Color actual = robot.getPixelColor(p.x, p.y); if (actual.equals(BG_COLOR)|| actual.equals(FG_COLOR)) throw new RuntimeException("Error in point "+p+": "+actual+" equals to foreground or background color"); else System.out.println("OK with foreground point "+p); } } public void checkDynamicShape() throws Exception { Point[] points = new Point[4]; Dimension size = window.getSize(); int blockSizeX = (int) (size.getWidth() / 17); int blockSizeY = (int) (size.getHeight() / 17); // background points[0] = new Point((int) (blockSizeX * 5.5), (int) (blockSizeY * 5.5)); points[1] = new Point((int) (size.getWidth() - blockSizeX * 5.5), (int) (size.getHeight() - blockSizeY * 5.5)); points[2] = new Point((int) (blockSizeX * 5.5), (int) (size.getHeight() - blockSizeY * 5.5)); points[3] = new Point((int) (size.getWidth() - blockSizeX * 5.5), (int) (blockSizeY * 5.5)); checkShape(points, true); // foreground if (opacity < 1.0f){ checkTranslucentShape(); } else { points[0] = new Point(3 * blockSizeX, 3 * blockSizeY); points[1] = new Point(14 * blockSizeX, 14 * blockSizeY); points[2] = new Point(3 * blockSizeX, 14 * blockSizeY); points[3] = new Point(14 * blockSizeX, 3 * blockSizeY); checkShape(points, false); } } public void checkShape(Point[] points, boolean areBackgroundPoints) throws Exception { Point location = window.getLocationOnScreen(); for (Point p : points) { p.translate(location.x, location.y); Color pixel = robot.getPixelColor(p.x, p.y); if (areBackgroundPoints) { if (pixel.getRed() != 0 || pixel.getGreen() != 0 ) throw new RuntimeException("Background point " + p + " color " + pixel + " does not equal to background color " + BG_COLOR); else System.out.println("OK with background point " + p); } else { if (pixel.equals(BG_COLOR)) throw new RuntimeException("Foreground point " + p + " color " + pixel + " equals to background color " + BG_COLOR); else System.out.println("OK with foreground point " + p); } } } public void initBackgroundFrame() { background = new JFrame(); background.setUndecorated(true); background.getContentPane().setBackground(BG_COLOR); background.setSize(500, 500); background.setLocation(dl, dl); background.setVisible(true); } public void initGUI() { Container contentPane; if (windowClass.equals(Frame.class)) { window = new JFrame(); ((JFrame) window).setUndecorated(true); contentPane = ((JFrame) window).getContentPane(); } else if (windowClass.equals(Dialog.class)) { window = new JDialog(background); ((JDialog) window).setUndecorated(true); contentPane = ((JDialog) window).getContentPane(); } else { window = new JWindow(background); contentPane = ((JWindow) window).getContentPane(); } if (perPixelTranslucency < 1.0f) { contentPane.setBackground(colorWithOpacity(FG_COLOR, perPixelTranslucency)); window.setBackground(colorWithOpacity(FG_COLOR, perPixelTranslucency)); } else { contentPane.setBackground(FG_COLOR); window.setBackground(FG_COLOR); } window.setLocation(2 * dl, 2 * dl); window.setSize(255, 255); window.setPreferredSize(new Dimension(255, 255)); createSwingComponents(); if (opacity < 1.0f) window.setOpacity(opacity); window.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { applyShape(); } }); applyShape(); window.setVisible(true); applyAppDragNResizeSupport(); window.toFront(); } public void createSwingComponents() { Container contentPane; if (gradientBackgroundEnabled) { JPanel jPanel = new JPanel() { @Override protected void paintComponent(Graphics g) { if (g instanceof Graphics2D) { Color background = Color.RED; Paint p = new GradientPaint(0.0f, 0.0f, colorWithOpacity(background, 0), 0.0f, gradientHeight - 3, colorWithOpacity(background, 1), true); Graphics2D g2d = (Graphics2D) g; g2d.setPaint(p); g2d.fillRect(0, 3, gradientWidth, gradientHeight - 3); } else { super.paintComponent(g); } } }; jPanel.setBorder(new EmptyBorder(15, 5, 5, 5)); jPanel.setOpaque(false); contentPane = jPanel; RootPaneContainer.class.cast(window).setContentPane(contentPane); } else { contentPane = RootPaneContainer.class.cast(window).getContentPane(); } contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); JButton button = new JButton("JButton"); window.add(button); JTextArea textArea = new JTextArea("JTextArea"); window.add(textArea); JCheckBox checkbox = new JCheckBox("JCheckBox"); checkbox.setOpaque(false); window.add(checkbox); JComboBox comboBox = new JComboBox(new String[]{"JComboBox", "Some item"}); window.add(comboBox); JLabel label = new JLabel("JLabel"); window.add(label); JTextField textField = new JTextField("JTextField"); window.add(textField); JPanel panel = new JPanel(); panel.setOpaque(false); window.add(panel); JComboBox comboBox2 = new JComboBox(new String[]{"JComboBox2", "Another item"}); window.add(comboBox2); JRadioButton radioButton = new JRadioButton("JRadioButton"); radioButton.setOpaque(false); window.add(radioButton); } Color colorWithOpacity(Color color, float opacity) { return new Color(color.getColorSpace(), color.getColorComponents(null), opacity); } public void checkTranslucent() throws Exception { checkTranslucentShape(); // Drag Point location = window.getLocationOnScreen(); robot.dragAndDrop(location.x + 30, location.y + 5, location.x + dl + random.nextInt(dl), location.y + random.nextInt(dl)); robot.waitForIdle(delay); checkTranslucentShape(); // Resize location = window.getLocationOnScreen(); robot.dragAndDrop(location.x + 4, location.y + 4, location.x + random.nextInt(2*dl)-dl, location.y + random.nextInt(2*dl)-dl); robot.waitForIdle(delay); checkTranslucentShape(); EventQueue.invokeAndWait(this::dispose); } public void checkDynamic() throws Exception { checkDynamicShape(); // Drag Point location = window.getLocationOnScreen(); robot.dragAndDrop(location.x + 30, location.y + 5, location.x + dl + random.nextInt(dl), location.y + random.nextInt(dl)); robot.waitForIdle(delay); checkDynamicShape(); // Resize location = window.getLocationOnScreen(); robot.dragAndDrop(location.x + 4, location.y + 4, location.x + random.nextInt(2*dl)-dl, location.y + random.nextInt(2*dl)-dl); robot.waitForIdle(delay); checkDynamicShape(); EventQueue.invokeAndWait(this::dispose); } void checkClick(int x, int y, int flag) throws Exception { System.out.println("Trying to click point " + x + ", " + y + ", looking for " + flag + " flag to trigger."); clicked = 0; robot.mouseMove(x, y); robot.click(); for (int i = 0; i < 100; i++) if ((clicked & (1 << flag)) == 0) robot.delay(50); else break; if ((clicked & (1 << flag)) == 0) throw new RuntimeException("FAIL: Flag " + flag + " is not triggered for point " + x + ", " + y + "!"); } }