1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * The contents of this file are subject to the terms of either the Universal Permissive License 7 * v 1.0 as shown at http://oss.oracle.com/licenses/upl 8 * 9 * or the following license: 10 * 11 * Redistribution and use in source and binary forms, with or without modification, are permitted 12 * provided that the following conditions are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions 15 * and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 18 * conditions and the following disclaimer in the documentation and/or other materials provided with 19 * the distribution. 20 * 21 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 22 * endorse or promote products derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 26 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 31 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 package org.openjdk.jmc.test.jemmy.misc.wrappers; 34 35 import java.util.ArrayList; 36 import java.util.List; 37 38 import org.eclipse.jface.dialogs.IDialogConstants; 39 import org.eclipse.swt.graphics.Image; 40 import org.eclipse.swt.widgets.Button; 41 import org.eclipse.swt.widgets.Display; 42 import org.eclipse.swt.widgets.Shell; 43 import org.jemmy.Point; 44 import org.jemmy.control.Wrap; 45 import org.jemmy.interfaces.Parent; 46 import org.jemmy.lookup.Lookup; 47 import org.jemmy.swt.ControlWrap; 48 import org.jemmy.swt.lookup.ByName; 49 import org.jemmy.swt.lookup.ByTextControlLookup; 50 import org.junit.Assert; 51 52 import org.openjdk.jmc.test.jemmy.misc.base.wrappers.MCJemmyBase; 53 import org.openjdk.jmc.test.jemmy.misc.fetchers.Fetcher; 54 55 /** 56 * The Jemmy wrapper for Buttons 57 */ 58 public class MCButton extends MCJemmyBase { 59 60 private MCButton(Wrap<? extends Button> button) { 61 this.control = button; 62 } 63 64 /** 65 * Finds a button in the supplied shell by image and returns it. 66 * 67 * @param shell 68 * the shell where to search for the button 69 * @param image 70 * the image to look up the button with 71 * @return a {@link MCButton} (possibly null) 72 */ 73 @SuppressWarnings("unchecked") 74 public static MCButton getByImage(Wrap<? extends Shell> shell, Image image) { 75 List<Wrap<? extends Button>> allVisibleButtonWraps = getVisible( 76 shell.as(Parent.class, Button.class).lookup(Button.class)); 77 for (final Wrap<? extends Button> buttonWrap : allVisibleButtonWraps) { 78 Fetcher<Image> fetcher = new Fetcher<Image>() { 79 @Override 80 public void run() { 81 setOutput(buttonWrap.getControl().getImage()); 82 } 83 }; 84 Display.getDefault().syncExec(fetcher); 85 if (image.equals(fetcher.getOutput())) { 86 return new MCButton(buttonWrap); 87 } 88 } 89 return null; 90 } 91 92 /** 93 * Finds a button in the default Mission Control shell and returns it. 94 * 95 * @param image 96 * the image of the button 97 * @return a {@link MCButton} in the default shell matching the image. 98 */ 99 public static MCButton getByImage(Image image) { 100 return getByImage(getShell(), image); 101 } 102 103 /** 104 * Finds a button in the default Mission Control shell and returns it. 105 * 106 * @param label 107 * the {@link MCButton} Label of the button 108 * @return a {@link MCButton} in the default shell matching the label 109 */ 110 public static MCButton getByLabel(Labels label) { 111 return getByLabel(getShell(), label); 112 } 113 114 /** 115 * Finds a button in the default Mission Control shell and returns it. 116 * 117 * @param label 118 * the {@link MCButton} Label of the button 119 * @param waitForIdle 120 * {@code true} if supposed to wait for an idle UI before trying to find the Button 121 * @return a {@link MCButton} in the default shell matching the label 122 */ 123 public static MCButton getByLabel(Labels label, boolean waitForIdle) { 124 return getByLabel(getShell(), label, waitForIdle); 125 } 126 127 /** 128 * Finds a button in the default Mission Control shell and returns it. 129 * 130 * @param label 131 * the label string of the button 132 * @return a {@link MCButton} in the default shell matching the label 133 */ 134 public static MCButton getByLabel(String label) { 135 return getByLabel(getShell(), label); 136 } 137 138 /** 139 * Finds a button in a shell with the given text and returns it. 140 * 141 * @param label 142 * the label string of the button 143 * @param shellText 144 * the text to look up the shell that the button is contained in 145 * @return a {@link MCButton} in the shell matching the label 146 */ 147 public static MCButton getByLabel(String shellText, String label) { 148 return getByLabel(getShellByText(shellText), label); 149 } 150 151 /** 152 * Finds a button by button label and returns it 153 * 154 * @param shell 155 * the shell where to find the button 156 * @param label 157 * the {@link MCButton} Label of the button 158 * @param waitForIdle 159 * {@code true} if supposed to wait for an idle UI before trying to find the Button 160 * @return a {@link MCButton} in the correct shell matching the label 161 */ 162 public static MCButton getByLabel(Wrap<? extends Shell> shell, Labels label, boolean waitForIdle) { 163 return getByLabel(shell, Labels.getButtonLabel(label), waitForIdle); 164 } 165 166 /** 167 * Finds a button by button label and returns it 168 * 169 * @param shell 170 * the shell where to find the button 171 * @param label 172 * the {@link MCButton} Label of the button 173 * @return a {@link MCButton} in the correct shell matching the label 174 */ 175 public static MCButton getByLabel(Wrap<? extends Shell> shell, Labels label) { 176 return getByLabel(shell, Labels.getButtonLabel(label)); 177 } 178 179 /** 180 * Finds a button by button label string and returns it 181 * 182 * @param shell 183 * the shell where to find the button 184 * @param label 185 * the label string of the button 186 * @return a {@link MCButton} in the correct shell matching the label 187 */ 188 public static MCButton getByLabel(Wrap<? extends Shell> shell, String label) { 189 return getByLabel(shell, label, true); 190 } 191 192 /** 193 * Finds a button by button label string and returns it 194 * 195 * @param shell 196 * the shell where to find the button 197 * @param label 198 * the label string of the button 199 * @param waitForIdle 200 * {@code true} if supposed to wait for an idle UI before trying to find the Button 201 * @return a {@link MCButton} in the correct shell matching the label 202 */ 203 @SuppressWarnings("unchecked") 204 public static MCButton getByLabel(Wrap<? extends Shell> shell, String label, boolean waitForIdle) { 205 Lookup<Button> lookup = shell.as(Parent.class, Button.class).lookup(Button.class, 206 new ByTextControlLookup<Button>(label)); 207 return new MCButton(getVisible(lookup, waitForIdle).get(0)); 208 } 209 210 /** 211 * Finds a button by button label string and returns it 212 * 213 * @param dialog 214 * the {@link MCDialog} where to find the button 215 * @param label 216 * the label string of the button 217 * @param waitForIdle 218 * {@code true} if supposed to wait for an idle UI before trying to find the Button 219 * @return a {@link MCButton} in the correct dialog matching the label 220 */ 221 public static MCButton getByLabel(MCDialog dialog, String label, boolean waitForIdle) { 222 return getByLabel(dialog.getDialogShell(), label, waitForIdle); 223 } 224 225 /** 226 * Finds a button by button label string and returns it 227 * 228 * @param dialog 229 * the {@link MCDialog} where to find the button 230 * @param label 231 * the {@link MCButton} Label of the button 232 * @param waitForIdle 233 * {@code true} if supposed to wait for an idle UI before trying to find the Button 234 * @return a {@link MCButton} in the correct dialog matching the label 235 */ 236 public static MCButton getByLabel(MCDialog dialog, Labels label, boolean waitForIdle) { 237 return getByLabel(dialog, Labels.getButtonLabel(label), waitForIdle); 238 } 239 240 /** 241 * Finds a button, visible or not, by button label string and returns it 242 * 243 * @param shell 244 * the shell where to find the button 245 * @param label 246 * the label string of the button 247 * @return a {@link MCButton} in the correct shell matching the label, {@code null} if not 248 * found 249 */ 250 @SuppressWarnings("unchecked") 251 public static MCButton getAnyByLabel(Wrap<? extends Shell> shell, String label) { 252 Lookup<Button> lookup = shell.as(Parent.class, Button.class).lookup(Button.class, 253 new ByTextControlLookup<Button>(label)); 254 if (lookup.size() > 0) { 255 return new MCButton(lookup.wrap(0)); 256 } else { 257 return null; 258 } 259 } 260 261 /** 262 * Finds a button, visible or not, by name 263 * 264 * @param shell 265 * the shell where to find the button 266 * @param name 267 * the name of the button 268 * @return a {@link MCButton} matching the name, {@code null} if not found 269 */ 270 @SuppressWarnings("unchecked") 271 public static MCButton getByName(Wrap<? extends Shell> shell, String name) { 272 return new MCButton(shell.as(Parent.class, Button.class).lookup(Button.class, new ByName<>(name)).wrap()); 273 } 274 275 /** 276 * Finds a button, visible or not, by name (in the main shell of Mission Control) 277 * 278 * @param name 279 * the name of the button 280 * @return a {@link MCButton} matching the name, {@code null} if not found 281 */ 282 public static MCButton getByName(String name) { 283 return getByName(getShell(), name); 284 } 285 286 /** 287 * Finds all visible buttons in the supplied shell and returns a {@link List} of these 288 * 289 * @param shell 290 * the shell where to search for buttons 291 * @return a {@link List} of {@link MCButton} (possibly empty) 292 */ 293 @SuppressWarnings("unchecked") 294 public static List<MCButton> getVisible(Wrap<? extends Shell> shell) { 295 List<Wrap<? extends Button>> allVisibleButtonWraps = getVisible( 296 shell.as(Parent.class, Button.class).lookup(Button.class)); 297 List<MCButton> allVisibleMcButtons = new ArrayList<>(); 298 for (Wrap<? extends Button> buttonWrap : allVisibleButtonWraps) { 299 allVisibleMcButtons.add(new MCButton(buttonWrap)); 300 } 301 return allVisibleMcButtons; 302 } 303 304 /** 305 * Finds all visible buttons in the supplied shell and returns a {@link List} of these 306 * 307 * @param shell 308 * the shell where to search for buttons 309 * @param waitForIdle 310 * {@code true} if supposed to wait for the UI to be idle before ending the lookup 311 * @return a {@link List} of {@link MCButton} (possibly empty) 312 */ 313 @SuppressWarnings("unchecked") 314 public static List<MCButton> getVisible(Wrap<? extends Shell> shell, boolean waitForIdle) { 315 List<Wrap<? extends Button>> allVisibleButtonWraps = getVisible( 316 shell.as(Parent.class, Button.class).lookup(Button.class), waitForIdle); 317 List<MCButton> allVisibleMcButtons = new ArrayList<>(); 318 for (Wrap<? extends Button> buttonWrap : allVisibleButtonWraps) { 319 allVisibleMcButtons.add(new MCButton(buttonWrap)); 320 } 321 return allVisibleMcButtons; 322 } 323 324 /** 325 * Gets the selection state of the button. 326 * 327 * @return {@code true} if selected, otherwise {@code false} 328 */ 329 public boolean getSelection() { 330 Fetcher<Boolean> fetcher = new Fetcher<Boolean>() { 331 @Override 332 public void run() { 333 setOutput(getWrap().getControl().getSelection()); 334 } 335 }; 336 Display.getDefault().syncExec(fetcher); 337 return fetcher.getOutput(); 338 } 339 340 /** 341 * Sets the state of the button/checkbox with retries in case it is a checkbox that may be grey. 342 * Sets the click point very close to the origin of the button instead of centered in order to 343 * ensure that Mac OS X will work as well 344 * 345 * @param state 346 * the desired state of the button/checkbox 347 */ 348 public void setState(boolean state) { 349 int maxRetries = 10; 350 int currentRetry = 0; 351 while (getSelection() != state && maxRetries > currentRetry) { 352 currentRetry++; 353 control.mouse().click(1, new Point(1, 1)); 354 sleep(200); 355 } 356 Assert.assertTrue("Unable to set Button state to " + state, getSelection() == state); 357 } 358 359 public static enum Labels { 360 OK, FINISH, CANCEL, CLOSE, YES, NEXT, NO, APPLY_AND_CLOSE; 361 362 public static String getButtonLabel(Labels buttonLabel) { 363 String labelString = ""; 364 365 switch (buttonLabel) { 366 case YES: 367 labelString = IDialogConstants.YES_LABEL; 368 break; 369 case CANCEL: 370 labelString = IDialogConstants.CANCEL_LABEL; 371 break; 372 case CLOSE: 373 labelString = IDialogConstants.CLOSE_LABEL; 374 break; 375 case FINISH: 376 labelString = IDialogConstants.FINISH_LABEL; 377 break; 378 case NEXT: 379 labelString = IDialogConstants.NEXT_LABEL; 380 break; 381 case OK: 382 labelString = IDialogConstants.OK_LABEL; 383 break; 384 case NO: 385 labelString = IDialogConstants.NO_LABEL; 386 break; 387 case APPLY_AND_CLOSE: 388 labelString = "Apply and Close"; 389 } 390 return labelString; 391 } 392 } 393 394 @SuppressWarnings("unchecked") 395 private Wrap<? extends Button> getWrap() { 396 return control.as(ControlWrap.class); 397 } 398 }