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 }