1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation. Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package org.netbeans.jemmy.operators;
  26 
  27 import java.awt.Component;
  28 import java.awt.Window;
  29 import java.util.ArrayList;
  30 import java.util.Arrays;
  31 import java.util.Hashtable;
  32 import java.util.List;
  33 
  34 import javax.swing.JComponent;
  35 import javax.swing.JToolTip;
  36 import javax.swing.plaf.ToolTipUI;
  37 
  38 import org.netbeans.jemmy.ComponentChooser;
  39 import org.netbeans.jemmy.ComponentSearcher;
  40 import org.netbeans.jemmy.JemmyException;
  41 import org.netbeans.jemmy.TimeoutExpiredException;
  42 import org.netbeans.jemmy.Timeouts;
  43 import org.netbeans.jemmy.Waitable;
  44 import org.netbeans.jemmy.Waiter;
  45 
  46 /**
  47  * <BR>
  48  * <BR>
  49  * Timeouts used: <BR>
  50  * {@code ComponentOperator.WaitComponentTimeout} - time to wait component
  51  * displayed.<BR>
  52  * {@code ComponentOperator.WaitStateTimeout} - time to wait for tip text. <BR>
  53  *
  54  * @see org.netbeans.jemmy.Timeouts
  55  */
  56 public class JToolTipOperator extends JComponentOperator {
  57 
  58     private static long WAIT_TOOLTIP_TIMEOUT = 60000;
  59 
  60     /**
  61      * Identifier for a "tip text" property.
  62      *
  63      * @see #getDump()
  64      */
  65     public static final String TIP_TEXT_DPROP = "TipText";
  66 
  67     static {
  68         Timeouts.initDefault("JToolTipOperator.WaitToolTipTimeout", WAIT_TOOLTIP_TIMEOUT);
  69     }
  70     /**
  71      * Constructs a JToolTipOperator object, waiting for a shown
  72      * JToolTip.
  73      */
  74     public JToolTipOperator() {
  75         this(TRUE_CHOOSER);
  76     }
  77 
  78     /**
  79      * Constructs a JToolTipOperator object for a given JToolTip component.
  80      *
  81      * @param toolTip
  82      *            a component
  83      */
  84     public JToolTipOperator(JToolTip toolTip) {
  85         super(toolTip);
  86     }
  87 
  88     /**
  89      * Constructs a JToolTipOperator object waiting for the JToolTip having a
  90      * given tip text (compared using default string comparator).
  91      *
  92      * @param tipText
  93      *            tip text.
  94      * @see #getDefaultStringComparator()
  95      */
  96     public JToolTipOperator(String tipText) {
  97         this(waitJToolTip(new JToolTipByTipTextFinder(tipText,
  98                 getDefaultStringComparator())));
  99     }
 100 
 101     /**
 102      * Constructs a JToolTipOperator object waiting for the JToolTip
 103      * associated with the given component. Uses {@code comp}'s timeout and
 104      * output for waiting. Copies environment from {@code comp}.
 105      *
 106      * @param comp
 107      *            component on which tool tip associated
 108      * @see #copyEnvironment(org.netbeans.jemmy.operators.Operator)
 109      */
 110     public JToolTipOperator(ComponentOperator comp) {
 111         this(comp, TRUE_CHOOSER);
 112     }
 113 
 114     /**
 115      * Constructs a JToolTipOperator object waiting for the JToolTip
 116      * conforming to the given component chooser.
 117      *
 118      * @param chooser
 119      *            a component chooser specifying searching criteria.
 120      */
 121     public JToolTipOperator(ComponentChooser chooser) {
 122         this(null, chooser);
 123     }
 124 
 125     /**
 126      * Constructs a JToolTipOperator object waiting for the JToolTip
 127      * associated with the given component and conforming to the given
 128      * component chooser. Uses {@code comp}'s timeout and output for waiting.
 129      * Copies environment from {@code comp}.
 130      *
 131      * @param comp
 132      *            component on which tool tip associated
 133      * @param chooser
 134      *            a component chooser specifying searching criteria.
 135      * @see #copyEnvironment(org.netbeans.jemmy.operators.Operator)
 136      */
 137     public JToolTipOperator(ComponentOperator comp, ComponentChooser chooser) {
 138         this(waitJToolTip(comp, chooser));
 139         if(comp != null) {
 140             copyEnvironment(comp);
 141         }
 142     }
 143 
 144     /**
 145      * Constructs a JToolTipOperator object waiting for the JToolTip
 146      * associated with the given component and having the given tip text.
 147      * Uses {@code comp}'s string comparator for tip text comparison, timeout
 148      * and output for waiting. Copies environment from {@code comp}.
 149      *
 150      * @param comp
 151      *            component on which tool tip associated
 152      * @param tipText
 153      *            tip text
 154      * @see #getComparator()
 155      * @see #copyEnvironment(org.netbeans.jemmy.operators.Operator)
 156      */
 157     public JToolTipOperator(ComponentOperator comp, String tipText) {
 158         this(waitJToolTip(comp,
 159                 new JToolTipByTipTextFinder(tipText, comp.getComparator())));
 160         copyEnvironment(comp);
 161     }
 162 
 163     /**
 164      * Searches for the JToolTip associated with the given component and
 165      * conforming to the given component chooser. Uses {@code comp}'s timeout
 166      * and output for waiting.
 167      *
 168      * @param comp
 169      *            component on which tool tip associated
 170      * @param chooser
 171      *            a component chooser specifying searching criteria.
 172      * @return JToolTip instance or null if component was not found.
 173      */
 174     public static JToolTip findJToolTip(ComponentOperator comp,
 175             ComponentChooser chooser) {
 176         List<Window> windowList;
 177         if(comp != null && comp.getWindow() != null) {
 178             windowList = new ArrayList<>(
 179                     Arrays.asList(comp.getWindow().getOwnedWindows()));
 180             windowList.add(comp.getWindow());
 181         } else {
 182             windowList = new ArrayList<>(
 183                     Arrays.asList(WindowOperator.getWindows()));
 184         }
 185         ComponentChooser toolTipChooser = new JToolTipFinder(chooser);
 186         for (Window w : windowList) {
 187             ComponentSearcher searcher = new ComponentSearcher(w);
 188             Component[] components = searcher.findComponents(toolTipChooser);
 189             if (components.length > 0) {
 190                 if(comp!= null && comp.getSource() != null) {
 191                     if(comp.getSource().equals(
 192                             ((JToolTip) components[0]).getComponent())) {
 193                         return (JToolTip) components[0];
 194                     }
 195                 } else {
 196                     return (JToolTip) components[0];
 197                 }
 198             }
 199         }
 200         return null;
 201     }
 202 
 203 
 204     /**
 205      * Searches for a JToolTip.
 206      *
 207      * @return JToolTip instance or null if component was not found.
 208      */
 209     public static JToolTip findJToolTip() {
 210         return findJToolTip(null);
 211     }
 212 
 213     /**
 214      * Searches for the JToolTip associated with the given component. Uses
 215      * {@code comp}'s timeout and output for waiting.
 216      *
 217      * @param comp
 218      *            component on which tool tip associated
 219      * @return JToolTip instance or null if component was not found.
 220      */
 221     public static JToolTip findJToolTip(ComponentOperator comp) {
 222         return findJToolTip(comp, TRUE_CHOOSER);
 223     }
 224 
 225     /**
 226      * Searches for the JToolTip associated with the given component and
 227      * looking for given tip text using specified string comparator options.
 228      * Uses {@code comp}'s timeout and output for waiting.
 229      *
 230      * @param comp
 231      *            component on which tool tip associated
 232      * @param tipText
 233      *            Tip text.
 234      * @param ce
 235      *            Compare text exactly.
 236      * @param ccs
 237      *            Compare text case sensitively.
 238      * @return JToolTip instance or null if component was not found.
 239      * @see DefaultStringComparator
 240      * @see JToolTipByTipTextFinder
 241      */
 242     public static JToolTip findJToolTip(ComponentOperator comp, String tipText,
 243             boolean ce, boolean ccs) {
 244         return findJToolTip(comp, new JToolTipByTipTextFinder(tipText,
 245                 new DefaultStringComparator(ce, ccs)));
 246     }
 247 
 248     /**
 249      * Waits for a JToolTip.
 250      *
 251      * @return JToolTip instance.
 252      * @see TimeoutExpiredException
 253      */
 254     public static JToolTip waitJToolTip() {
 255         return waitJToolTip(TRUE_CHOOSER);
 256     }
 257 
 258 
 259     /**
 260      * Waits for the first JToolTip associated with the given component.
 261      *
 262      * @param comp
 263      *            component on which tool tip associated
 264      * @return JToolTip instance.
 265      * @see TimeoutExpiredException
 266      */
 267     public static JToolTip waitJToolTip(ComponentOperator comp) {
 268         return waitJToolTip(comp, TRUE_CHOOSER);
 269     }
 270 
 271     /**
 272      * Waits for the JToolTip conforming to the given component
 273      * chooser.
 274      *
 275      * @param chooser
 276      *            a component chooser specifying searching criteria.
 277      * @return JToolTip instance.
 278      * @see TimeoutExpiredException
 279      */
 280     public static JToolTip waitJToolTip(ComponentChooser chooser) {
 281         return waitJToolTip(null, chooser);
 282     }
 283 
 284     /**
 285      * Waits for the JToolTip associated with the given component and
 286      * conforming to the specified component chooser.
 287      *
 288      * @param comp
 289      *            component on which tool tip associated
 290      * @param chooser
 291      *            a component chooser specifying searching criteria.
 292      * @return JToolTip instance.
 293      * @see TimeoutExpiredException
 294      */
 295     public static JToolTip waitJToolTip(ComponentOperator comp,
 296             ComponentChooser chooser) {
 297         Waitable<JToolTip, Void> waitable = new Waitable<JToolTip, Void>() {
 298             @Override
 299             public JToolTip actionProduced(Void obj) {
 300                 return findJToolTip(comp, chooser);
 301             }
 302 
 303             @Override
 304             public String getDescription() {
 305                 return "Wait for JTooltip to be displayed for Component = "
 306                         + comp + ", " + "chooser = " + chooser;
 307             }
 308 
 309             @Override
 310             public String toString() {
 311                 return "JToolTipOperator.waitJToolTip.Waitable{description = "
 312                         + getDescription() + '}';
 313             }
 314         };
 315         Waiter<JToolTip, Void> stateWaiter = new Waiter<>(waitable);
 316         stateWaiter.setTimeoutsToCloneOf(Operator.getEnvironmentOperator().
 317                 getTimeouts(), "JToolTipOperator.WaitToolTipTimeout");
 318         stateWaiter.setOutput(Operator.getEnvironmentOperator().
 319                 getOutput().createErrorOutput());
 320         try {
 321             return stateWaiter.waitAction(null);
 322         } catch (InterruptedException e) {
 323            Thread.currentThread().interrupt();
 324            throw (new JemmyException("Waiting of " + waitable.getDescription()
 325                + " state has been interrupted!"));
 326         }
 327     }
 328 
 329     /**
 330      * Waits for the JToolTip associated with the given component and having
 331      * the given tip text compared using given string comparator options.
 332      *
 333      * @param comp
 334      *            component on which tool tip associated
 335      * @param tipText
 336      *            Tip text.
 337      * @param ce
 338      *            Compare text exactly.
 339      * @param ccs
 340      *            Compare text case sensitively.
 341      * @return JToolTip instance.
 342      * @see TimeoutExpiredException
 343      */
 344     public static JToolTip waitJToolTip(ComponentOperator comp, String tipText,
 345             boolean ce, boolean ccs) {
 346         return waitJToolTip(comp, new JToolTipByTipTextFinder(tipText,
 347                 new DefaultStringComparator(ce, ccs)));
 348     }
 349 
 350     /**
 351      * Waits for the given tip text. Uses {@linkplain #getComparator()}
 352      * comparator.
 353      *
 354      * @param tipText
 355      *            Tip text to wait for.
 356      * @see TimeoutExpiredException
 357      */
 358     public void waitTipText(String tipText) {
 359         getOutput().printLine("Wait \"" + tipText
 360                 + "\" tip text in JToolTip \n    : " + toStringSource());
 361         getOutput().printGolden("Wait \"" + tipText + "\" tip text");
 362         waitState(new JToolTipByTipTextFinder(tipText, getComparator()));
 363     }
 364 
 365     /**
 366      * Returns information about the component.
 367      *
 368      * @return Map of component properties.
 369      */
 370     @Override
 371     public Hashtable<String, Object> getDump() {
 372         Hashtable<String, Object> result = super.getDump();
 373         String tipText = getTipText();
 374         if (tipText != null) {
 375             result.put(TIP_TEXT_DPROP, tipText);
 376         } else {
 377             result.put(TIP_TEXT_DPROP, "null");
 378         }
 379         return result;
 380     }
 381 
 382     ////////////////////////////////////////////////////////
 383     // Mapping //
 384 
 385     /**
 386      * Maps {@linkplain JToolTip#getTipText()} through queue
 387      *
 388      * @return
 389      */
 390     public String getTipText() {
 391         return runMapping(new MapAction<String>("getTipText") {
 392             @Override
 393             public String map() {
 394                 return ((JToolTip) getSource()).getTipText();
 395             }
 396         });
 397     }
 398 
 399     /**
 400      * Maps {@linkplain JToolTip#getComponent()} through queue
 401      *
 402      * @return
 403      */
 404     public JComponent getComponent() {
 405         return runMapping(new MapAction<JComponent>("getComponent") {
 406             @Override
 407             public JComponent map() {
 408                 return ((JToolTip) getSource()).getComponent();
 409             }
 410         });
 411     }
 412 
 413     /**
 414      * Maps {@linkplain JToolTip#getUI()} through queue
 415      *
 416      * @return
 417      */
 418     public ToolTipUI getUI() {
 419         return runMapping(new MapAction<ToolTipUI>("getUI") {
 420             @Override
 421             public ToolTipUI map() {
 422                 return ((JToolTip) getSource()).getUI();
 423             }
 424         });
 425     }
 426 
 427     /**
 428      * Maps {@linkplain JToolTip#setTipText(String)} through queue
 429      *
 430      * @param tipText
 431      */
 432     public void setTipText(final String tipText) {
 433         runMapping(new MapVoidAction("setTipText") {
 434             @Override
 435             public void map() {
 436                 ((JToolTip) getSource()).setTipText(tipText);
 437             }
 438         });
 439     }
 440 
 441     /**
 442      * Maps {@linkplain JToolTip#setComponent(JComponent)} through queue
 443      *
 444      * @param component
 445      */
 446     public void setComponent(final JComponent component) {
 447         runMapping(new MapVoidAction("setComponent") {
 448             @Override
 449             public void map() {
 450                 ((JToolTip) getSource()).setComponent(component);
 451             }
 452         });
 453     }
 454     // End of mapping //
 455     ////////////////////////////////////////////////////////
 456 
 457 
 458     /**
 459      * Allows to find JToolTip by tip text.
 460      */
 461     public static class JToolTipByTipTextFinder implements ComponentChooser {
 462 
 463         String tipText;
 464         StringComparator comparator;
 465 
 466         /**
 467          * Constructs JToolTipByTipTextFinder.
 468          *
 469          * @param tipText
 470          *            a tip text pattern
 471          * @param comparator
 472          *            specifies string comparison algorithm.
 473          */
 474         public JToolTipByTipTextFinder(String tipText,
 475                 StringComparator comparator) {
 476             this.tipText = tipText;
 477             this.comparator = comparator;
 478         }
 479 
 480         /**
 481          * Constructs JToolTipByTipTextFinder.
 482          *
 483          * @param tipText
 484          *            a tip text pattern
 485          */
 486         public JToolTipByTipTextFinder(String tipText) {
 487             this(tipText, Operator.getDefaultStringComparator());
 488         }
 489 
 490         @Override
 491         public boolean checkComponent(Component comp) {
 492             if (comp instanceof JToolTip) {
 493                 if (((JToolTip) comp).getTipText() != null) {
 494                     return (comparator.equals(((JToolTip) comp).getTipText(),
 495                             tipText));
 496                 }
 497             }
 498             return false;
 499         }
 500 
 501         @Override
 502         public String getDescription() {
 503             return "JToolTip with tip text \"" + tipText + "\"";
 504         }
 505 
 506         @Override
 507         public String toString() {
 508             return "JToolTipByTipTextFinder{" + "tipText=" + tipText
 509                     + ", comparator=" + comparator + '}';
 510         }
 511     }
 512 
 513     /**
 514      * Allows to find JToolTips among components.
 515      */
 516     public static class JToolTipFinder extends Finder {
 517 
 518         /**
 519          * Constructs JToolTipFinder chaining another component chooser.
 520          *
 521          * @param sf
 522          *            other searching criteria.
 523          */
 524         public JToolTipFinder(ComponentChooser sf) {
 525             super(JToolTip.class, sf);
 526         }
 527 
 528         /**
 529          * Constructs JToolTipFinder.
 530          */
 531         public JToolTipFinder() {
 532             super(JToolTip.class);
 533         }
 534     }
 535 
 536     private static final ComponentChooser TRUE_CHOOSER = ComponentSearcher
 537             .getTrueChooser("Any JToolTip");
 538 }