8253820: Save test images and dumps with timestamps from client sanity suite
Reviewed-by: serb
This commit is contained in:
parent
dff26a489d
commit
e32a4ea4ef
@ -22,22 +22,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import com.sun.swingset3.demos.button.ButtonDemo;
|
import com.sun.swingset3.demos.button.ButtonDemo;
|
||||||
import org.jemmy2ext.JemmyExt;
|
|
||||||
import org.jtregext.GuiTestListener;
|
import org.jtregext.GuiTestListener;
|
||||||
import org.netbeans.jemmy.ClassReference;
|
import org.netbeans.jemmy.ClassReference;
|
||||||
import org.netbeans.jemmy.ComponentChooser;
|
|
||||||
import org.netbeans.jemmy.image.StrictImageComparator;
|
|
||||||
import org.netbeans.jemmy.operators.JButtonOperator;
|
import org.netbeans.jemmy.operators.JButtonOperator;
|
||||||
import org.netbeans.jemmy.operators.JFrameOperator;
|
import org.netbeans.jemmy.operators.JFrameOperator;
|
||||||
import org.testng.annotations.BeforeClass;
|
|
||||||
import org.testng.annotations.Listeners;
|
import org.testng.annotations.Listeners;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Robot;
|
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
@ -65,25 +59,18 @@ import static org.jemmy2ext.JemmyExt.*;
|
|||||||
public class ButtonDemoScreenshotTest {
|
public class ButtonDemoScreenshotTest {
|
||||||
|
|
||||||
private static final int[] BUTTONS = {0, 1, 2, 3, 4, 5}; // "open browser" buttons (6, 7) open a browser, so ignore
|
private static final int[] BUTTONS = {0, 1, 2, 3, 4, 5}; // "open browser" buttons (6, 7) open a browser, so ignore
|
||||||
private static StrictImageComparator sComparator = null;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public void init() {
|
|
||||||
sComparator = new StrictImageComparator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(dataProvider = "availableLookAndFeels", dataProviderClass = TestHelpers.class)
|
@Test(dataProvider = "availableLookAndFeels", dataProviderClass = TestHelpers.class)
|
||||||
public void test(String lookAndFeel) throws Exception {
|
public void test(String lookAndFeel) throws Exception {
|
||||||
UIManager.setLookAndFeel(lookAndFeel);
|
UIManager.setLookAndFeel(lookAndFeel);
|
||||||
Robot rob = new Robot();
|
|
||||||
|
|
||||||
//capture some of the background
|
//capture some of the background
|
||||||
Dimension screeSize = Toolkit.getDefaultToolkit().getScreenSize();
|
Dimension screeSize = Toolkit.getDefaultToolkit().getScreenSize();
|
||||||
Point screenCenter = new Point(screeSize.width / 2, screeSize.height / 2);
|
Point screenCenter = new Point(screeSize.width / 2, screeSize.height / 2);
|
||||||
Rectangle center = new Rectangle(
|
Rectangle center = new Rectangle(
|
||||||
screenCenter.x - 50, screenCenter.y - 50,
|
screenCenter.x - 50, screenCenter.y - 50,
|
||||||
screenCenter.x + 50, screenCenter.y + 50);
|
100, 100);
|
||||||
BufferedImage background = rob.createScreenCapture(center);
|
BufferedImage background = getRobot().createScreenCapture(center);
|
||||||
|
|
||||||
new ClassReference(ButtonDemo.class.getCanonicalName()).startApplication();
|
new ClassReference(ButtonDemo.class.getCanonicalName()).startApplication();
|
||||||
|
|
||||||
@ -91,18 +78,18 @@ public class ButtonDemoScreenshotTest {
|
|||||||
mainFrame.waitComponentShowing(true);
|
mainFrame.waitComponentShowing(true);
|
||||||
|
|
||||||
//make sure the frame is already painted
|
//make sure the frame is already painted
|
||||||
waitChangedImage(rob, () -> rob.createScreenCapture(center),
|
waitChangedImage(() -> getRobot().createScreenCapture(center),
|
||||||
background, mainFrame.getTimeouts(), "background.png");
|
background, mainFrame.getTimeouts(), "background");
|
||||||
//make sure the frame is painted completely
|
//make sure the frame is painted completely
|
||||||
waitStillImage(rob, mainFrame, "frame.png");
|
waitStillImage(mainFrame, "frame");
|
||||||
|
|
||||||
// Check all the buttons
|
// Check all the buttons
|
||||||
for (int i : BUTTONS) {
|
for (int i : BUTTONS) {
|
||||||
checkButton(mainFrame, i, rob);
|
checkButton(mainFrame, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkButton(JFrameOperator jfo, int i, Robot rob) throws InterruptedException {
|
private void checkButton(JFrameOperator jfo, int i) throws InterruptedException {
|
||||||
JButtonOperator button = new JButtonOperator(jfo, i);
|
JButtonOperator button = new JButtonOperator(jfo, i);
|
||||||
|
|
||||||
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed
|
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed
|
||||||
@ -113,9 +100,7 @@ public class ButtonDemoScreenshotTest {
|
|||||||
button.moveMouse(button.getCenterX(), button.getCenterY());
|
button.moveMouse(button.getCenterX(), button.getCenterY());
|
||||||
|
|
||||||
BufferedImage notPressed, pressed = null;
|
BufferedImage notPressed, pressed = null;
|
||||||
notPressed = waitStillImage(rob, button, "not-pressed-" + i + ".png");
|
notPressed = waitStillImage(button, "not-pressed-" + i);
|
||||||
|
|
||||||
BufferedImage[] pressedImage = new BufferedImage[1];
|
|
||||||
|
|
||||||
button.pressMouse();
|
button.pressMouse();
|
||||||
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed
|
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed
|
||||||
@ -126,14 +111,14 @@ public class ButtonDemoScreenshotTest {
|
|||||||
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed
|
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed
|
||||||
button.getOutput().printTrace("JDK-8198920: Button press confirmed by " + System.currentTimeMillis());
|
button.getOutput().printTrace("JDK-8198920: Button press confirmed by " + System.currentTimeMillis());
|
||||||
//end of instrumentation for JDK-8198920
|
//end of instrumentation for JDK-8198920
|
||||||
waitChangedImage(rob, () -> capture(rob, button), notPressed,
|
waitChangedImage(() -> capture(button), notPressed,
|
||||||
button.getTimeouts(), "pressed-" + i + ".png");
|
button.getTimeouts(), "after-press-" + i);
|
||||||
pressed = waitStillImage(rob, button, "pressed.png");
|
pressed = waitStillImage(button, "pressed-" + i);
|
||||||
} finally {
|
} finally {
|
||||||
button.releaseMouse();
|
button.releaseMouse();
|
||||||
if(pressed != null) {
|
if(pressed != null) {
|
||||||
waitChangedImage(rob, () -> capture(rob, button), pressed,
|
waitChangedImage(() -> capture(button), pressed,
|
||||||
button.getTimeouts(), "released-" + i + ".png");
|
button.getTimeouts(), "released-" + i);
|
||||||
}
|
}
|
||||||
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed
|
//additional instrumentation for JDK-8198920. To be removed after the bug is fixed
|
||||||
button.getOutput().printTrace("JDK-8198920: Button released at " + System.currentTimeMillis());
|
button.getOutput().printTrace("JDK-8198920: Button released at " + System.currentTimeMillis());
|
||||||
|
@ -149,7 +149,7 @@ public class EditorPaneDemoTest {
|
|||||||
final int xGap = 100, yGap = 40, columns = 2, rows = 5;
|
final int xGap = 100, yGap = 40, columns = 2, rows = 5;
|
||||||
editorPaneOperator.waitState(comp -> {
|
editorPaneOperator.waitState(comp -> {
|
||||||
BufferedImage capturedImage = ImageTool.getImage(imageRect);
|
BufferedImage capturedImage = ImageTool.getImage(imageRect);
|
||||||
save(capturedImage, "editor.png");
|
save(capturedImage, "editor");
|
||||||
assertFalse(isBlack(capturedImage), "image blackness");
|
assertFalse(isBlack(capturedImage), "image blackness");
|
||||||
int x = 0, y = 0, i = 0, j;
|
int x = 0, y = 0, i = 0, j;
|
||||||
for (; i < columns; i++) {
|
for (; i < columns; i++) {
|
||||||
@ -159,8 +159,7 @@ public class EditorPaneDemoTest {
|
|||||||
y += yGap;
|
y += yGap;
|
||||||
if(capturedImage.getRGB(x, y) == Color.WHITE.getRGB()) {
|
if(capturedImage.getRGB(x, y) == Color.WHITE.getRGB()) {
|
||||||
// saving image for failure case
|
// saving image for failure case
|
||||||
JemmyExt.save(capturedImage, "capturedimage_" + pageName + "_" +
|
save(capturedImage, "capturedimage-" + pageName);
|
||||||
UIManager.getLookAndFeel().getClass().getSimpleName() + ".png");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.jemmy2ext;
|
package org.jemmy2ext;
|
||||||
|
|
||||||
|
import java.awt.AWTException;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.Robot;
|
import java.awt.Robot;
|
||||||
|
import java.awt.Toolkit;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
@ -36,8 +38,11 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@ -83,6 +88,19 @@ import static org.testng.AssertJUnit.*;
|
|||||||
*/
|
*/
|
||||||
public class JemmyExt {
|
public class JemmyExt {
|
||||||
|
|
||||||
|
private static Robot robot = null;
|
||||||
|
|
||||||
|
public static Robot getRobot() {
|
||||||
|
try {
|
||||||
|
if(robot == null) {
|
||||||
|
robot = new Robot();
|
||||||
|
}
|
||||||
|
return robot;
|
||||||
|
} catch (AWTException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Statically referencing all the classes that are needed by tests so that
|
* Statically referencing all the classes that are needed by tests so that
|
||||||
* they're compiled by jtreg
|
* they're compiled by jtreg
|
||||||
@ -151,78 +169,62 @@ public class JemmyExt {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertEquals(String string, StrictImageComparator comparator, BufferedImage expected, BufferedImage actual) {
|
private static final DateFormat timestampFormat = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||||
try {
|
private static String timeStamp() {
|
||||||
assertTrue(string, comparator.compare(expected, actual));
|
return timestampFormat.format(new Date());
|
||||||
} catch (Error err) {
|
|
||||||
save(expected, "expected.png");
|
|
||||||
save(actual, "actual.png");
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertNotEquals(String string, StrictImageComparator comparator, BufferedImage notExpected, BufferedImage actual) {
|
/**
|
||||||
try {
|
* Constructs filename with a timestamp.
|
||||||
assertFalse(string, comparator.compare(notExpected, actual));
|
* @param name File name or a path without the extension
|
||||||
} catch (Error err) {
|
* @param extension File extension (without the dot). Could be null,
|
||||||
save(notExpected, "notExpected.png");
|
* in which case timestamp is simply added to the filename (no trailing dot).
|
||||||
save(actual, "actual.png");
|
* @return file name
|
||||||
throw err;
|
*/
|
||||||
}
|
public static String timeStamp(String name, String extension) {
|
||||||
|
return name + "-" + timeStamp() +
|
||||||
|
((extension != null) ? ("." + extension) : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void save(BufferedImage image, String filename) {
|
/**
|
||||||
String filepath = filename;
|
* Saves an image into a file. Filename will be constructed from the given fileID and
|
||||||
|
* a timestamp.
|
||||||
|
* @param image
|
||||||
|
* @param fileID
|
||||||
|
*/
|
||||||
|
public static void save(BufferedImage image, String fileID) {
|
||||||
|
doSave(image, timeStamp(fileID + "-" + lafShortName(), "png"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Saves an image into a file with the provided filename
|
||||||
|
private static void doSave(BufferedImage image, String filename) {
|
||||||
try {
|
try {
|
||||||
filepath = new File(filename).getCanonicalPath();
|
String filepath = new File(filename).getCanonicalPath();
|
||||||
System.out.println("Saving screenshot to " + filepath);
|
System.out.println("Saving screenshot to " + filepath);
|
||||||
BufferedOutputStream file = new BufferedOutputStream(new FileOutputStream(filepath));
|
BufferedOutputStream file = new BufferedOutputStream(new FileOutputStream(filepath));
|
||||||
new PNGEncoder(file, PNGEncoder.COLOR_MODE).encode(image);
|
new PNGEncoder(file, PNGEncoder.COLOR_MODE).encode(image);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new RuntimeException("Failed to save image to " + filepath, ioe);
|
throw new RuntimeException("Failed to save image to " + filename, ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Waits for a screen area taken by a component to not be completely black rectangle.
|
|
||||||
* @return last (non-black) image
|
|
||||||
* @throws TimeoutExpiredException if the waiting is unsuccessful
|
|
||||||
*/
|
|
||||||
public static BufferedImage waitNotBlack(Robot rob, ComponentOperator operator, String imageName) {
|
|
||||||
class NonBlackImageChooser implements ComponentChooser {
|
|
||||||
private BufferedImage image = null;
|
|
||||||
@Override
|
|
||||||
public boolean checkComponent(Component comp) {
|
|
||||||
image = capture(rob, operator);
|
|
||||||
save(image, imageName);
|
|
||||||
return !isBlack(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "A non-black Image of " + operator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NonBlackImageChooser chooser = new NonBlackImageChooser();
|
|
||||||
operator.waitState(chooser);
|
|
||||||
return chooser.image;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for the displayed image to be still.
|
* Waits for the displayed image to be still.
|
||||||
|
* @param imageID an image ID with no extension. Timestamp and LAF information is added to the ID when saving.
|
||||||
* @return last still image
|
* @return last still image
|
||||||
* @throws TimeoutExpiredException if the waiting is unsuccessful
|
* @throws TimeoutExpiredException if the waiting is unsuccessful
|
||||||
*/
|
*/
|
||||||
public static BufferedImage waitStillImage(Robot rob, ComponentOperator operator, String imageName) {
|
public static BufferedImage waitStillImage(ComponentOperator operator, String imageID) {
|
||||||
operator.getTimeouts().setTimeout("Waiter.TimeDelta", 1000);
|
operator.getTimeouts().setTimeout("Waiter.TimeDelta", 1000);
|
||||||
|
String timestampName = timeStamp(imageID + "-" + lafShortName(), "png");
|
||||||
class StillImageChooser implements ComponentChooser {
|
class StillImageChooser implements ComponentChooser {
|
||||||
private BufferedImage previousImage = null;
|
private BufferedImage previousImage = null;
|
||||||
private final StrictImageComparator sComparator = new StrictImageComparator();
|
private final StrictImageComparator sComparator = new StrictImageComparator();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkComponent(Component comp) {
|
public boolean checkComponent(Component comp) {
|
||||||
BufferedImage currentImage = capture(rob, operator);
|
BufferedImage currentImage = capture(operator);
|
||||||
save(currentImage, imageName);
|
doSave(currentImage, timestampName);
|
||||||
boolean compareResult = previousImage == null ? false : sComparator.compare(currentImage, previousImage);
|
boolean compareResult = previousImage == null ? false : sComparator.compare(currentImage, previousImage);
|
||||||
previousImage = currentImage;
|
previousImage = currentImage;
|
||||||
return compareResult;
|
return compareResult;
|
||||||
@ -241,22 +243,23 @@ public class JemmyExt {
|
|||||||
/**
|
/**
|
||||||
* Waits for the displayed image to change.
|
* Waits for the displayed image to change.
|
||||||
* @param reference image to compare to
|
* @param reference image to compare to
|
||||||
|
* @param imageID an image ID with no extension. Timestamp and LAF information is added to the ID when saving.
|
||||||
* @return last (changed) image
|
* @return last (changed) image
|
||||||
* @throws TimeoutExpiredException if the waiting is unsuccessful
|
* @throws TimeoutExpiredException if the waiting is unsuccessful
|
||||||
*/
|
*/
|
||||||
public static BufferedImage waitChangedImage(Robot rob,
|
public static BufferedImage waitChangedImage(Supplier<BufferedImage> supplier,
|
||||||
Supplier<BufferedImage> supplier,
|
|
||||||
BufferedImage reference,
|
BufferedImage reference,
|
||||||
Timeouts timeouts,
|
Timeouts timeouts,
|
||||||
String imageName) throws InterruptedException {
|
String imageID) throws InterruptedException {
|
||||||
ImageComparator comparator = new StrictImageComparator();
|
ImageComparator comparator = new StrictImageComparator();
|
||||||
|
String timestampName = timeStamp(imageID + "-" + lafShortName(), "png");
|
||||||
class ImageWaitable implements Waitable {
|
class ImageWaitable implements Waitable {
|
||||||
BufferedImage image;
|
BufferedImage image;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object actionProduced(Object obj) {
|
public Object actionProduced(Object obj) {
|
||||||
image = supplier.get();
|
image = supplier.get();
|
||||||
save(image, imageName);
|
doSave(image, timestampName);
|
||||||
return comparator.compare(reference, image) ? null : image;
|
return comparator.compare(reference, image) ? null : image;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,10 +319,10 @@ public class JemmyExt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BufferedImage capture(Robot rob, ComponentOperator operator) {
|
public static BufferedImage capture(ComponentOperator operator) {
|
||||||
Rectangle boundary = new Rectangle(operator.getLocationOnScreen(),
|
Rectangle boundary = new Rectangle(operator.getLocationOnScreen(),
|
||||||
operator.getSize());
|
operator.getSize());
|
||||||
return rob.createScreenCapture(boundary);
|
return getRobot().createScreenCapture(boundary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -400,26 +403,26 @@ public class JemmyExt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String lafShortName() { return UIManager.getLookAndFeel().getClass().getSimpleName(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trying to capture as much information as possible. Currently it includes
|
* Trying to capture as much information as possible. Currently it includes
|
||||||
* full dump and a screenshot of the whole screen.
|
* full dump and a screenshot of the whole screen.
|
||||||
*/
|
*/
|
||||||
public static void captureAll() {
|
public static void captureAll() {
|
||||||
String lookAndFeelClassName = UIManager.getLookAndFeel().getClass().getSimpleName();
|
save(getRobot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())), "failure");
|
||||||
PNGEncoder.captureScreen("failure_" + lookAndFeelClassName + ".png", PNGEncoder.COLOR_MODE);
|
|
||||||
try {
|
try {
|
||||||
Dumper.dumpAll("dumpAll_" + lookAndFeelClassName + ".xml");
|
Dumper.dumpAll(timeStamp("dumpAll-" + lafShortName(), "xml"));
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
Logger.getLogger(JemmyExt.class.getName()).log(Level.SEVERE, null, ex);
|
Logger.getLogger(JemmyExt.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
}
|
}
|
||||||
captureWindows(lookAndFeelClassName);
|
captureWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Captures each showing window image using Window.paint() method.
|
* Captures each showing window image using Window.paint() method.
|
||||||
* @param lookAndFeelClassName
|
|
||||||
*/
|
*/
|
||||||
private static void captureWindows(String lookAndFeelClassName) {
|
private static void captureWindows() {
|
||||||
try {
|
try {
|
||||||
EventQueue.invokeAndWait(() -> {
|
EventQueue.invokeAndWait(() -> {
|
||||||
Window[] windows = Window.getWindows();
|
Window[] windows = Window.getWindows();
|
||||||
@ -434,10 +437,14 @@ public class JemmyExt {
|
|||||||
g.dispose();
|
g.dispose();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ImageIO.write(img, "png", new File("window_" + lookAndFeelClassName
|
save(img, "window-" + index++);
|
||||||
+ "_" + index++ + ".png"));
|
} catch (RuntimeException e) {
|
||||||
} catch (IOException e) {
|
if (e.getCause() instanceof IOException) {
|
||||||
e.printStackTrace();
|
System.err.println("Failed to save screen images");
|
||||||
|
e.printStackTrace();
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user