Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java
47626 views
/*1* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.awt.*;24import java.awt.event.*;25import java.awt.peer.ComponentPeer;26import java.lang.reflect.Constructor;27import java.lang.reflect.InvocationTargetException;28import java.lang.reflect.Method;29import java.util.ArrayList;30import javax.swing.*;31import sun.awt.EmbeddedFrame;32import java.io.*;33import test.java.awt.regtesthelpers.Util;3435/**36* <p>This class provides basis for AWT Mixing testing.37* <p>It provides all standard test machinery and should be used by38* extending and overriding next methods:39* <li> {@link OverlappingTestBase#prepareControls()} - setup UI components40* <li> {@link OverlappingTestBase#performTest()} - run particular test41* Those methods would be run in the loop for each AWT component.42* <p>Current AWT component should be added to the tested UI by {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) ()}.43* There AWT components are prepared to be tested as being overlayed by other (e.g. Swing) components - they are colored to44* {@link OverlappingTestBase#AWT_BACKGROUND_COLOR} and throws failure on catching mouse event.45* <p> Validation of component being overlayed should be tested by {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) }46* See each method javadoc for more details.47*48* <p>Due to test machinery limitations all test should be run from their own main() by calling next coe49* <code>50* public static void main(String args[]) throws InterruptedException {51* instance = new YourTestInstance();52* OverlappingTestBase.doMain(args);53* }54* </code>55*56* @author Sergey Grinev57*/58public abstract class OverlappingTestBase {59// working variables60private static volatile boolean wasHWClicked = false;61private static volatile boolean passed = true;62// constants63/**64* Default color for AWT component used for validate correct drawing of overlapping. <b>Never</b> use it for lightweight components.65*/66protected static final Color AWT_BACKGROUND_COLOR = new Color(21, 244, 54);67protected static Color AWT_VERIFY_COLOR = AWT_BACKGROUND_COLOR;68protected static final int ROBOT_DELAY = 500;69private static final String[] simpleAwtControls = {"Button", "Checkbox", "Label", "TextArea"};70/**71* Generic strings array. To be used for population of List based controls.72*/73protected static final String[] petStrings = {"Bird", "Cat", "Dog", "Rabbit", "Rhynocephalia Granda", "Bear", "Tiger", "Mustang"};74// "properties"75/**76* Tests customization. Set this variable to test only control from java.awt77* <p>Usage of this variable should be marked with CR being the reason.78* <p>Do not use this variable simultaneously with {@link OverlappingTestBase#skipClassNames}79*/80protected String onlyClassName = null;81/**82* For customizing tests. List classes' simple names to skip them from testings.83* <p>Usage of this variable should be marked with CR being the reason.84*/85protected String[] skipClassNames = null;86/**87* Set to false to avoid event delivery validation88* @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)89*/90protected boolean useClickValidation = true;91/**92* Set to false if test doesn't supposed to verify EmbeddedFrame93*/94protected boolean testEmbeddedFrame = false;95/**96* Set this variable to true if testing embedded frame is impossible (on Mac, for instance, for now).97* The testEmbeddedFrame is explicitly set to true in dozen places.98*/99protected boolean skipTestingEmbeddedFrame = false;100101public static final boolean isMac = System.getProperty("os.name").toLowerCase().contains("os x");102private boolean isFrameBorderCalculated;103private int borderShift;104105{ if (Toolkit.getDefaultToolkit().getClass().getName().matches(".*L.*Toolkit")) {106// No EmbeddedFrame in LWToolkit/LWCToolkit, yet107// And it should be programmed some other way, too, in any case108System.err.println("skipTestingEmbeddedFrame");109skipTestingEmbeddedFrame = true;110}else {111System.err.println("do not skipTestingEmbeddedFrame");112}113}114115protected int frameBorderCounter() {116if (!isFrameBorderCalculated) {117try {118new FrameBorderCounter(); // force compilation by jtreg119String JAVA_HOME = System.getProperty("java.home");120Process p = Runtime.getRuntime().exec(JAVA_HOME + "/bin/java FrameBorderCounter");121try {122p.waitFor();123} catch (InterruptedException e) {124e.printStackTrace();125throw new RuntimeException(e);126}127if (p.exitValue() != 0) {128throw new RuntimeException("FrameBorderCounter exited with not null code!\n" + readInputStream(p.getErrorStream()));129}130borderShift = Integer.parseInt(readInputStream(p.getInputStream()).trim());131isFrameBorderCalculated = true;132} catch (IOException e) {133e.printStackTrace();134throw new RuntimeException("Problem calculating a native border size");135}136}137return borderShift;138}139140public void getVerifyColor() {141try {142final int size = 200;143final Point[] p = new Point[1];144SwingUtilities.invokeAndWait(new Runnable() {145public void run(){146JFrame frame = new JFrame("set back");147frame.getContentPane().setBackground(AWT_BACKGROUND_COLOR);148frame.setSize(size, size);149frame.setUndecorated(true);150frame.setVisible(true);151frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);152p[0] = frame.getLocation();153}154});155Robot robot = new Robot();156robot.waitForIdle();157Thread.sleep(ROBOT_DELAY);158AWT_VERIFY_COLOR = robot.getPixelColor(p[0].x+size/2, p[0].y+size/2);159System.out.println("Color will be compared with " + AWT_VERIFY_COLOR + " instead of " + AWT_BACKGROUND_COLOR);160} catch (Exception e) {161System.err.println("Cannot get verify color: "+e.getMessage());162}163}164165private String readInputStream(InputStream is) throws IOException {166byte[] buffer = new byte[4096];167int len = 0;168StringBuilder sb = new StringBuilder();169try (InputStreamReader isr = new InputStreamReader(is)) {170while ((len = is.read(buffer)) > 0) {171sb.append(new String(buffer, 0, len));172}173}174return sb.toString();175}176177private void setupControl(final Component control) {178if (useClickValidation) {179control.addMouseListener(new MouseAdapter() {180@Override181public void mouseClicked(MouseEvent e) {182System.err.println("ERROR: " + control.getClass() + " received mouse click.");183wasHWClicked = true;184}185});186}187control.setBackground(AWT_BACKGROUND_COLOR);188control.setForeground(AWT_BACKGROUND_COLOR);189control.setPreferredSize(new Dimension(150, 150));190control.setFocusable(false);191}192193private void addAwtControl(java.util.List<Component> container, final Component control) {194String simpleName = control.getClass().getSimpleName();195if (onlyClassName != null && !simpleName.equals(onlyClassName)) {196return;197}198if (skipClassNames != null) {199for (String skipMe : skipClassNames) {200if (simpleName.equals(skipMe)) {201return;202}203}204}205setupControl(control);206container.add(control);207}208209private void addSimpleAwtControl(java.util.List<Component> container, String className) {210try {211Class definition = Class.forName("java.awt." + className);212Constructor constructor = definition.getConstructor(new Class[]{String.class});213java.awt.Component component = (java.awt.Component) constructor.newInstance(new Object[]{"AWT Component " + className});214addAwtControl(container, component);215} catch (Exception ex) {216System.err.println(ex.getMessage());217fail("Setup error, this jdk doesn't have awt conrol " + className);218}219}220221/**222* Adds current AWT control to container223* <p>N.B.: if testEmbeddedFrame == true this method will also add EmbeddedFrame over Canvas224* and it should be called <b>after</b> Frame.setVisible(true) call225* @param container container to hold AWT component226*/227protected final void propagateAWTControls(Container container) {228if (currentAwtControl != null) {229container.add(currentAwtControl);230} else { // embedded frame231try {232233//create embedder234Canvas embedder = new Canvas();235embedder.setBackground(Color.RED);236embedder.setPreferredSize(new Dimension(150, 150));237container.add(embedder);238container.setVisible(true); // create peer239240long frameWindow = 0;241String getWindowMethodName = "getHWnd";242if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {243getWindowMethodName = "getWindow";244}245ComponentPeer peer = embedder.getPeer();246// System.err.println("Peer: " + peer);247Method getWindowMethod = peer.getClass().getMethod(getWindowMethodName);248frameWindow = (Long) getWindowMethod.invoke(peer);249// System.err.println("frame peer ID: " + frameWindow);250251String eframeClassName = "sun.awt.windows.WEmbeddedFrame";252if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {253eframeClassName = "sun.awt.X11.XEmbeddedFrame";254}255Class eframeClass = Class.forName(eframeClassName);256Constructor eframeCtor = eframeClass.getConstructor(long.class);257EmbeddedFrame eframe = (EmbeddedFrame) eframeCtor.newInstance(frameWindow);258setupControl(eframe);259eframe.setSize(new Dimension(150, 150));260eframe.setVisible(true);261// System.err.println(eframe.getSize());262} catch (Exception ex) {263ex.printStackTrace();264fail("Failed to instantiate EmbeddedFrame: " + ex.getMessage());265}266}267}268private static final Font hugeFont = new Font("Arial", Font.BOLD, 70);269270private java.util.List<Component> getAWTControls() {271java.util.List<Component> components = new ArrayList<Component>();272273for (String clazz : simpleAwtControls) {274addSimpleAwtControl(components, clazz);275}276277TextField tf = new TextField();278tf.setFont(hugeFont);279addAwtControl(components, tf);280281// more complex controls282Choice c = new Choice();283for (int i = 0; i < petStrings.length; i++) {284c.add(petStrings[i]);285}286addAwtControl(components, c);287c.setPreferredSize(null);288c.setFont(hugeFont); // to make control bigger as setPrefferedSize don't do his job here289290List l = new List(petStrings.length);291for (int i = 0; i < petStrings.length; i++) {292l.add(petStrings[i]);293}294addAwtControl(components, l);295296Canvas canvas = new Canvas();297canvas.setSize(100, 200);298addAwtControl(components, canvas);299300Scrollbar sb = new Scrollbar(Scrollbar.VERTICAL, 500, 1, 0, 500);301addAwtControl(components, sb);302303Scrollbar sb2 = new Scrollbar(Scrollbar.HORIZONTAL, 500, 1, 0, 500);304addAwtControl(components, sb2);305306return components;307}308/**309* Default shift for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) }310*/311protected static Point shift = new Point(16, 16);312313/**314* Verifies point using specified AWT Robot. Supposes <code>defaultShift == true</code> for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean) }.315* This method is used to verify controls by providing just their plain screen coordinates.316* @param robot AWT Robot. Usually created by {@link Util#createRobot() }317* @param lLoc point to verify318* @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)319*/320protected void clickAndBlink(Robot robot, Point lLoc) {321clickAndBlink(robot, lLoc, true);322}323/**324* Default failure message for color check325* @see OverlappingTestBase#performTest()326*/327protected String failMessageColorCheck = "The LW component did not pass pixel color check and is overlapped";328/**329* Default failure message event check330* @see OverlappingTestBase#performTest()331*/332protected String failMessage = "The LW component did not received the click.";333334private static boolean isValidForPixelCheck(Component component) {335if ((component instanceof java.awt.Scrollbar) || isMac && (component instanceof java.awt.Button)) {336return false;337}338return true;339}340341/**342* Preliminary validation - should be run <b>before</b> overlapping happens to ensure test is correct.343* @param robot AWT Robot. Usually created by {@link Util#createRobot() }344* @param lLoc point to validate to be <b>of</b> {@link OverlappingTestBase#AWT_BACKGROUND_COLOR}345* @param component tested component, should be pointed out as not all components are valid for pixel check.346*/347protected void pixelPreCheck(Robot robot, Point lLoc, Component component) {348if (isValidForPixelCheck(component)) {349int tries = 10;350Color c = null;351while (tries-- > 0) {352c = robot.getPixelColor(lLoc.x, lLoc.y);353System.out.println("Precheck. color: "+c+" compare with "+AWT_VERIFY_COLOR);354if (c.equals(AWT_VERIFY_COLOR)) {355return;356}357try {358Thread.sleep(100);359} catch (InterruptedException e) {360}361}362System.err.println(lLoc + ": " + c);363fail("Dropdown test setup failure, colored part of AWT component is not located at click area");364}365}366367/**368* Verifies point using specified AWT Robot.369* <p>Firstly, verifies point by color pixel check370* <p>Secondly, verifies event delivery by mouse click371* @param robot AWT Robot. Usually created by {@link Util#createRobot() }372* @param lLoc point to verify373* @param defaultShift if true verified position will be shifted by {@link OverlappingTestBase#shift }.374*/375protected void clickAndBlink(Robot robot, Point lLoc, boolean defaultShift) {376Point loc = lLoc.getLocation();377//check color378Util.waitForIdle(robot);379try{380Thread.sleep(500);381}catch(Exception exx){382exx.printStackTrace();383}384385if (defaultShift) {386loc.translate(shift.x, shift.y);387}388if (!(System.getProperty("os.name").toLowerCase().contains("os x"))) {389Color c = robot.getPixelColor(loc.x, loc.y);390System.out.println("C&B. color: "+c+" compare with "+AWT_VERIFY_COLOR);391if (c.equals(AWT_VERIFY_COLOR)) {392fail(failMessageColorCheck);393passed = false;394}395396// perform click397Util.waitForIdle(robot);398}399400robot.mouseMove(loc.x, loc.y);401402robot.mousePress(InputEvent.BUTTON1_MASK);403robot.mouseRelease(InputEvent.BUTTON1_MASK);404Util.waitForIdle(robot);405}406407/**408* This method should be overriden with code which setups UI for testing.409* Code in this method <b>will</b> be called only from AWT thread so Swing operations can be called directly.410*411* @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI412*/413protected abstract void prepareControls();414415/**416* This method should be overriden with test execution. It will <b>not</b> be called from AWT thread so all Swing operations should be treated accordingly.417* @return true if test passed. Otherwise fail with default fail message.418* @see {@link OverlappingTestBase#failMessage} default fail message419*/420protected abstract boolean performTest();421/**422* This method can be overriden with cleanup routines. It will be called from AWT thread so all Swing operations should be treated accordingly.423*/424protected void cleanup() {425// intentionally do nothing426}427/**428* Currect tested AWT Control. Usually shouldn't be accessed directly.429*430* @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI431*/432protected Component currentAwtControl;433434private void testComponent(Component component) throws InterruptedException, InvocationTargetException {435Robot robot = null;436try {437robot = new Robot();438}catch(Exception ignorex) {439}440currentAwtControl = component;441System.out.println("Testing " + currentAwtControl.getClass().getSimpleName());442SwingUtilities.invokeAndWait(new Runnable() {443public void run() {444prepareControls();445}446});447if (component != null) {448Util.waitTillShown(component);449}450Util.waitForIdle(robot);451try {452Thread.sleep(500); // wait for graphic effects on systems like Win7453} catch (InterruptedException ex) {454}455if (!instance.performTest()) {456fail(failMessage);457passed = false;458}459SwingUtilities.invokeAndWait(new Runnable() {460public void run() {461cleanup();462}463});464}465466private void testEmbeddedFrame() throws InvocationTargetException, InterruptedException {467Robot robot = null;468try {469robot = new Robot();470}catch(Exception ignorex) {471}472System.out.println("Testing EmbeddedFrame");473currentAwtControl = null;474SwingUtilities.invokeAndWait(new Runnable() {475public void run() {476prepareControls();477}478});479Util.waitForIdle(robot);480try {481Thread.sleep(500); // wait for graphic effects on systems like Win7482} catch (InterruptedException ex) {483}484if (!instance.performTest()) {485fail(failMessage);486passed = false;487}488SwingUtilities.invokeAndWait(new Runnable() {489public void run() {490cleanup();491}492});493}494495private void testAwtControls() throws InterruptedException {496try {497for (Component component : getAWTControls()) {498testComponent(component);499}500if (testEmbeddedFrame && !skipTestingEmbeddedFrame) {501testEmbeddedFrame();502}503} catch (InvocationTargetException ex) {504ex.printStackTrace();505fail(ex.getMessage());506}507}508/**509* Used by standard test machinery. See usage at {@link OverlappingTestBase }510*/511protected static OverlappingTestBase instance;512513protected OverlappingTestBase() {514getVerifyColor();515}516517/*****************************************************518* Standard Test Machinery Section519* DO NOT modify anything in this section -- it's a520* standard chunk of code which has all of the521* synchronisation necessary for the test harness.522* By keeping it the same in all tests, it is easier523* to read and understand someone else's test, as524* well as insuring that all tests behave correctly525* with the test harness.526* There is a section following this for test-527* classes528******************************************************/529private static void init() throws InterruptedException {530//*** Create instructions for the user here ***531//System.setProperty("sun.awt.disableMixing", "true");532533String[] instructions = {534"This is an AUTOMATIC test, simply wait until it is done.",535"The result (passed or failed) will be shown in the",536"message window below."537};538Sysout.createDialog();539Sysout.printInstructions(instructions);540541instance.testAwtControls();542543if (wasHWClicked) {544fail("HW component received the click.");545passed = false;546}547if (passed) {548pass();549}550}//End init()551private static boolean theTestPassed = false;552private static boolean testGeneratedInterrupt = false;553private static String failureMessage = "";554private static Thread mainThread = null;555private static int sleepTime = 300000;556557// Not sure about what happens if multiple of this test are558// instantiated in the same VM. Being static (and using559// static vars), it aint gonna work. Not worrying about560// it for now.561/**562* Starting point for test runs. See usage at {@link OverlappingTestBase }563* @param args regular main args, not used.564* @throws InterruptedException565*/566public static void doMain(String args[]) throws InterruptedException {567mainThread = Thread.currentThread();568try {569init();570} catch (TestPassedException e) {571//The test passed, so just return from main and harness will572// interepret this return as a pass573return;574}575//At this point, neither test pass nor test fail has been576// called -- either would have thrown an exception and ended the577// test, so we know we have multiple threads.578579//Test involves other threads, so sleep and wait for them to580// called pass() or fail()581try {582Thread.sleep(sleepTime);583//Timed out, so fail the test584throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds");585} catch (InterruptedException e) {586//The test harness may have interrupted the test. If so, rethrow the exception587// so that the harness gets it and deals with it.588if (!testGeneratedInterrupt) {589throw e;590}591592//reset flag in case hit this code more than once for some reason (just safety)593testGeneratedInterrupt = false;594595if (theTestPassed == false) {596throw new RuntimeException(failureMessage);597}598}599600}//main601602/**603* Test will fail if not passed after this timeout. Default timeout is 300 seconds.604* @param seconds timeout in seconds605*/606public static synchronized void setTimeoutTo(int seconds) {607sleepTime = seconds * 1000;608}609610/**611* Set test as passed. Usually shoudn't be called directly.612*/613public static synchronized void pass() {614Sysout.println("The test passed.");615Sysout.println("The test is over, hit Ctl-C to stop Java VM");616//first check if this is executing in main thread617if (mainThread == Thread.currentThread()) {618//Still in the main thread, so set the flag just for kicks,619// and throw a test passed exception which will be caught620// and end the test.621theTestPassed = true;622throw new TestPassedException();623}624theTestPassed = true;625testGeneratedInterrupt = true;626mainThread.interrupt();627}//pass()628629/**630* Fail test generic message.631*/632public static synchronized void fail() {633//test writer didn't specify why test failed, so give generic634fail("it just plain failed! :-)");635}636637/**638* Fail test providing specific reason.639* @param whyFailed reason640*/641public static synchronized void fail(String whyFailed) {642Sysout.println("The test failed: " + whyFailed);643Sysout.println("The test is over, hit Ctl-C to stop Java VM");644//check if this called from main thread645if (mainThread == Thread.currentThread()) {646//If main thread, fail now 'cause not sleeping647throw new RuntimeException(whyFailed);648}649theTestPassed = false;650testGeneratedInterrupt = true;651failureMessage = whyFailed;652mainThread.interrupt();653}//fail()654}// class LWComboBox655class TestPassedException extends RuntimeException {656}657658//*********** End Standard Test Machinery Section **********659//************ Begin classes defined for the test ****************660// if want to make listeners, here is the recommended place for them, then instantiate661// them in init()662663/* Example of a class which may be written as part of a test664class NewClass implements anInterface665{666static int newVar = 0;667668public void eventDispatched(AWTEvent e)669{670//Counting events to see if we get enough671eventCount++;672673if( eventCount == 20 )674{675//got enough events, so pass676677LWComboBox.pass();678}679else if( tries == 20 )680{681//tried too many times without getting enough events so fail682683LWComboBox.fail();684}685686}// eventDispatched()687688}// NewClass class689690*/691//************** End classes defined for the test *******************692/****************************************************693Standard Test Machinery694DO NOT modify anything below -- it's a standard695chunk of code whose purpose is to make user696interaction uniform, and thereby make it simpler697to read and understand someone else's test.698****************************************************/699/**700This is part of the standard test machinery.701It creates a dialog (with the instructions), and is the interface702for sending text messages to the user.703To print the instructions, send an array of strings to Sysout.createDialog704WithInstructions method. Put one line of instructions per array entry.705To display a message for the tester to see, simply call Sysout.println706with the string to be displayed.707This mimics System.out.println but works within the test harness as well708as standalone.709*/710class Sysout {711private static TestDialog dialog;712713public static void createDialogWithInstructions(String[] instructions) {714dialog = new TestDialog(new Frame(), "Instructions");715dialog.printInstructions(instructions);716//dialog.setVisible(true);717println("Any messages for the tester will display here.");718}719720public static void createDialog() {721dialog = new TestDialog(new Frame(), "Instructions");722String[] defInstr = {"Instructions will appear here. ", ""};723dialog.printInstructions(defInstr);724//dialog.setVisible(true);725println("Any messages for the tester will display here.");726}727728public static void printInstructions(String[] instructions) {729dialog.printInstructions(instructions);730}731732public static void println(String messageIn) {733dialog.displayMessage(messageIn);734System.out.println(messageIn);735}736}// Sysout class737738/**739This is part of the standard test machinery. It provides a place for the740test instructions to be displayed, and a place for interactive messages741to the user to be displayed.742To have the test instructions displayed, see Sysout.743To have a message to the user be displayed, see Sysout.744Do not call anything in this dialog directly.745*/746class TestDialog extends Dialog {747TextArea instructionsText;748TextArea messageText;749int maxStringLength = 80;750751//DO NOT call this directly, go through Sysout752public TestDialog(Frame frame, String name) {753super(frame, name);754int scrollBoth = TextArea.SCROLLBARS_BOTH;755instructionsText = new TextArea("", 15, maxStringLength, scrollBoth);756add("North", instructionsText);757758messageText = new TextArea("", 5, maxStringLength, scrollBoth);759add("Center", messageText);760761pack();762763//setVisible(true);764}// TestDialog()765766//DO NOT call this directly, go through Sysout767public void printInstructions(String[] instructions) {768//Clear out any current instructions769instructionsText.setText("");770771//Go down array of instruction strings772773String printStr, remainingStr;774for (int i = 0; i < instructions.length; i++) {775//chop up each into pieces maxSringLength long776remainingStr = instructions[i];777while (remainingStr.length() > 0) {778//if longer than max then chop off first max chars to print779if (remainingStr.length() >= maxStringLength) {780//Try to chop on a word boundary781int posOfSpace = remainingStr.lastIndexOf(' ', maxStringLength - 1);782783if (posOfSpace <= 0) {784posOfSpace = maxStringLength - 1;785}786787printStr = remainingStr.substring(0, posOfSpace + 1);788remainingStr = remainingStr.substring(posOfSpace + 1);789} //else just print790else {791printStr = remainingStr;792remainingStr = "";793}794795instructionsText.append(printStr + "\n");796797}// while798799}// for800801}//printInstructions()802803//DO NOT call this directly, go through Sysout804public void displayMessage(String messageIn) {805messageText.append(messageIn + "\n");806System.out.println(messageIn);807}808}// TestDialog class809810811812