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.widgets.Button; 40 import org.eclipse.swt.widgets.Display; 41 import org.eclipse.swt.widgets.Shell; 42 import org.jemmy.Point; 43 import org.jemmy.control.Wrap; 44 import org.jemmy.interfaces.Parent; 45 import org.jemmy.lookup.Lookup; 46 import org.jemmy.swt.ControlWrap; 47 import org.jemmy.swt.lookup.ByName; 48 import org.jemmy.swt.lookup.ByTextControlLookup; 49 import org.junit.Assert; 50 51 import org.openjdk.jmc.test.jemmy.misc.base.wrappers.MCJemmyBase; 52 import org.openjdk.jmc.test.jemmy.misc.fetchers.Fetcher; 53 54 /** 55 * The Jemmy wrapper for Buttons 56 */ 57 public class MCButton extends MCJemmyBase { 58 59 private MCButton(Wrap<? extends Button> button) { 60 this.control = button; 61 } 62 63 /** 64 * Finds a button in the default Mission Control shell and returns it. 65 * 66 * @param label 67 * the {@link MCButton} Label of the button 68 * @return a {@link MCButton} in the default shell matching the label 69 */ 70 public static MCButton getByLabel(Labels label) { 71 return getByLabel(getShell(), label); 72 } 73 74 /** 75 * Finds a button in the default Mission Control shell and returns it. 76 * 77 * @param label 78 * the {@link MCButton} Label of the button 79 * @param waitForIdle 80 * {@code true} if supposed to wait for an idle UI before trying to find the Button 81 * @return a {@link MCButton} in the default shell matching the label 82 */ 83 public static MCButton getByLabel(Labels label, boolean waitForIdle) { 84 return getByLabel(getShell(), label, waitForIdle); 85 } 86 87 /** 88 * Finds a button in the default Mission Control shell and returns it. 89 * 90 * @param label 91 * the label string of the button 92 * @return a {@link MCButton} in the default shell matching the label 93 */ 94 public static MCButton getByLabel(String label) { 95 return getByLabel(getShell(), label); 96 } 97 98 /** 99 * Finds a button by button label and returns it 100 * 101 * @param shell 102 * the shell where to find the button 103 * @param label 104 * the {@link MCButton} Label of the button 105 * @param waitForIdle 106 * {@code true} if supposed to wait for an idle UI before trying to find the Button 107 * @return a {@link MCButton} in the correct shell matching the label 108 */ 109 public static MCButton getByLabel(Wrap<? extends Shell> shell, Labels label, boolean waitForIdle) { 110 return getByLabel(shell, Labels.getButtonLabel(label), waitForIdle); 111 } 112 113 /** 114 * Finds a button by button label and returns it 115 * 116 * @param shell 117 * the shell where to find the button 118 * @param label 119 * the {@link MCButton} Label of the button 120 * @return a {@link MCButton} in the correct shell matching the label 121 */ 122 public static MCButton getByLabel(Wrap<? extends Shell> shell, Labels label) { 123 return getByLabel(shell, Labels.getButtonLabel(label)); 124 } 125 126 /** 127 * Finds a button by button label string and returns it 128 * 129 * @param shell 130 * the shell where to find the button 131 * @param label 132 * the label string of the button 133 * @return a {@link MCButton} in the correct shell matching the label 134 */ 135 public static MCButton getByLabel(Wrap<? extends Shell> shell, String label) { 136 return getByLabel(shell, label, true); 137 } 138 139 /** 140 * Finds a button by button label string and returns it 141 * 142 * @param shell 143 * the shell where to find the button 144 * @param label 145 * the label string of the button 146 * @param waitForIdle 147 * {@code true} if supposed to wait for an idle UI before trying to find the Button 148 * @return a {@link MCButton} in the correct shell matching the label 149 */ 150 @SuppressWarnings("unchecked") 151 public static MCButton getByLabel(Wrap<? extends Shell> shell, String label, boolean waitForIdle) { 152 Lookup<Button> lookup = shell.as(Parent.class, Button.class).lookup(Button.class, 153 new ByTextControlLookup<Button>(label)); 154 return new MCButton(getVisible(lookup, waitForIdle).get(0)); 155 } 156 157 /** 158 * Finds a button by button label string and returns it 159 * 160 * @param dialog 161 * the {@link MCDialog} where to find the button 162 * @param label 163 * the label string of the button 164 * @param waitForIdle 165 * {@code true} if supposed to wait for an idle UI before trying to find the Button 166 * @return a {@link MCButton} in the correct dialog matching the label 167 */ 168 public static MCButton getByLabel(MCDialog dialog, String label, boolean waitForIdle) { 169 return getByLabel(dialog.getDialogShell(), label, waitForIdle); 170 } 171 172 /** 173 * Finds a button by button label string and returns it 174 * 175 * @param dialog 176 * the {@link MCDialog} where to find the button 177 * @param label 178 * the {@link MCButton} Label of the button 179 * @param waitForIdle 180 * {@code true} if supposed to wait for an idle UI before trying to find the Button 181 * @return a {@link MCButton} in the correct dialog matching the label 182 */ 183 public static MCButton getByLabel(MCDialog dialog, Labels label, boolean waitForIdle) { 184 return getByLabel(dialog, Labels.getButtonLabel(label), waitForIdle); 185 } 186 187 /** 188 * Finds a button, visible or not, by button label string and returns it 189 * 190 * @param shell 191 * the shell where to find the button 192 * @param label 193 * the label string of the button 194 * @return a {@link MCButton} in the correct shell matching the label, {@code null} if not 195 * found 196 */ 197 @SuppressWarnings("unchecked") 198 public static MCButton getAnyByLabel(Wrap<? extends Shell> shell, String label) { 199 Lookup<Button> lookup = shell.as(Parent.class, Button.class).lookup(Button.class, 200 new ByTextControlLookup<Button>(label)); 201 if (lookup.size() > 0) { 202 return new MCButton(lookup.wrap(0)); 203 } else { 204 return null; 205 } 206 } 207 208 /** 209 * Finds a button, visible or not, by name 210 * 211 * @param shell 212 * the shell where to find the button 213 * @param name 214 * the name of the button 215 * @return a {@link MCButton} matching the name, {@code null} if not found 216 */ 217 @SuppressWarnings("unchecked") 218 public static MCButton getByName(Wrap<? extends Shell> shell, String name) { 219 return new MCButton(shell.as(Parent.class, Button.class).lookup(Button.class, new ByName<>(name)).wrap()); 220 } 221 222 /** 223 * Finds a button, visible or not, by name (in the main shell of Mission Control) 224 * 225 * @param name 226 * the name of the button 227 * @return a {@link MCButton} matching the name, {@code null} if not found 228 */ 229 public static MCButton getByName(String name) { 230 return getByName(getShell(), name); 231 } 232 233 /** 234 * Finds all visible buttons in the supplied shell and returns a {@link List} of these 235 * 236 * @param shell 237 * the shell where to search for buttons 238 * @return a {@link List} of {@link MCButton} (possibly empty) 239 */ 240 @SuppressWarnings("unchecked") 241 public static List<MCButton> getVisible(Wrap<? extends Shell> shell) { 242 List<Wrap<? extends Button>> allVisibleButtonWraps = getVisible( 243 shell.as(Parent.class, Button.class).lookup(Button.class)); 244 List<MCButton> allVisibleMcButtons = new ArrayList<>(); 245 for (Wrap<? extends Button> buttonWrap : allVisibleButtonWraps) { 246 allVisibleMcButtons.add(new MCButton(buttonWrap)); 247 } 248 return allVisibleMcButtons; 249 } 250 251 /** 252 * Finds all visible buttons in the supplied shell and returns a {@link List} of these 253 * 254 * @param shell 255 * the shell where to search for buttons 256 * @param waitForIdle 257 * {@code true} if supposed to wait for the UI to be idle before ending the lookup 258 * @return a {@link List} of {@link MCButton} (possibly empty) 259 */ 260 @SuppressWarnings("unchecked") 261 public static List<MCButton> getVisible(Wrap<? extends Shell> shell, boolean waitForIdle) { 262 List<Wrap<? extends Button>> allVisibleButtonWraps = getVisible( 263 shell.as(Parent.class, Button.class).lookup(Button.class), waitForIdle); 264 List<MCButton> allVisibleMcButtons = new ArrayList<>(); 265 for (Wrap<? extends Button> buttonWrap : allVisibleButtonWraps) { 266 allVisibleMcButtons.add(new MCButton(buttonWrap)); 267 } 268 return allVisibleMcButtons; 269 } 270 271 /** 272 * Gets the selection state of the button. 273 * 274 * @return {@code true} if selected, otherwise {@code false} 275 */ 276 public boolean getSelection() { 277 Fetcher<Boolean> fetcher = new Fetcher<Boolean>() { 278 @Override 279 public void run() { 280 setOutput(getWrap().getControl().getSelection()); 281 } 282 }; 283 Display.getDefault().syncExec(fetcher); 284 return fetcher.getOutput(); 285 } 286 287 /** 288 * Sets the state of the button/checkbox with retries in case it is a checkbox that may be grey. 289 * Sets the click point very close to the origin of the button instead of centered in order to 290 * ensure that Mac OS X will work as well 291 * 292 * @param state 293 * the desired state of the button/checkbox 294 */ 295 public void setState(boolean state) { 296 int maxRetries = 10; 297 int currentRetry = 0; 298 while (getSelection() != state && maxRetries > currentRetry) { 299 currentRetry++; 300 control.mouse().click(1, new Point(1, 1)); 301 sleep(200); 302 } 303 Assert.assertTrue("Unable to set Button state to " + state, getSelection() == state); 304 } 305 306 public static enum Labels { 307 OK, FINISH, CANCEL, CLOSE, YES, NEXT, NO, APPLY_AND_CLOSE; 308 309 public static String getButtonLabel(Labels buttonLabel) { 310 String labelString = ""; 311 312 switch (buttonLabel) { 313 case YES: 314 labelString = IDialogConstants.YES_LABEL; 315 break; 316 case CANCEL: 317 labelString = IDialogConstants.CANCEL_LABEL; 318 break; 319 case CLOSE: 320 labelString = IDialogConstants.CLOSE_LABEL; 321 break; 322 case FINISH: 323 labelString = IDialogConstants.FINISH_LABEL; 324 break; 325 case NEXT: 326 labelString = IDialogConstants.NEXT_LABEL; 327 break; 328 case OK: 329 labelString = IDialogConstants.OK_LABEL; 330 break; 331 case NO: 332 labelString = IDialogConstants.NO_LABEL; 333 break; 334 case APPLY_AND_CLOSE: 335 labelString = "Apply and Close"; 336 } 337 return labelString; 338 } 339 } 340 341 @SuppressWarnings("unchecked") 342 private Wrap<? extends Button> getWrap() { 343 return control.as(ControlWrap.class); 344 } 345 }