All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sikuli.guide.Guide Maven / Gradle / Ivy

There is a newer version: 2.0.5
Show newest version
/*
 * Copyright (c) 2010-2018, sikuli.org, sikulix.com - MIT license
 */

package org.sikuli.guide;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

import javax.swing.JComponent;
import javax.swing.JPanel;

import org.sikuli.guide.Transition.TransitionListener;
import org.sikuli.basics.Debug;
import org.sikuli.util.EventObserver;
import org.sikuli.util.EventSubject;
import org.sikuli.script.Location;
import org.sikuli.script.Pattern;
import org.sikuli.script.Region;
import org.sikuli.script.Screen;
import org.sikuli.util.OverlayTransparentWindow;
import org.sikuli.basics.Settings;
import org.sikuli.natives.SysUtil;

public class Guide extends OverlayTransparentWindow implements EventObserver {

  static float DEFAULT_TIMEOUT = 10.0f;
  static public final int FIRST = 0;
  static public final int MIDDLE = 1;
  static public final int LAST = 2;
  static public final int SIMPLE = 4;
  final float DIMMING_OPACITY = 0.5f;

  Robot robot;
  Region _region;
  JPanel content = null;
  Transition transition;
  ArrayList transitions = new ArrayList();
  ArrayList trackers = new ArrayList();
  Transition triggeredTransition;
  ClickableWindow clickableWindow = null;
  SxBeam beam = null;

  /**
   * create a new guide overlay on whole primary screen
   */
  public Guide() {
    super(new Color(0.1f, 0f, 0f, 0.1f), null);
    super.addObserver(this);
    init(new Screen());
  }

  /**
   * create a new guide overlay on given region
   */
  public Guide(Region region) {
    super(new Color(0.1f, 0f, 0f, 0.1f), null);
    super.addObserver(this);
    init(region);
  }

  private void init(Region region) {
    try {
      robot = new Robot();
    } catch (AWTException e1) {
      e1.printStackTrace();
    }
    content = getJPanel();
    _region = region;
    Rectangle rect = _region.getRect();
    content.setPreferredSize(rect.getSize());
    add(content);
    setBounds(rect);
    getRootPane().putClientProperty("Window.shadow", Boolean.FALSE);
    ((JPanel) getContentPane()).setDoubleBuffered(true);
    setVisible(false);
    setFocusableWindowState(false);
  }

  public void focusBelow() {
    if (Settings.isMac()) {
      // TODO: replace this hack with a more robust method

      // Mac's hack to bring focus to the window directly underneath
      // this hack works on the assumption that the caller has
      // the input focus but no interaction area at the current
      // mouse cursor position
      // This hack does not work well with applications that
      // can receive mouse clicks without having the input focus
      // (e.g., finder, system preferences)
      //         robot.mousePress(InputEvent.BUTTON1_MASK);
      //         robot.mouseRelease(InputEvent.BUTTON1_MASK);

      // Another temporary hack to switch to the previous window on Mac
      robot.keyPress(KeyEvent.VK_META);
      robot.keyPress(KeyEvent.VK_TAB);
      robot.keyRelease(KeyEvent.VK_META);
      robot.keyRelease(KeyEvent.VK_TAB);

      // wait a little bit for the switch to complete
      robot.delay(1000);
    }

  }

  @Override
  public void toFront() {
    if (Settings.isMac() || Settings.isWindows()) {
      // this call is necessary to allow clicks to go through the window (ignoreMouse == true)
      if (Settings.JavaVersion < 7) {
        SysUtil.getOSUtil().bringWindowToFront(this, true);
      } else {
      }
    }
    super.toFront();
  }

  @Override
  public void update(EventSubject es) {
    //TODO transparent paint
  }

  public String showNow(float secs) {
    transitions.add(new TimeoutTransition((int) secs * 1000));
    return showNow();
  }

  public String showNow() {
    String cmd = "Next";
    if (content.getComponentCount() == 0
            && transitions.isEmpty()) {
      //&& search == null) {
      return cmd;
    }
    startAnimation();
    startTracking();
    setVisible(true);
    toFront();

    //
    /*    if (search != null) {
     * search.setVisible(true);
     * search.requestFocus();
     * synchronized (this) {
     * try {
     * wait();
     * } catch (InterruptedException e) {
     * e.printStackTrace();
     * }
     * }
     * search.dispose();
     * search.setVisible(false);
     * String key = search.getSelectedKey();
     * search = null;
     * reset();
     * focusBelow();
     * return key;
     * }*/    //

    if (transitions.isEmpty()) {
      // if no transition is added, use the default timeout transition
      transitions.add(new TimeoutTransition((int) DEFAULT_TIMEOUT * 1000));
    }
    final Object token = new Object();
    synchronized (token) {
      for (Transition transition : transitions) {
        transition.waitForTransition(new TransitionListener() {
          @Override
          public void transitionOccurred(Object source) {
            triggeredTransition = (Transition) source;
            synchronized (token) {
              token.notify();
            }
          }
        });
      }
      try {
        token.wait();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    if (triggeredTransition instanceof ClickableWindow) {
      ClickableWindow cw = (ClickableWindow) triggeredTransition;
//TODO click through if not button
      cmd = cw.getLastClicked().getName();
    } else if (triggeredTransition instanceof TimeoutTransition) {
      cmd = "timeout";
    }
    reset();
    return cmd;
  }

  public void addToFront(JComponent comp) {
    addComponent(comp);
  }

  public void addComponent(JComponent comp) {
    content.add(comp, 0);
  }

  public void addToFront(Visual comp) {
    addComponent(comp, 0);
  }

  public void addComponent(Visual comp, int index) {
    if (comp instanceof SxClickable) {
      // add to the guide window
      content.add(comp, 0);
      if (clickableWindow == null) {
        clickableWindow = new ClickableWindow(this);
        addWindowListener(new WindowAdapter() {
          @Override
          public void windowClosed(WindowEvent e) {
            //Debug.info("[Guide] window closed");
            GlobalMouseMotionTracker.getInstance().stop();
          }
        });
      }
      clickableWindow.addClickable((SxClickable) comp);
      addTransition(clickableWindow);
      return;
    }
    content.add(comp, index);
    if (comp instanceof SxSpotlight) {
      setDarken(true);
    }
  }

  public void removeComponent(Component comp) {
    content.remove(comp);
  }

  private void reset() {
    clear();
    transitions.clear();
    // now we dipose window so the .py script can terminate
    if (clickableWindow != null) {
      clickableWindow.dispose();
      clickableWindow = null;
    }
    dispose();
  }

  public void clear() {
    if (clickableWindow != null) {
      clickableWindow.clear();
    }
    stopAnimation();
    stopTracking();
    content.removeAll();
    transition = null;
    beam = null;
    setDarken(false);
    setVisible(false);
    GlobalMouseMotionTracker.getInstance().stop();
  }

  public void setDefaultTimeout(float timeout_in_seconds) {
    DEFAULT_TIMEOUT = timeout_in_seconds;
  }

  public Region getRegion() {
    return _region;
  }

  Point convertToRegionLocation(Point point_in_global_coordinate) {
    Point ret = new Point(point_in_global_coordinate);
    ret.translate(-_region.x, -_region.y);
    return ret;
  }

//
  //  SearchDialog search = null;

  /*  public void addSearchDialog() {
   * search = new SearchDialog(this, "Enter the search string:");
   * //search = new GUISearchDialog(this);
   * search.setLocationRelativeTo(null);
   * search.setAlwaysOnTop(true);
   * }
   *
   * public void setSearchDialog(SearchDialog search) {
   * this.search = search;
   * }
   *
   * public void addSearchEntry(String key, Region region) {
   * if (search == null) {
   * addSearchDialog();
   * }
   * search.addEntry(key, region);
   * }*/
  //

  boolean hasSpotlight() {
    for (Component comp : content.getComponents()) {
      if (comp instanceof SxSpotlight) {
        return true;
      }
    }
    return false;
  }

  public void updateSpotlights(ArrayList regions) {
    removeSpotlights();

    if (regions.isEmpty()) {

      setBackground(null);
      content.setBackground(null);

    } else {

      // if there are spotlights added, darken the background
      setBackground(new Color(0f, 0f, 0f, DIMMING_OPACITY));
      content.setBackground(new Color(0f, 0f, 0f, DIMMING_OPACITY));
      for (Region r : regions) {
        SxSpotlight spotlight = new SxSpotlight(r);
        spotlight.setShape(SxSpotlight.CIRCLE);
        //addSpotlight(r,SxSpotlight.CIRCLE);
      }
    }

    repaint();
  }

  public void removeSpotlights() {
    for (Component co : content.getComponents()) {
      if (co instanceof SxSpotlight) {
        content.remove(co);
      }
    }
  }

  public void setDarken(boolean darken) {
//TODO check against transparency
    if (darken) {
      //setBackground(new Color(0f,0f,0f,DIMMING_OPACITY));
      content.setBackground(new Color(0f, 0f, 0f, DIMMING_OPACITY));
    } else {
      setBackground(null);
      content.setBackground(null);
    }
  }

  public Visual addBeam(Region r) {
    beam = new SxBeam(this, r);
    SxAnchor anchor = new SxAnchor(r);
    addTransition(beam);
    return anchor;
  }

//
  /*  public void addMagnifier(Region region) {
   * Magnifier mag = new Magnifier(this, region);
   * content.add(mag);
   * }*/
  //

  //
  public void setDialog(String message) {
    TransitionDialog dialog = new TransitionDialog();
    dialog.setText(message);
    transition = dialog;
  }

  public void setDialog(TransitionDialog dialog_) {
    //dialog = dialog_;
    transition = dialog_;
  }

  //

  public void stopAnimation() {
    for (Component co : content.getComponents()) {

      /*      if (co instanceof Magnifier) {
       * ((Magnifier) co).start();
       * }*/
      if (co instanceof Visual) {
        ((Visual) co).stopAnimation();
      }
    }
  }

  public void startAnimation() {
    for (Component co : content.getComponents()) {

//      if (co instanceof Magnifier) {
//        ((Magnifier) co).start();
//      }
      if (co instanceof Visual) {
        ((Visual) co).startAnimation();
      }
    }
  }

  public void addTransition(Transition t) {
    if (!transitions.contains(t)) {
      transitions.add(t);
    }
  }

  public Transition getTransition() {
    return transition;
  }

  public void startTracking() {
    for (Component co : content.getComponents()) {
      ((Visual) co).updateComponent();
      if (co instanceof SxAnchor) {
        ((SxAnchor) co).startTracking();
      }
    }
  }

  public void stopTracking() {
    for (Component co : content.getComponents()) {
      if (co instanceof SxAnchor) {
        ((SxAnchor) co).stopTracking();
      }
    }
  }

  //
  public void addTracker(Pattern pattern, SxAnchor anchor) {
    Tracker tracker = null;

    //      // find a tracker already assigned to this pattern
    //      for (Tracker t : trackers){
    //         if (t.isAlreadyTracking(pattern,r)){
    //            tracker = t;
    //            break;
    //         }
    //      }

    //      if (tracker == null){
    tracker = new Tracker(this, pattern, null);
    trackers.add(tracker);
    //      }
    BufferedImage img;
    try {
      img = pattern.getBImage();
      anchor.setActualSize(img.getWidth(), img.getHeight());
      tracker.setAnchor(anchor);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void addTracker(Pattern pattern, Region r, Visual c) {
    Tracker tracker = null;

    // find a tracker already assigned to this pattern
    for (Tracker t : trackers) {
      if (t.isAlreadyTracking(pattern, r)) {
        tracker = t;
        break;
      }
    }

    if (tracker == null) {
      tracker = new Tracker(this, pattern, r);
      trackers.add(tracker);
    }

    tracker.setAnchor(c);
  }

  public void addTracker(Pattern pattern, Region r, ArrayList components) {
    Tracker tracker = new Tracker(this, pattern, r);
    for (Visual c : components) {
      tracker.setAnchor(c);
    }
    trackers.add(tracker);
  }

  abstract class TrackerAdapter {
    abstract void patternAnchored();
  }

  //

//
  /*  public void playStepOnWebpage(Step step, Region leftmarker, Region rightmarker) {
   *
   * //Point screenshotOrigin = new Point(614,166);
   *
   * int originalWidth = step.getScreenImage().getWidth();
   * int originalHeight = step.getScreenImage().getHeight();
   *
   * int displayWidth = rightmarker.x + rightmarker.w - leftmarker.x;
   * float scale = 1.0f * displayWidth / originalWidth;
   * Debug.info("scale:" + scale);
   * int displayHeight = (int) (originalHeight * scale);
   *
   * int originX = leftmarker.x;
   * int originY = leftmarker.y - displayHeight;
   * Point screenshotOrigin = new Point(originX, originY);
   *
   * //scale = 1.0f;
   * //Point screenshotOrigin = new Point(715,192);
   * //Point screenshotOrigin = new Point(953,257);//
   *
   * Debug.info("Step size:" + step.getView().getSize());
   * //Dimension displaySize = new Dimension(480,363);
   * //float scale = 480f/640f;
   *
   * Screen s = new Screen();
   * for (Part part : step.getParts()) {
   *
   * Point targetOrigin = part.getTargetOrigin();
   *
   * Point screenOrigin = new Point();
   * screenOrigin.x = screenshotOrigin.x + (int) (targetOrigin.x * scale);
   * screenOrigin.y = screenshotOrigin.y + (int) (targetOrigin.y * scale);
   *
   * part.setAnchorScreenLocation(screenOrigin);
   * }
   *
   * playStep(step, scale);
   * }
   *
   * public void playStep(Step step) {
   * playStep(step, 1.0f);
   * }
   *
   * public void play(ArrayList steps) {
   * for (SklStepModel step : steps) {
   * String ret = playStep(step);
   * if (ret == null) {
   * continue;
   * }
   *
   * if (ret.equals("Exit")) {
   * return;
   * }
   * }
   *
   * }*/
  //   public void playStepList(SklStepListModel stepListModel){
  //      for (Enumeration e = stepListModel.elements() ; e.hasMoreElements() ;) {
  //          SklStepModel eachStepModel = (SklStepModel) e.nextElement();
  //          String ret = playStep(eachStepModel);
  //          if (ret == null)
  //             continue;
  //
  //          if (ret.equals("Exit")){
  //             return;
  //          }
  //       }
  //
  //   }
  /*  public String playStep(SklStepModel step_) {
   *
   * SklStepModel step = null;
   * try {
   * step = (SklStepModel) step_.clone();
   * } catch (CloneNotSupportedException e1) {
   * e1.printStackTrace();
   * }
   *
   * for (SklModel model : step.getModels()) {
   * model.setOpacity(0f);
   * SklView view = SklViewFactory.createView(model);
   * addToFront(view);
   * }
   *
   *
   * SxButton btn = new SxButton("Exit");
   * btn.setActualLocation(10, 50);
   * addToFront(btn);
   *
   * SxButton skip = new SxButton("Skip");
   * skip.setActualLocation(90, 50);
   * addToFront(skip);
   *
   * // do these to allow static elements to be drawn
   * setVisible(true);
   * toFront();
   *
   * step.startTracking(this);
   * step.startAnimation();
   *
   * String ret = showNow();
   * Debug.info("[Guide.playStep] ret = " + ret);
   *
   * return ret;
   * }
   *
   * public void playStep(Step step, final float scale) {
   *
   *
   * SxImage screenshot = new SxImage(step.getScreenImage());
   * screenshot.setLocationRelativeToRegion(new Screen(), Layout.INSIDE);
   * //      screenshot.setOpacity(0);
   * //      screenshot.addAnimation(AnimationFactory.createOpacityAnimation(screenshot,0.1f,0.9f));
   * //      // TODO replace these with a Pause animation
   * //      screenshot.addAnimation(AnimationFactory.createOpacityAnimation(screenshot,0.9f,0.9f));
   * //      screenshot.addAnimation(AnimationFactory.createOpacityAnimation(screenshot,0.9f,0.9f));
   * //      screenshot.addAnimation(AnimationFactory.createOpacityAnimation(screenshot,1,0));
   * //      addToFront(screenshot);
   *
   * for (final Part part : step.getParts()) {
   *
   * Pattern pattern = part.getTargetPattern();
   *
   * BufferedImage patternImage = null;
   * try {
   * patternImage = pattern.getBImage();
   * } catch (Exception e) {
   * }
   *
   * final SxAnchor anchor = new SxAnchor(pattern);
   * anchor.setEditable(true);
   * anchor.setOpacity(1f);
   * anchor.setAnimateAnchoring(true);
   *
   * Point anchorLocation = new Point(part.getTargetOrigin());
   * Point screenshotLocation = screenshot.getActualLocation();
   * anchorLocation.translate(screenshotLocation.x, screenshotLocation.y);
   * anchor.setActualLocation(anchorLocation);
   *
   * SxClickable clickable = new SxClickable(null);
   * clickable.setLocationRelativeToComponent(anchor, Layout.OVER);
   * addToFront(clickable);
   *
   * // add an image to visualize the target pattern
   * final SxImage sklImage = new SxImage(patternImage);
   * sklImage.setLocationRelativeToComponent(anchor, Layout.OVER);
   *
   * anchor.addListener(new AnchorListener() {
   * @Override
   * public void anchored() {
   * sklImage.removeFromLeader();
   * sklImage.setVisible(false);
   * repaint();
   *
   *
   * for (Visual comp : anchor.getFollowers()) {
   * if (comp instanceof SxText || comp instanceof SxFlag) {
   * comp.popin();
   * }
   * }
   *
   * anchor.popin();
   * }
   *
   * @Override
   * public void found(SxAnchor source) {
   * }
   * });
   *
   * addToFront(sklImage);
   * addToFront(anchor);
   *
   * Point o = part.getTargetOrigin();
   * Point p = anchor.getActualLocation();
   *
   * for (Visual compo : part.getAnnotationComponents()) {
   *
   * Visual comp = (Visual) compo.clone();
   *
   * Point loc = comp.getActualLocation();
   * loc.x = (int) ((int) (loc.x - o.x) * scale) + p.x;
   * loc.y = (int) ((int) (loc.y - o.y) * scale) + p.y;
   *
   * comp.setActualLocation(loc);
   * comp.setLocationRelativeToComponent(anchor);
   * comp.setActualSize((int) (comp.getActualWidth() * scale), (int) (comp.getActualHeight() * scale));
   *
   * addToFront(comp);
   *
   * comp.popout();
   *
   * }
   *
   * anchor.popout();
   *
   * }
   *
   * SxButton btn = new SxButton("Exit");
   * btn.setActualLocation(50, 50);
   * addToFront(btn);
   *
   * showNow();
   *
   * }
   *
   * public void playSteps(ArrayList steps) throws FindFailed {
   *
   * Screen s = new Screen();
   *
   * for (Step step : steps) {
   * SxButton btn = new SxButton("Next");
   * btn.setLocation(s.getTopRight().left(200).below(50));
   *
   *
   * addToFront(btn);
   *
   * step.setTransition(getTransition());
   *
   * playStep(step, 1.0f);
   * }
   *
   * }*///

  /**
   * create a rectangle in this guide plane and add to front
   *
   * @return the rectangle
   */

  public Visual rectangle() {
    Visual gc = new SxRectangle();
    gc.setGuide(this);
    addToFront(gc);
    return gc;
  }

  public Visual circle() {
    Visual gc = new SxCircle();
    gc.setGuide(this);
    addToFront(gc);
    return gc;
  }

  public Visual text(String text) {
    Visual gc = new SxText(text);
    gc.setGuide(this);
    addToFront(gc);
    return gc;
  }

  public Visual flag(String text) {
    Visual gc = new SxFlag(text);
    gc.setGuide(this);
    addToFront(gc);
    return gc;
  }

  public Visual callout(String text) {
    Visual gc = new SxCallout(text);
    gc.setGuide(this);
    addToFront(gc);
    return gc;
  }

  public Visual image(Object img) {
    Visual gc = null;
    if (img instanceof String) {
      gc = new SxImage((String) img);
    } else if (img instanceof BufferedImage) {
      gc = new SxImage((BufferedImage) img);
    }
    if (gc != null) {
      gc.setGuide(this);
      addToFront(gc);
    } else {
      Debug.log(2, "Guide.image: invalid argument");
    }
    return gc;
  }

  public Visual bracket() {
    Visual gc = new SxBracket();
    gc.setGuide(this);
    addToFront(gc);
    return gc;
  }

  public Visual arrow(Object from, Object to) {
    Visual gc = null;
    if (from instanceof Region) {
      gc = new SxArrow(((Region) from).getCenter().getPoint(), ((Region) to).getCenter().getPoint());
    } else if (from instanceof Point || from instanceof Location) {
      gc = new SxArrow((Point) from, (Point) to);
    } else if (from instanceof Visual) {
      gc = new SxArrow((Visual) from, (Visual) to);
    }
    if (gc != null) {
      gc.setGuide(this);
      addToFront(gc);
    } else {
      Debug.log(2, "Guide.arrow: invalid arguments");
    }
    return gc;
  }

  public Visual button(String name) {
    Visual gc = new SxButton(name);
    gc.setGuide(this);
    addToFront(gc);
    return gc;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy