[sikuli] 320/385: ongoing: getting observe to work

Gilles Filippini pini at moszumanska.debian.org
Sun Jun 29 19:26:28 UTC 2014


This is an automated email from the git hooks/post-receive script.

pini pushed a commit to tag upstream/1.1.0_beta1
in repository sikuli.

commit 22d636ff90d738adcfd2f8b06814d609c85d92cd
Author: Raimund Hocke <rmhdevelop at me.com>
Date:   Tue Mar 4 17:30:11 2014 +0100

    ongoing: getting observe to work
---
 API/src/main/java/org/sikuli/script/Finder.java    |   8 +-
 API/src/main/java/org/sikuli/script/Image.java     |  37 ++
 API/src/main/java/org/sikuli/script/Match.java     |   5 +
 .../main/java/org/sikuli/script/ObserveAppear.java |  19 -
 .../main/java/org/sikuli/script/ObserveChange.java |  27 --
 .../main/java/org/sikuli/script/ObserveEvent.java  |  51 +--
 .../main/java/org/sikuli/script/ObserveVanish.java |  18 -
 API/src/main/java/org/sikuli/script/Observer.java  | 494 ++++++++++-----------
 API/src/main/java/org/sikuli/script/Observing.java | 153 ++++---
 API/src/main/java/org/sikuli/script/Region.java    | 176 +++++---
 .../java/org/sikuli/script/SikuliEventAdapter.java |  12 +-
 .../org/sikuli/script/SikuliEventObserver.java     |  11 +-
 API/src/main/java/org/sikuli/script/SikuliX.java   |   2 +-
 .../src/main/java/org/sikuli/basics/Settings.java  |   2 +-
 .../sikuli/scriptrunner/JythonScriptRunner.java    |   2 +-
 15 files changed, 528 insertions(+), 489 deletions(-)

diff --git a/API/src/main/java/org/sikuli/script/Finder.java b/API/src/main/java/org/sikuli/script/Finder.java
index af4ca9e..7d74089 100755
--- a/API/src/main/java/org/sikuli/script/Finder.java
+++ b/API/src/main/java/org/sikuli/script/Finder.java
@@ -196,7 +196,13 @@ public class Finder implements Iterator<Match> {
       _results = Vision.find(_findInput);
       _cur_result_i = 0;
       return img.getFilename();
-    } else {
+    } else if (img.isUseable()) {
+      if (img.getPattern() !=null) {
+        return find(img.getPattern());
+      } else {
+        return null;
+      }
+    } else {      
       return null;
     }
   }
diff --git a/API/src/main/java/org/sikuli/script/Image.java b/API/src/main/java/org/sikuli/script/Image.java
index 7b2a02d..7c5bd9d 100644
--- a/API/src/main/java/org/sikuli/script/Image.java
+++ b/API/src/main/java/org/sikuli/script/Image.java
@@ -92,10 +92,12 @@ public class Image {
   private String imageName = null;
   private boolean imageIsText = false;
   private boolean imageIsAbsolute = false;
+  private boolean imageIsPattern = false;
   private boolean beSilent = false;
   private String filepath = null;
   private URL fileURL = null;
   private BufferedImage bimg = null;
+  private Pattern pattern = null;
   private long bsize = 0;
   private int bwidth = -1;
   private int bheight = -1;
@@ -323,6 +325,37 @@ public class Image {
     }
     return createImageValidate(img);
   }
+  
+  public static Image createFromObject(Object obj) {
+    if (obj instanceof String) {
+      return create((String) obj);
+    } else if (obj instanceof Image) {
+      return (Image) obj;
+    }  else if (obj instanceof Pattern) {
+      return new Image((Pattern) obj);
+    }
+    return new Image();
+  } 
+  
+  private Image(Pattern p) {
+    pattern = p;
+    imageIsPattern = true;
+    setLastSeen(p.getImage().getLastSeen(), p.getImage().getLastSeenScore());
+  }
+  
+  public Pattern getPattern() {
+    return pattern;
+  }
+  
+  public Image getImage() {
+    if (isValid()) {
+      return this;
+    }
+    if (pattern != null) {
+      return pattern.getImage();
+    }
+    return null;
+  } 
 
   protected static Image get(URL imgURL) {
     return imageFiles.get(imgURL);
@@ -526,6 +559,10 @@ public class Image {
   public boolean isValid() {
     return filepath != null;
   }
+  
+  public boolean isUseable() {
+    return isValid() || imageIsPattern;
+  }
 
   /**
    *
diff --git a/API/src/main/java/org/sikuli/script/Match.java b/API/src/main/java/org/sikuli/script/Match.java
index 050ea22..aef3398 100755
--- a/API/src/main/java/org/sikuli/script/Match.java
+++ b/API/src/main/java/org/sikuli/script/Match.java
@@ -48,6 +48,11 @@ public class Match extends Region implements Comparable<Match> {
     copy(m);
   }
 
+  public Match(Region reg, double sc) {
+    init(reg.x, reg.y, reg.w, reg.h, reg.getScreen());
+    simScore = sc;
+  }
+
   private Match(Match m, Screen parent) {
     init(m.x, m.y, m.w, m.h, parent);
     copy(m);
diff --git a/API/src/main/java/org/sikuli/script/ObserveAppear.java b/API/src/main/java/org/sikuli/script/ObserveAppear.java
deleted file mode 100755
index b6f8a5d..0000000
--- a/API/src/main/java/org/sikuli/script/ObserveAppear.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2010-2014, Sikuli.org, SikuliX.com
- * Released under the MIT License.
- *
- * modified RaiMan
- */
-package org.sikuli.script;
-
-/**
- * INTERNAL USE
- */
-public class ObserveAppear extends ObserveEvent {
-
-   public ObserveAppear(String name, Object ptn, Match m, Region r){
-      super(name, ptn, m, r);
-      type = Type.APPEAR;
-   }
-
-}
diff --git a/API/src/main/java/org/sikuli/script/ObserveChange.java b/API/src/main/java/org/sikuli/script/ObserveChange.java
deleted file mode 100755
index 812f654..0000000
--- a/API/src/main/java/org/sikuli/script/ObserveChange.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2010-2014, Sikuli.org, SikuliX.com
- * Released under the MIT License.
- *
- * modified RaiMan
- */
-package org.sikuli.script;
-
-import java.util.List;
-
-/**
- * INTERNAL USE
- */
-public class ObserveChange extends ObserveEvent {
-   public ObserveChange(String name, List<Match> results, Region r, int eventIndex){
-     super(name, null, null, r);
-      type = Type.CHANGE;
-      setChanges(results);
-      setIndex(eventIndex);
-   }
-
-	@Override
-   public String toString(){
-      return String.format("ChangeEvent on %s | %d changes",
-               getRegion(), getChanges().size());
-   }
-}
diff --git a/API/src/main/java/org/sikuli/script/ObserveEvent.java b/API/src/main/java/org/sikuli/script/ObserveEvent.java
index 9b8e6a6..58abe58 100755
--- a/API/src/main/java/org/sikuli/script/ObserveEvent.java
+++ b/API/src/main/java/org/sikuli/script/ObserveEvent.java
@@ -1,13 +1,12 @@
 /*
- * Copyright 2010-2013, Sikuli.org
+ * Copyright 2010-2014, Sikuli.org, sikulix.com
  * Released under the MIT License.
  *
- * modified RaiMan 2013
+ * modified RaiMan
  */
 package org.sikuli.script;
 
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 
 public class ObserveEvent {
@@ -29,22 +28,23 @@ public class ObserveEvent {
   private long time;
   private String name;
 
-  public ObserveEvent() {
+  protected ObserveEvent() {
   }
   
   /**
    * INTERNAL USE ONLY: creates an observed event
    */
-  public ObserveEvent(String name, Object ptn, Match m, Region r) {
-    init(name, ptn, m, r);
+  protected ObserveEvent(String name, Type type, Object ptn, Match m, Region r, long now) {
+    init(name, type, ptn, m, r, now);
   }
 
-	private void init(String name, Object ptn, Match m, Region r) {
+	private void init(String name, Type type, Object ptn, Match m, Region r, long now) {
     this.name = name;
+    this.type = type;
     setRegion(r);
     setMatch(m);
     setPattern(ptn);
-    time = new Date().getTime();
+    time = now;
 	}
   
   /**
@@ -81,15 +81,7 @@ public class ObserveEvent {
     }
   }
 
-  /**
-   *
-   * @return the index in the observer map in Observer (CHANGE)
-   */
-  public int getIndex() {
-    return index;
-  }
-
-  public void setIndex(int index) {
+  protected void setIndex(int index) {
     this.index = index;
   }
 
@@ -132,6 +124,10 @@ public class ObserveEvent {
       }
     }
   }
+  
+  public long getTime() {
+    return time;
+  }
 
   /**
    * tell the observer to repeat this event's observe action immediately
@@ -147,32 +143,29 @@ public class ObserveEvent {
    * @param secs
    */
   public void repeat(long secs) {
-    region.getObserver().repeat(type, name, match, secs);
+    region.getObserver().repeat(name, secs);
   }
 
   /**
    * @return the number how often this event has already been triggered until now
    */
   public int getCount() {
-    if (region.getObserver() == null) {
-      return 1;
-    }
-    if (type == Type.CHANGE) {
-      return region.getObserver().getChangedCount(name);
-    } else {
-      return region.getObserver().getCount(name);
-    }
+    return region.getObserver().getCount(name);
   }
 
   /**
-   * stops the observer after returning from the handler
+   * stops the observer
    */
   public void stopObserver() {
     region.stopObserver();
   }
 
-  public void stopObserver(String msg) {
-    region.stopObserver(msg);
+  /**
+   * stops the observer and prints the given text
+   * @param text
+   */
+  public void stopObserver(String text) {
+    region.stopObserver(text);
   }
 
   @Override
diff --git a/API/src/main/java/org/sikuli/script/ObserveVanish.java b/API/src/main/java/org/sikuli/script/ObserveVanish.java
deleted file mode 100755
index 8a86805..0000000
--- a/API/src/main/java/org/sikuli/script/ObserveVanish.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2010-2014, Sikuli.org, SikuliX.com
- * Released under the MIT License.
- *
- * modified RaiMan
- */
-package org.sikuli.script;
-
-/**
- * INTERNAL USE
- */
-public class ObserveVanish extends ObserveEvent {
-   public ObserveVanish(String name, Object ptn, Match m, Region r){
-      super(name, ptn, m, r);
-      type = Type.VANISH;
-   }
-}
-
diff --git a/API/src/main/java/org/sikuli/script/Observer.java b/API/src/main/java/org/sikuli/script/Observer.java
index 65bfab5..cdc7bab 100755
--- a/API/src/main/java/org/sikuli/script/Observer.java
+++ b/API/src/main/java/org/sikuli/script/Observer.java
@@ -34,70 +34,73 @@ public class Observer {
 
   protected enum State {
 
-    FIRST, UNKNOWN, MISSING, APPEARED, VANISHED, REPEAT
+    FIRST, UNKNOWN, MISSING, REPEAT, HAPPENED, INACTIVE
   }
-  private Region observedRegion;
+  private Region observedRegion = null;
   private Mat lastImgMat = null;
   private org.opencv.core.Mat lastImageMat = null;
-  private final Map<String, State> eventStates;
-  private final Map<String, Long> repeatWaitTimes;
-  private final Map<String, Match> lastMatches;
-  private final Map<String, Object> eventNames;
-  private final Map<String, ObserveEvent.Type> eventTypes;
-  private final Map<String, Object> eventCallBacks;
-  private final Map<String, Integer> happenedCount;
-  private final Map<String, Integer> onChangeNames;
-  private int minChanges;
-  private boolean sthgLeft;
-  private boolean shouldCheckChanges;
+  private Map<String, State> eventStates = null;
+  private Map<String, Long> eventRepeatWaitTimes = null;
+  private Map<String, Match> eventMatches = null;
+  private Map<String, Object> eventNames = null;
+  private Map<String, ObserveEvent.Type> eventTypes = null;
+  private Map<String, Object> eventCallBacks = null;
+  private Map<String, Integer> eventCounts = null;
+  private int minChanges = 0;
+  private int numChangeCallBacks = 0;
+  private int numChangeObservers = 0;
+  private static boolean shouldStopOnFirstEvent = false;
+  
+  private Observer() {
+  }
 
-  public Observer(Region region) {
+  protected Observer(Region region) {
     observedRegion = region;
     eventStates = Collections.synchronizedMap(new HashMap<String, State>());
-    repeatWaitTimes = Collections.synchronizedMap(new HashMap<String, Long>());
-    happenedCount = Collections.synchronizedMap(new HashMap<String, Integer>());
-    lastMatches = Collections.synchronizedMap(new HashMap<String, Match>());
+    eventRepeatWaitTimes = Collections.synchronizedMap(new HashMap<String, Long>());
+    eventCounts = Collections.synchronizedMap(new HashMap<String, Integer>());
+    eventMatches = Collections.synchronizedMap(new HashMap<String, Match>());
     eventNames = Collections.synchronizedMap(new HashMap<String, Object>());
     eventTypes = Collections.synchronizedMap(new HashMap<String, ObserveEvent.Type>());
     eventCallBacks = Collections.synchronizedMap(new HashMap<String, Object>());
-    onChangeNames = Collections.synchronizedMap(new HashMap<String, Integer>());
   }
 
-  public void initialize() {
+  protected void initialize() {
     log(3, "resetting observe states for " + observedRegion.toStringShort());
-    sthgLeft = true;
-    shouldCheckChanges = true;
-    for (String name : eventNames.keySet()) {
-      eventStates.put(name, State.FIRST);
-      happenedCount.put(name, 0);
+    synchronized (eventNames) {
+      for (String name : eventNames.keySet()) {
+        eventStates.put(name, State.FIRST);
+        eventCounts.put(name, 0);
+        eventMatches.put(name, null);
+      }
     }
-    for (String name : onChangeNames.keySet()) {
-      happenedCount.put(name, 0);
+    shouldStopOnFirstEvent = false;
+    if (Observing.getStopOnFirstEvent()) {
+      log(lvl, "requested to stop on first event");
+      shouldStopOnFirstEvent = true;
     }
   }
-
-  public String[] getNames() {
-    String[] names = new String[eventNames.size() + onChangeNames.size()];
-    int i = 0;
-    for (String n : eventNames.keySet()) {
-      names[i++] = n;
-    }
-    for (String n : onChangeNames.keySet()) {
-      names[i++] = n;
-    }
-    return names;
+  
+  protected void setStopOnFirstEvent() {
+    shouldStopOnFirstEvent = true;
   }
 
-  public void setRegion(Region reg) {
-    observedRegion = reg;
+  protected String[] getNames() {
+    return eventNames.keySet().toArray(new String[0]);
   }
-
-  public int getCount(String name) {
-    return happenedCount.get(name);
+  
+  protected void setActive(String name, boolean state) {
+    if (eventNames.containsKey(me)) {
+      if (state) {
+        eventStates.put(name, State.FIRST);
+      } else {
+        eventStates.put(name, State.INACTIVE);
+      }
+    }
   }
-
-  public int getChangedCount(String name) {
-    return happenedCount.get(name);
+  
+  protected int getCount(String name) {
+    return eventCounts.get(name);
   }
 
   private <PSC> float getSimiliarity(PSC ptn) {
@@ -111,47 +114,45 @@ public class Observer {
     return similarity;
   }
 
-  public <PSC> void addObserver(PSC ptn, ObserverCallBack ob, String name, ObserveEvent.Type type) {
+  protected <PSC> void addObserver(PSC ptn, ObserverCallBack ob, String name, ObserveEvent.Type type) {
     eventCallBacks.put(name, ob);
     eventStates.put(name, State.FIRST);
     eventNames.put(name, ptn);
+    eventTypes.put(name, type);
+    if (type == ObserveEvent.Type.CHANGE) {
+      minChanges = getMinChanges();
+      numChangeObservers++;
+      if (eventCallBacks.get(name) != null) {
+        numChangeCallBacks++;
+      }
+    }
   }
 
-  public void removeObserver(String name) {
+  protected void removeObserver(String name) {
     Observing.remove(name);
+    if (eventTypes.get(name) == ObserveEvent.Type.CHANGE) {
+      if (eventCallBacks.get(name) != null) {
+        numChangeCallBacks--;
+      }
+      numChangeObservers--;
+    }
     eventNames.remove(name);
     eventCallBacks.remove(name);
     eventStates.remove(name);
+    eventTypes.remove(name);
+    eventCounts.remove(name);
+    eventMatches.remove(name);
+    eventRepeatWaitTimes.remove(name);
   }
-
-  private void callAppearObserver(String name, Match m) {
-    Object ptn = eventNames.get(name);
-    log(lvl, "appeared: %s with: %s\nat: %s", name, ptn, m);
-    ObserveAppear observeEvent = new ObserveAppear(name, ptn, m, observedRegion);
-    Object callBack = eventCallBacks.get(name);
-    Observing.addEvent(observeEvent);
-    if (callBack != null && callBack instanceof ObserverCallBack) {
-      log(lvl, "running call back");
-      ((ObserverCallBack) callBack).appeared(observeEvent);
-    }
+  
+  protected boolean hasObservers() {
+    return eventNames.size() > 0;
   }
 
-  private void callVanishObserver(String name, Match m) {
+  private void callEventObserver(String name, Match match, long time) {
     Object ptn = eventNames.get(name);
-    log(lvl, "vanished: %s with: %s\nat: %s", name, ptn, m);
-    ObserveVanish observeEvent = new ObserveVanish(name, ptn, m, observedRegion);
-    Object callBack = eventCallBacks.get(name);
-    Observing.addEvent(observeEvent);
-    if (callBack != null && callBack instanceof ObserverCallBack) {
-      log(lvl, "running call back");
-      ((ObserverCallBack) callBack).vanished(observeEvent);
-    }
-  }
-  
-  private void callEventObserver(String name, Match m) {
-    Object ptn = eventNames.get(name);
-    log(lvl, "appeared: %s with: %s\nat: %s", name, ptn, m);
-    ObserveAppear observeEvent = new ObserveAppear(name, ptn, m, observedRegion);
+    log(lvl, "%s: %s with: %s at: %s", eventTypes.get(name), name, ptn, match);
+    ObserveEvent observeEvent = new ObserveEvent(name, eventTypes.get(name), ptn, match, observedRegion, time);
     Object callBack = eventCallBacks.get(name);
     Observing.addEvent(observeEvent);
     if (callBack != null && callBack instanceof ObserverCallBack) {
@@ -160,140 +161,129 @@ public class Observer {
     }    
   }
 
-  private void checkPatterns(ScreenImage simg) {
-    Finder finder = null;
-    if (Settings.UseImageFinder) {
-      finder = new ImageFinder(observedRegion);
-      ((ImageFinder) finder).setIsMultiFinder();
-    } else {
-      finder = new Finder(simg, observedRegion);
+  private boolean checkPatterns(ScreenImage simg) {
+    log(lvl + 1, "update: checking patterns");
+    if (!observedRegion.isObserving()) {
+      return false;
     }
-    String imgOK;
-    log(lvl + 1, "checkPatterns entry: sthgLeft: %s isObserving: %s", sthgLeft, observedRegion.isObserving());
+    Finder finder = null;
     for (String name : eventStates.keySet()) {
-      if (eventStates.get(name) != State.FIRST
-              && eventStates.get(name) != State.UNKNOWN
-              && eventStates.get(name) != State.REPEAT) {
+      if (!patternsToCheck()) {
         continue;
       }
-      imgOK = null;
-      Object ptn = eventNames.get(name);
-      if (ptn instanceof String) {
-        imgOK = finder.find((String) ptn);
-        Image img = Image.create((String) ptn);
-        if (img.isValid()) {
-          imgOK = finder.find(img);
-        } else if (img.isText()) {
-          imgOK = finder.findText((String) ptn);
+      if (eventStates.get(name) == State.REPEAT) {
+        if ((new Date()).getTime() < eventRepeatWaitTimes.get(name)) {
+          continue;
+        } else {
+          eventStates.put(name, State.UNKNOWN);
         }
-      } else if (ptn instanceof Pattern) {
-        imgOK = finder.find((Pattern) ptn);
-      } else if (ptn instanceof Image) {
-        imgOK = finder.find((Image) ptn);
       }
-      if (null == imgOK) {
+      Object ptn = eventNames.get(name);
+      Image img = Image.createFromObject(ptn);
+      if (!img.isUseable()) {
         Debug.error("EventMgr: checkPatterns: Image not valid", ptn);
         eventStates.put(name, State.MISSING);
         continue;
       }
-      if (eventStates.get(name) == State.REPEAT) {
-        log(lvl, "repeat: checking");
-        if (lastMatches.get(name).exists(ptn) != null) {
-          if ((new Date()).getTime() > repeatWaitTimes.get(name)) {
-            eventStates.put(name, State.APPEARED);
-            log(lvl, "repeat: vanish timeout");
-            // time out
+      Match match = null;
+      boolean hasMatch = false;
+      long lastSearchTime;
+      long now = 0;
+      if (!Settings.UseImageFinder && Settings.CheckLastSeen && null != img.getLastSeen()) {
+        Region r = Region.create(img.getLastSeen());
+        if (observedRegion.contains(r)) {
+          lastSearchTime = (new Date()).getTime();
+          Finder f = new Finder(new Screen().capture(r), r);
+          f.find(new Pattern(img.getImage()).similar(Settings.CheckLastSeenSimilar));
+          if (f.hasNext()) {
+            log(lvl + 1, "checkLastSeen: still there");
+            match = new Match(new Region(img.getLastSeen()), img.getLastSeenScore());
+            match.setTimes(0, (new Date()).getTime() - lastSearchTime);
+            hasMatch = true;
           } else {
-            sthgLeft = true;
+            log(lvl + 1, "checkLastSeen: not there");
           }
-          continue; // not vanished within given time or still there
-        } else {
-          eventStates.put(name, State.UNKNOWN);
-          sthgLeft = true;
-          log(lvl, "repeat: has vanished");
-          continue; // has vanished, repeat
         }
       }
-      Match m = null;
-      boolean hasMatch = false;
-      if (finder.hasNext()) {
-        m = finder.next();
-        if (m.getScore() >= getSimiliarity(ptn)) {
-          hasMatch = true;
-          lastMatches.put(name, m);
+      if (match == null) {
+        if (finder == null) {
+          if (Settings.UseImageFinder) {
+            finder = new ImageFinder(observedRegion);
+            ((ImageFinder) finder).setIsMultiFinder();
+          } else {
+            finder = new Finder(simg, observedRegion);
+          }
+        }
+        lastSearchTime = (new Date()).getTime();
+        now = (new Date()).getTime();
+        finder.find(img);
+        if (finder.hasNext()) {
+          match = finder.next();
+          match.setTimes(0, now - lastSearchTime);
+          if (match.getScore() >= getSimiliarity(ptn)) {
+            hasMatch = true;
+            img.setLastSeen(match.getRect(), match.getScore());
+          }
         }
       }
       if (hasMatch) {
-        log(lvl + 1, "checkPatterns: " + ptn.toString() + " match: "
-                + m.toStringShort() + " in " + observedRegion.toStringShort());
+        eventMatches.put(name, match);
+        log(lvl + 1, "(%s): %s match: %s in:%s", eventTypes.get(name), ptn.toString(), 
+                match.toStringShort(), observedRegion.toStringShort());
       } else if (eventStates.get(ptn) == State.FIRST) {
-        log(lvl + 1, "checkPatterns: " + ptn.toString() + " match: "
-                + "NO" + " in " + observedRegion.toStringShort());
+        log(lvl + 1, "(%s): %s match: %s in:%s", eventTypes.get(name), ptn.toString(), 
+                match.toStringShort(), observedRegion.toStringShort());
         eventStates.put(name, State.UNKNOWN);
       }
-      if (appearCallBacks.containsKey(name)) {
-        if (eventStates.get(name) != State.APPEARED) {
-          if (hasMatch) {
-            eventStates.put(name, State.APPEARED);
-            happenedCount.put(name, happenedCount.get(name) + 1);
-            callAppearObserver(name, m);
-          } else {
-            sthgLeft = true;
-          }
+      if (eventStates.get(name) != State.HAPPENED) {
+        if (hasMatch && eventTypes.get(name) == ObserveEvent.Type.VANISH) {
+          eventMatches.put(name, match);
         }
-      } else if (vanishCallBacks.containsKey(ptn)) {
-        if (eventStates.get(ptn) != State.VANISHED) {
-          if (!hasMatch) {
-            eventStates.put(name, State.VANISHED);
-            happenedCount.put(name, happenedCount.get(name) + 1);
-            callVanishObserver(name, lastMatches.get(name));
-          } else {
-            sthgLeft = true;
+        if ((hasMatch && eventTypes.get(name) == ObserveEvent.Type.APPEAR)
+                || (!hasMatch && eventTypes.get(name) == ObserveEvent.Type.VANISH)) {
+          eventStates.put(name, State.HAPPENED);
+          eventCounts.put(name, eventCounts.get(name) + 1);
+          callEventObserver(name, eventMatches.get(name), now);
+          if (shouldStopOnFirstEvent) {
+            observedRegion.stopObserver();
           }
         }
       }
       if (!observedRegion.isObserving()) {
-        break;
+        return false;
       }
     }
-    log(lvl + 1, "checkPatterns exit: sthgLeft: %s isObserving: %s", sthgLeft, observedRegion.isObserving());
+    return patternsToCheck();
   }
-
-  public void repeat(ObserveEvent.Type type, String name, Match match, long secs) {
-    if (type == ObserveEvent.Type.CHANGE) {
-      Debug.error("EventMgr: repeat: CHANGE repeats automatically");
-    } else if (type == ObserveEvent.Type.VANISH) {
-      Debug.error("EventMgr: repeat: not supported for VANISH");
-    } else if (type == ObserveEvent.Type.APPEAR) {
-      eventStates.put(name, State.REPEAT);
-      if (secs <= 0) {
-        secs = (long) observedRegion.getWaitForVanish();
+  
+  private boolean patternsToCheck () {
+    for (String name : eventNames.keySet()) {
+      if (eventTypes.get(name) == ObserveEvent.Type.CHANGE) {
+        continue;
+      }
+      State s = eventStates.get(name);
+      if (s == State.FIRST || s == State.UNKNOWN || s == State.REPEAT) {
+        return true;
       }
-      repeatWaitTimes.put(name, (new Date()).getTime() + 1000 * secs);
-      log(lvl, "repeat: requested for APPEAR: "
-              + eventNames.get(name).toString() + " at " + match.toStringShort() + " after " + secs + " seconds");
-      sthgLeft = true;
     }
+    return false;
   }
-
-  public void addChangeObserver(int threshold, ObserverCallBack ob, String name) {
-    eventCallBacks.put(name, ob);
-    minChanges = getMinChanges();
-    onChangeNames.put(name, threshold);
+  
+  protected void repeat(String name, long secs) {
+    eventStates.put(name, State.REPEAT);
+    if (secs <= 0) {
+      secs = (long) observedRegion.getRepeatWaitTime();
+    }
+    eventRepeatWaitTimes.put(name, (new Date()).getTime() + 1000 * secs);
+    log(lvl, "repeat (%s): %s after %d seconds", eventTypes.get(name), name, secs);
   }
 
-//  public void removeChangeObserver(int threshold) {
-//    Observing.remove(onChangeNames.get(threshold));
-//    onChangeNames.remove(threshold);
-//    changeCallBacks.remove(new Integer(threshold));
-//    minChanges = getMinChanges();
-//  }
-//
   private int getMinChanges() {
     int min = Integer.MAX_VALUE;
     int n;
-    for (String name : onChangeNames.keySet()) {
-      n = onChangeNames.get(name);
+    for (String name : eventNames.keySet()) {
+      if (eventTypes.get(name) != ObserveEvent.Type.CHANGE) continue;
+      n = (Integer) eventNames.get(name);
       if (n < min) {
         min = n;
       }
@@ -301,16 +291,75 @@ public class Observer {
     return min;
   }
 
-  private int callChangeObserver(FindResults results) {
-    int activeChangeCallBacks = 0;
+  private boolean checkChanges(ScreenImage img) {
+    if (numChangeObservers == 0) {
+      return false;
+    }
+    boolean leftToDo = false;
+    if (lastImgMat == null) {
+      if (Settings.UseImageFinder) {
+        lastImageMat = new org.opencv.core.Mat();
+      } else {
+        lastImgMat = Image.convertBufferedImageToMat(img.getImage());
+      }
+      return true;
+    }
+    if (Settings.UseImageFinder && lastImageMat.empty()) {
+      lastImageMat = Image.createMat(img.getImage());
+      return true;
+    }
+    for (String name : eventNames.keySet()) {
+      if (eventTypes.get(name) != ObserveEvent.Type.CHANGE) {
+        continue;
+      }
+      if (eventStates.get(name) == State.REPEAT) {
+        if ((new Date()).getTime() < eventRepeatWaitTimes.get(name)) {
+          continue;
+        }
+      }
+      leftToDo = true;
+    }
+    if (leftToDo) {
+      leftToDo = false;
+      log(lvl + 1, "update: checking changes");
+      if (Settings.UseImageFinder) {
+        ImageFinder f = new ImageFinder(lastImageMat);
+        f.setMinChanges(minChanges);
+        org.opencv.core.Mat current = Image.createMat(img.getImage());
+        if (f.hasChanges(current)) {
+          //TODO implement ChangeObserver: processing changes
+          log(lvl, "TODO: processing changes");
+        }
+        lastImageMat = current;
+      } else {
+        FindInput fin = new FindInput();
+        fin.setSource(lastImgMat);
+        Mat target = Image.convertBufferedImageToMat(img.getImage());
+        fin.setTarget(target);
+        fin.setSimilarity(minChanges);
+        FindResults results = Vision.findChanges(fin);
+        if (results.size() > 0) {
+          callChangeObserver(results);
+          if (shouldStopOnFirstEvent) {
+            observedRegion.stopObserver();
+          }
+        } else {
+          leftToDo = true;
+        }
+        lastImgMat = target;
+      }
+    }
+    return leftToDo |= numChangeCallBacks > 0;
+  }
+
+  private void callChangeObserver(FindResults results) {
     int n;
     log(lvl, "changes: %d in: %s", results.size(), observedRegion);
-    for (String name : onChangeNames.keySet()) {
-      n = onChangeNames.get(name);
-      if (happenedCount.get(name) == -1) {
+    for (String name : eventNames.keySet()) {
+      if (eventTypes.get(name) != ObserveEvent.Type.CHANGE) {
         continue;
-      }
-      activeChangeCallBacks++;
+      } 
+      n = (Integer) eventNames.get(name);
       List<Match> changes = new ArrayList<Match>();
       for (int i = 0; i < results.size(); i++) {
         FindResult r = results.get(i);
@@ -319,87 +368,32 @@ public class Observer {
         }
       }
       if (changes.size() > 0) {
-        happenedCount.put(name, happenedCount.get(name) + 1);
-        ObserveChange observeEvent = new ObserveChange(name, changes, observedRegion, n);
-        Object callBack = eventCallBacks.get(name);
+        long now = (new Date()).getTime();
+        eventCounts.put(name, eventCounts.get(name) + 1);
+        ObserveEvent observeEvent = new ObserveEvent(name, ObserveEvent.Type.CHANGE, null, null, observedRegion, now);
+        observeEvent.setChanges(changes);
+        observeEvent.setIndex(n);
         Observing.addEvent(observeEvent);
-        if (callBack != null && callBack instanceof ObserverCallBack) {
+        Object callBack = eventCallBacks.get(name);
+        if (callBack != null) {
           log(lvl, "running call back");
           ((ObserverCallBack) callBack).changed(observeEvent);
-        } else {
-          // onChange only repeated if CallBack given
-          happenedCount.put(name, -1);
-          activeChangeCallBacks--;
-        }
-      }
-    }
-    return activeChangeCallBacks;
-  }
-
-  private boolean checkChanges(ScreenImage img) {
-    boolean changesObserved = true;
-    if (Settings.UseImageFinder) {
-      //TODO hack to hide the native call - should be at the top
-      if (lastImageMat == null) {
-        lastImageMat = new org.opencv.core.Mat();
-      }
-      if (lastImageMat.empty()) {
-        lastImageMat = Image.createMat(img.getImage());
-        return true;
-      }
-      ImageFinder f = new ImageFinder(lastImageMat);
-      f.setMinChanges(minChanges);
-      org.opencv.core.Mat current = Image.createMat(img.getImage());
-      if (f.hasChanges(current)) {
-        //TODO implement ChangeObserver: processing changes
-        log(lvl, "TODO: processing changes");
-      }
-      lastImageMat = current;
-    } else {
-      if (lastImgMat == null) {
-        lastImgMat = Image.convertBufferedImageToMat(img.getImage());
-        return true;
-      }
-      FindInput fin = new FindInput();
-      fin.setSource(lastImgMat);
-      Mat target = Image.convertBufferedImageToMat(img.getImage());
-      fin.setTarget(target);
-      fin.setSimilarity(minChanges);
-      FindResults results = Vision.findChanges(fin);
-      if (results.size() > 0) {
-        if (0 == callChangeObserver(results)) {
-          changesObserved = false;
         }
       }
-      lastImgMat = target;
     }
-    return changesObserved;
   }
 
-  public boolean update(ScreenImage simg) {
-    log(lvl + 1, "update entry: sthgLeft: %s obs? %s", sthgLeft, observedRegion.isObserving());
-    boolean ret;
-    boolean changesObserved;
-    ret = sthgLeft;
-    if (sthgLeft) {
-      sthgLeft = false;
-      checkPatterns(simg);
-      if (!observedRegion.isObserving()) {
-        return false;
-      }
+  protected boolean update(ScreenImage simg) {
+    boolean fromPatterns = checkPatterns(simg);
+    log(lvl, "update result: Patterns: %s", fromPatterns);
+    if (!observedRegion.isObserving()) {
+      return false;
     }
-    if (observedRegion.isObserving()) {
-      ret = sthgLeft;
-      if (shouldCheckChanges && onChangeNames.size() > 0) {
-        changesObserved = checkChanges(simg);
-        shouldCheckChanges = changesObserved;
-        if (!observedRegion.isObserving()) {
-          return false;
-        }
-        ret = changesObserved;
-      }
+    boolean fromChanges = checkChanges(simg);
+    log(lvl, "update result: Changes: %s", fromChanges);
+    if (!observedRegion.isObserving()) {
+      return false;
     }
-    log(lvl + 1, "update exit: ret: %s", ret);
-    return ret;
+   return false || fromPatterns || fromChanges;
   }
 }
diff --git a/API/src/main/java/org/sikuli/script/Observing.java b/API/src/main/java/org/sikuli/script/Observing.java
index e76383c..ac3633a 100644
--- a/API/src/main/java/org/sikuli/script/Observing.java
+++ b/API/src/main/java/org/sikuli/script/Observing.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010-2014, Sikuli.org, SikuliX.com
+ * Copyright 2010-2014, Sikuli.org, sikulix.com
  * Released under the MIT License.
  *
  * modified RaiMan
@@ -20,8 +20,8 @@ import org.sikuli.basics.Debug;
  */
 public class Observing {
 
-  private static String me = "Observing";
-  private static int lvl = 3;
+  private static final String me = "Observing";
+  private static final int lvl = 3;
 
   private static void log(int level, String message, Object... args) {
     Debug.logx(level, "", me + ": " + message, args);
@@ -30,25 +30,30 @@ public class Observing {
   private Observing() {
   }
 
-  private static class ObserverEntry {
-
-    private Region region;
-    private ObserveEvent.Type type;
-    private boolean isActive = true;
-    private ObserverCallBack obs;
-
-    protected ObserverEntry(Region reg, ObserverCallBack obs, ObserveEvent.Type type) {
-      region = reg;
-      this.obs = obs;
-      this.type = type;
-    }
-  }
-
-  private static final Map<String, ObserverEntry> observers = Collections.synchronizedMap(new HashMap<String, ObserverEntry>());
+  private static final Map<String, Region> observers = Collections.synchronizedMap(new HashMap<String, Region>());
   private static final Map<String, ObserveEvent> events = Collections.synchronizedMap(new HashMap<String, ObserveEvent>());
   private static final List<Region> runningObservers = Collections.synchronizedList(new ArrayList<Region>());
+  private static long lastName = 0;
+  private static boolean shouldStopOnFirstEvent = false;
 
+  /**
+   * tell the next starting observer, to stop on the first event
+   */
+  public static void setStopOnFirstEvent() {
+    shouldStopOnFirstEvent = true;
+  }
+  
+  protected static boolean getStopOnFirstEvent() {
+    boolean val = shouldStopOnFirstEvent;
+    shouldStopOnFirstEvent = false;
+    return val;
+  }
+  
   protected static void addRunningObserver(Region r) {
+    if (shouldStopOnFirstEvent) {
+      shouldStopOnFirstEvent = false;
+      r.getObserver().setStopOnFirstEvent();
+    }
     runningObservers.add(r);
     log(lvl,"add observer: now running %d observer(s)", runningObservers.size());
   }
@@ -58,44 +63,39 @@ public class Observing {
     log(lvl, "remove observer: now running %d observer(s)", runningObservers.size());
   }
   
-  protected static void stopRunningObservers() {
-    if (runningObservers.size() > 0) {
-      log(lvl, "stopping %d running observer(s)", runningObservers.size());
-      synchronized (runningObservers) {
-        for (Region r : runningObservers) {
-          r.stopObserver();
-        }
-        runningObservers.clear();
-      }
+  protected static synchronized String add(Region reg, ObserverCallBack obs, ObserveEvent.Type type, Object target) {
+    String name;
+    long now = new Date().getTime();
+    while (now <= lastName) {
+      now++;
     }
-    Observing.clear();
+    lastName = now;
+    name = "" + now;
+    observers.put(name, reg);
+    reg.getObserver().addObserver(target, (ObserverCallBack) obs, name, type);
+    return name;
+  }
+  
+  /**
+   * set the observer with the given name inactive (not checked while observing)
+   * @param name
+   */
+  public void setInactive(String name) {
+    setActive(name, false);
   }
 
   /**
-   * INTERNAL USE: adds an observer to the list
-   *
-   * @param reg the observed region
-   * @param obs the callback (might be null - observer without call back)
-   * @param type one off ObserveEvent.Type.APPEAR, VANISH, CHANGE, GENERIC
-   * @param target 
-   * @return a unique name derived from time or null if not possible
+   * set the observer with the given name active (checked while observing)
+   * @param name
    */
-  public static String add(Region reg, ObserverCallBack obs, ObserveEvent.Type type, Object target) {
-    String name = null;
-    long now = new Date().getTime();
-    while (true) {
-      name = "" + now++;
-      if (!hasName(name)) {
-        break;
-      }
-    }
-    observers.put("" + now, new ObserverEntry(reg, obs, type));
-    reg.getObserver().addObserver(target, (ObserverCallBack) obs, name, type);
-    return name;
+  public void setActive(String name) {
+    setActive(name, true);
   }
 
-  private static boolean hasName(String name) {
-    return observers.containsKey(name);
+  protected static void setActive(String name, boolean state) {
+    if (observers.containsKey(name)) {
+      observers.get(name).getObserver().setActive(name, state);
+    }
   }
 
   /**
@@ -103,11 +103,10 @@ public class Observing {
    * events for that observer are removed as well
    *
    * @param name name of observer
-   * @return success
    */
   public static void remove(String name) {
     if (observers.containsKey(name)) {
-      observers.get(name).region.stopObserver();
+      observers.get(name).stopObserver();
       observers.remove(name);
       events.remove(name);
     }
@@ -128,17 +127,29 @@ public class Observing {
    * stop and remove all observers and their registered events
    *
    */
-  public static void clear() {
+  public static void cleanUp() {
+    String[] names;
     synchronized (observers) {
+      names = new String[observers.size()];
+      int i = 0;
       for (String name : observers.keySet()) {
-        remove(name);
+        Region reg = observers.get(name);
+        if (reg.isObserving()) {
+          reg.stopObserver();
+        }
+        events.remove(name);
+        names[i++] = name;
       }
     }
-    log(lvl, "as requested: removed all observers");
+    runningObservers.clear();
+    for (String name : names) {
+      observers.remove(name);
+    }
+    log(lvl + 1, "as requested: removed all observers");
   }
 
   /**
-   * are their any events registered
+   * are their any happened events
    *
    * @return true if yes
    */
@@ -147,8 +158,9 @@ public class Observing {
   }
 
   /**
-   * are their any events registered for this region?
+   * are their any happened events for this region?
    *
+   * @param reg
    * @return true if yes
    */
   public static boolean hasEvents(Region reg) {
@@ -161,20 +173,16 @@ public class Observing {
   }
 
   /**
-   * are their any events registered for the observer having this name?
+   * are their any happened events for the observer having this name?
    *
+   * @param name
    * @return true if yes
    */
   public static boolean hasEvent(String name) {
     return events.containsKey(name);
   }
 
-  /**
-   * add a new event to the list
-   *
-   * @param name name of event
-   */
-  public static void addEvent(ObserveEvent evt) {
+  protected static void addEvent(ObserveEvent evt) {
     events.put(evt.getName(), evt);
   }
 
@@ -182,6 +190,7 @@ public class Observing {
    * return the events for that region <br>
    * events are removed from the list
    *
+   * @param reg
    * @return the array of events or size 0 array if none
    */
   public static ObserveEvent[] getEvents(Region reg) {
@@ -189,14 +198,16 @@ public class Observing {
     ObserveEvent evt;
     for (String name : reg.getObserver().getNames()) {
       evt = events.get(name);
-      if (evt != null) evts.add(evt);
+      if (evt != null) {
+        evts.add(evt);
+      }
       events.remove(name);
     }
     return evts.toArray(new ObserveEvent[0]);
   }
 
   /**
-   * return the all events (they are preserved) <br>
+   * return all events (they are preserved) <br>
    *
    * @return the array of events or size 0 array if none
    */
@@ -214,6 +225,18 @@ public class Observing {
     return evts.toArray(new ObserveEvent[0]);
   }
   
+  /**
+   * retrieves and removes the requested event
+   * @param name of event
+   * @return the event or null
+   */
+  public static ObserveEvent getEvent(String name) {
+    return events.remove(name);
+  }
+  
+  /**
+   * the event list is purged
+   */
   public static void clearEvents() {
     events.clear();
   }
diff --git a/API/src/main/java/org/sikuli/script/Region.java b/API/src/main/java/org/sikuli/script/Region.java
index c563d87..3c64c4e 100755
--- a/API/src/main/java/org/sikuli/script/Region.java
+++ b/API/src/main/java/org/sikuli/script/Region.java
@@ -75,7 +75,7 @@ public class Region {
    */
   private boolean observing = false;
   private float observeScanRate = Settings.ObserveScanRate;
-  private int waitForVanish = Settings.WaitForVanish;
+  private int repeatWaitTime = Settings.RepeatWaitTime;
   /**
    * The {@link Observer} Singleton instance
    */
@@ -686,19 +686,19 @@ public class Region {
 
   /**
    *
-   * @return the regions current WaitForVaish time in seconds
+   * @return the regions current RepeatWaitTime time in seconds
    */
-  public int getWaitForVanish() {
-    return waitForVanish;
+  public int getRepeatWaitTime() {
+    return repeatWaitTime;
   }
 
   /**
    * set the regions individual WaitForVanish
    *
-   * @param waitForVanish time in seconds
+   * @param time in seconds
    */
-  public void setWaitForVanish(int waitForVanish) {
-    this.waitForVanish = waitForVanish;
+  public void setRepeatWaitTime(int time) {
+    repeatWaitTime = time;
   }
 
   //</editor-fold>
@@ -2463,10 +2463,22 @@ public class Region {
     }
     return regionObserver;
   }
+  
+  /**
+   * evaluate if at least one event observer is defined for this region (the observer need not be running)
+   * @return true, if the region has an observer with event observers 
+   */
+  public boolean hasObserver() {
+    if (regionObserver != null) {
+      return regionObserver.hasObservers();
+    } else {
+      return false;
+    }
+  }
 
   /**
    *
-   * @return true if an observer is active for this region
+   * @return true if an observer is running for this region
    */
   public boolean isObserving() {
     return observing;
@@ -2474,17 +2486,52 @@ public class Region {
   
   /**
    *
-   * @return true if any events have been before, false otherwise
+   * @return true if any events have happened for this region, false otherwise
    */
   public boolean hasEvents() {
     return Observing.hasEvents(this);
   }
   
+  /**
+   * the region's events are removed from the list
+   * @return the region's happened events as array if any (size might be 0)  
+   */
   public ObserveEvent[] getEvents() {
     return Observing.getEvents(this);
   }
 
   /**
+   * the event is removed from the list
+   * @param name
+   * @return the named event if happened otherwise null 
+   */
+  public ObserveEvent getEvent(String name) {
+    return Observing.getEvent(name);
+  }
+
+  /**
+   * set the observer with the given name inactive (not checked while observing)
+   * @param name
+   */
+  public void setInactive(String name) {
+    if (!hasObserver()) {
+      return;
+    } 
+    Observing.setActive(name, false);
+  }
+
+  /**
+   * set the observer with the given name inactive (not checked while observing)
+   * @param name
+   */
+  public void setActive(String name) {
+    if (!hasObserver()) {
+      return;
+    } 
+    Observing.setActive(name, true);
+  }
+
+  /**
    * a subsequently started observer in this region should wait for target
    * and notify the given observer about this event<br />
    * for details about the observe event handler: {@link ObserverCallBack}<br />
@@ -2641,8 +2688,7 @@ public class Region {
   }
 
   public String onChangeDo(int threshold, Object observer) {
-    String name = Observing.add(this, (ObserverCallBack) observer, ObserveEvent.Type.CHANGE);
-    getObserver().addChangeObserver(threshold, (ObserverCallBack) observer, name);
+    String name = Observing.add(this, (ObserverCallBack) observer, ObserveEvent.Type.CHANGE, threshold);
     log(lvl, "%s: onChange%s: %s minSize: %d", toStringShort(), 
             (observer == null ? "" : " with callback"), name, threshold);
     return name;
@@ -2711,17 +2757,16 @@ public class Region {
         observing = false;
         break;
       }
-      long after_find = (new Date()).getTime();
       if (!observing) {
         break;
       }
+      long after_find = (new Date()).getTime();
       try {
         if (after_find - before_find < MaxTimePerScan) {
           Thread.sleep((int) (MaxTimePerScan - (after_find - before_find)));
         }
       } catch (Exception e) {
       }
-      log(lvl, "observe: checking again in %s", toStringShort());
     }
     boolean observeSuccess = false;
     if (observing) {
@@ -2787,8 +2832,6 @@ public class Region {
   //</editor-fold>
 
   //<editor-fold defaultstate="collapsed" desc="Mouse actions - clicking">
-  // returns target offset of lastmatch if exists
-  //Region.center / Match.targetOffset otherwise
   private Location checkMatch() {
     if (lastMatch != null) {
       return lastMatch.getTarget();
@@ -2815,12 +2858,12 @@ public class Region {
    * before and use the match<br> Region - position at center<br> Match - position at match's targetOffset<br> Location
    * - position at that point<br>
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> to search: Pattern, Filename, Text, Region, Match or Location 
+   * @param target
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed for Pattern or Filename
    */
-  public <PatternFilenameRegionMatchLocation> int hover(PatternFilenameRegionMatchLocation target)
-          throws FindFailed {
+  public <PFRML> int hover(PFRML target) throws FindFailed {
     log(lvl, "hover: " + target);
     return mouseMove(target);
   }
@@ -2844,12 +2887,12 @@ public class Region {
    * position at center<br> Match - position at match's targetOffset<br>
    * Location - position at that point<br>
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> to search: Pattern, Filename, Text, Region, Match or Location 
+   * @param target
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed for Pattern or Filename
    */
-  public <PatternFilenameRegionMatchLocation> int click(PatternFilenameRegionMatchLocation target)
-          throws FindFailed {
+  public <PFRML> int click(PFRML target) throws FindFailed {
     return click(target, 0);
   }
 
@@ -2858,13 +2901,13 @@ public class Region {
    * Pattern or Filename - do a find before and use the match<br> Region - position at center<br>
    * Match - position at match's targetOffset<br> Location - position at that point<br>
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> to search: Pattern, Filename, Text, Region, Match or Location 
+   * @param target
    * @param modifiers the value of the resulting bitmask (see KeyModifier)
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed for Pattern or Filename
    */
-  public <PatternFilenameRegionMatchLocation> int click(PatternFilenameRegionMatchLocation target, int modifiers)
-          throws FindFailed {
+  public <PFRML> int click(PFRML target, int modifiers) throws FindFailed {
     Location loc = getLocationFromTarget(target);
     int ret = Mouse.click(loc, InputEvent.BUTTON1_MASK, modifiers, false, this);
 
@@ -2891,12 +2934,12 @@ public class Region {
    * position at center<br> Match - position at match's targetOffset<br>
    * Location - position at that point<br>
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location 
+   * @param target
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed for Pattern or Filename
    */
-  public <PatternFilenameRegionMatchLocation> int doubleClick(PatternFilenameRegionMatchLocation target)
-          throws FindFailed {
+  public <PFRML> int doubleClick(PFRML target) throws FindFailed {
     return doubleClick(target, 0);
   }
 
@@ -2905,13 +2948,13 @@ public class Region {
    * Pattern or Filename - do a find before and use the match<br> Region - position at center<br > Match - position at
    * match's targetOffset<br> Location - position at that point<br>
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location 
+   * @param target
    * @param modifiers the value of the resulting bitmask (see KeyModifier)
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed for Pattern or Filename
    */
-  public <PatternFilenameRegionMatchLocation> int doubleClick(PatternFilenameRegionMatchLocation target, int modifiers)
-          throws FindFailed {
+  public <PFRML> int doubleClick(PFRML target, int modifiers) throws FindFailed {
     Location loc = getLocationFromTarget(target);
     int ret = Mouse.click(loc, InputEvent.BUTTON1_MASK, modifiers, true, this);
 
@@ -2937,12 +2980,12 @@ public class Region {
    * right click at the given target location<br> Pattern or Filename - do a find before and use the match<br> Region -
    * position at center<br> Match - position at match's targetOffset<br > Location - position at that point<br>
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location
+   * @param target
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed for Pattern or Filename
    */
-  public <PatternFilenameRegionMatchLocation> int rightClick(PatternFilenameRegionMatchLocation target)
-          throws FindFailed {
+  public <PFRML> int rightClick(PFRML target) throws FindFailed {
     return rightClick(target, 0);
   }
 
@@ -2951,13 +2994,13 @@ public class Region {
    * Pattern or Filename - do a find before and use the match<br> Region - position at center<br > Match - position at
    * match's targetOffset<br> Location - position at that point<br>
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location 
+   * @param target 
    * @param modifiers the value of the resulting bitmask (see KeyModifier)
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed for Pattern or Filename
    */
-  public <PatternFilenameRegionMatchLocation> int rightClick(PatternFilenameRegionMatchLocation target, int modifiers)
-          throws FindFailed {
+    public <PFRML> int rightClick(PFRML target, int modifiers) throws FindFailed {
     Location loc = getLocationFromTarget(target);
     int ret = Mouse.click(loc, InputEvent.BUTTON3_MASK, modifiers, false, this);
 
@@ -2980,12 +3023,12 @@ public class Region {
    * Drag from region's last match and drop at given target <br>applying Settings.DelayAfterDrag and DelayBeforeDrop
    * <br> using left mouse button
    *
-   * @param <PatternFilenameRegionMatchLocation> target destination position
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location
+   * @param target
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed if the Find operation failed
    */
-  public <PatternFilenameRegionMatchLocation> int dragDrop(PatternFilenameRegionMatchLocation target)
-          throws FindFailed {
+  public <PFRML> int dragDrop(PFRML target) throws FindFailed {
     return dragDrop(lastMatch, target);
   }
 
@@ -2993,13 +3036,13 @@ public class Region {
    * Drag from a position and drop to another using left mouse button<br>applying Settings.DelayAfterDrag and
    * DelayBeforeDrop
    *
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location
    * @param t1 source position
    * @param t2 destination position
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed if the Find operation failed
    */
-  public <PatternFilenameRegionMatchLocation> int dragDrop(PatternFilenameRegionMatchLocation t1, PatternFilenameRegionMatchLocation t2)
-          throws FindFailed {
+  public <PFRML> int dragDrop(PFRML t1, PFRML t2) throws FindFailed {
     Location loc1 = getLocationFromTarget(t1);
     Location loc2 = getLocationFromTarget(t2);
     if (loc1 != null && loc2 != null) {
@@ -3029,12 +3072,12 @@ public class Region {
    * Prepare a drag action: move mouse to given target <br>press and hold left mouse button <br >wait
    * Settings.DelayAfterDrag
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location 
+   * @param target 
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed
    */
-  public <PatternFilenameRegionMatchLocation> int drag(PatternFilenameRegionMatchLocation target)
-          throws FindFailed {
+  public <PFRML> int drag(PFRML target) throws FindFailed {
     Location loc = getLocationFromTarget(target);
     if (loc != null) {
       IRobot r = loc.getRobotForPoint("drag");
@@ -3055,12 +3098,12 @@ public class Region {
    * finalize a drag action with a drop: move mouse to given target <br>wait Settings.DelayBeforeDrop <br>release the
    * left mouse button
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location
+   * @param target
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed
    */
-  public <PatternFilenameRegionMatchLocation> int dropAt(PatternFilenameRegionMatchLocation target)
-          throws FindFailed {
+  public <PFRML> int dropAt(PFRML target) throws FindFailed {
     Location loc = getLocationFromTarget(target);
     if (loc != null) {
       IRobot r = loc.getRobotForPoint("drop");
@@ -3126,13 +3169,12 @@ public class Region {
    * and use the match<br> Region - position at center<br> Match - position at match's targetOffset<br>
    * Location - position at that point<br>
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location
    * @param target
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed for Pattern or Filename
    */
-  public <PatternFilenameRegionMatchLocation> int mouseMove(PatternFilenameRegionMatchLocation target)
-          throws FindFailed {
+  public <PFRML> int mouseMove(PFRML target) throws FindFailed {
     Location loc = getLocationFromTarget(target);
     return Mouse.move(loc, this);
   }
@@ -3154,14 +3196,14 @@ public class Region {
    * move the mouse pointer to the given target location<br> and move the wheel the given steps in the given direction:
    * <br>Button.WHEEL_DOWN, Button.WHEEL_UP
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location target
+   * @param target
    * @param direction to move the wheel
    * @param steps the number of steps
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed if the Find operation failed
    */
-  public <PatternFilenameRegionMatchLocation> int wheel(PatternFilenameRegionMatchLocation target, int direction, int steps)
-          throws FindFailed {
+  public <PFRML> int wheel(PFRML target, int direction, int steps) throws FindFailed {
     Location loc = getLocationFromTarget(target);
     if (loc != null) {
       Mouse.get().use(this);
@@ -3427,13 +3469,13 @@ public class Region {
    * character/key after another using keyDown/keyUp <br>about the usable Key constants see keyDown(keys)
    * <br>Class Key only provides a subset of a US-QWERTY PC keyboard layout
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location 
+   * @param target
    * @param text containing characters and/or Key constants
    * @return 1 if possible, 0 otherwise
    * @throws FindFailed
    */
-  public <PatternFilenameRegionMatchLocation> int type(PatternFilenameRegionMatchLocation target, String text)
-          throws FindFailed {
+  public <PFRML> int type(PFRML target, String text) throws FindFailed {
     return keyin(target, text, 0);
   }
 
@@ -3442,13 +3484,14 @@ public class Region {
    * character/key after another using keyDown/keyUp <br>while holding down the given modifier keys<br>about the usable
    * Key constants see keyDown(keys) <br>Class Key only provides a subset of a US-QWERTY PC keyboard layout
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location 
+   * @param target
    * @param text containing characters and/or Key constants
    * @param modifiers constants according to class KeyModifiers
    * @return 1 if possible, 0 otherwise
+   * @throws org.sikuli.script.FindFailed
    */
-  public <PatternFilenameRegionMatchLocation> int type(PatternFilenameRegionMatchLocation target, String text, int modifiers)
-          throws FindFailed {
+  public <PFRML> int type(PFRML target, String text, int modifiers) throws FindFailed {
     return keyin(target, text, modifiers);
   }
 
@@ -3457,18 +3500,19 @@ public class Region {
    * character/key after another using keyDown/keyUp <br>while holding down the given modifier keys<br>about the usable
    * Key constants see keyDown(keys) <br>Class Key only provides a subset of a US-QWERTY PC keyboard layout
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location 
+   * @param target 
    * @param text containing characters and/or Key constants
    * @param modifiers constants according to class Key - combine using +
    * @return 1 if possible, 0 otherwise
+   * @throws org.sikuli.script.FindFailed
    */
-  public <PatternFilenameRegionMatchLocation> int type(PatternFilenameRegionMatchLocation target, String text, String modifiers)
-          throws FindFailed {
+  public <PFRML> int type(PFRML target, String text, String modifiers) throws FindFailed {
     int modifiersNew = Key.convertModifiers(modifiers);
     return keyin(target, text, modifiersNew);
   }
 
-  private <PatternFilenameRegionMatchLocation> int keyin(PatternFilenameRegionMatchLocation target, String text, int modifiers)
+  private <PFRML> int keyin(PFRML target, String text, int modifiers)
           throws FindFailed {
     if (target != null && 0 == click(target, 0)) {
       return 0;
@@ -3540,13 +3584,13 @@ public class Region {
    * first does a click(target) at the given target position to gain focus/carret <br> and then pastes the text <br>
    * using the clipboard and strg/ctrl/cmd-v (paste keyboard shortcut)
    *
-   * @param <PatternFilenameRegionMatchLocation> target
+   * @param <PFRML> Pattern, Filename, Text, Region, Match or Location target
+   * @param target
    * @param text a string, which might contain unicode characters
    * @return 0 if possible, 1 otherwise
    * @throws FindFailed
    */
-  public <PatternFilenameRegionMatchLocation> int paste(PatternFilenameRegionMatchLocation target, String text)
-          throws FindFailed {
+  public <PFRML> int paste(PFRML target, String text) throws FindFailed {
     click(target, 0);
     if (text != null) {
       App.setClipboard(text);
diff --git a/API/src/main/java/org/sikuli/script/SikuliEventAdapter.java b/API/src/main/java/org/sikuli/script/SikuliEventAdapter.java
index 5573dfd..45c3a29 100755
--- a/API/src/main/java/org/sikuli/script/SikuliEventAdapter.java
+++ b/API/src/main/java/org/sikuli/script/SikuliEventAdapter.java
@@ -1,30 +1,30 @@
 /*
- * Copyright 2010-2013, Sikuli.org
+ * Copyright 2010-2014, Sikuli.org, sikulix.com
  * Released under the MIT License.
  *
- * modified RaiMan 2013
+ * modified RaiMan 2014
  */
 package org.sikuli.script;
 
 /**
  *
- * @deprecated use ObserverCallBack instead
+ * @deprecated use @{link ObserverCallBack} instead
  */
 @Deprecated
 public class SikuliEventAdapter implements SikuliEventObserver {
 
   @Override
-  public void targetAppeared(ObserveAppear e) {
+  public void targetAppeared(ObserveEvent e) {
     appeared(e);
   }
 
   @Override
-  public void targetVanished(ObserveVanish e) {
+  public void targetVanished(ObserveEvent e) {
     vanished(e);
   }
 
   @Override
-  public void targetChanged(ObserveChange e) {
+  public void targetChanged(ObserveEvent e) {
     changed(e);
   }
 
diff --git a/API/src/main/java/org/sikuli/script/SikuliEventObserver.java b/API/src/main/java/org/sikuli/script/SikuliEventObserver.java
index 2b40b03..6f0ae0e 100755
--- a/API/src/main/java/org/sikuli/script/SikuliEventObserver.java
+++ b/API/src/main/java/org/sikuli/script/SikuliEventObserver.java
@@ -8,12 +8,13 @@ package org.sikuli.script;
 
 import java.util.*;
 
-
 /**
- * CANDIDATE FOR DEPRECATION - ONLY HERE TO BE BACKWARD COMPATIBLE
+ * see @{link SikuliEventAdapter}
+ * @deprecated
  */
+ at Deprecated
 public interface SikuliEventObserver extends EventListener {
-   public void targetAppeared(ObserveAppear e);
-   public void targetVanished(ObserveVanish e);
-   public void targetChanged(ObserveChange e);
+   public void targetAppeared(ObserveEvent e);
+   public void targetVanished(ObserveEvent e);
+   public void targetChanged(ObserveEvent e);
 }
diff --git a/API/src/main/java/org/sikuli/script/SikuliX.java b/API/src/main/java/org/sikuli/script/SikuliX.java
index 18b4589..640b41a 100644
--- a/API/src/main/java/org/sikuli/script/SikuliX.java
+++ b/API/src/main/java/org/sikuli/script/SikuliX.java
@@ -49,7 +49,7 @@ public class SikuliX {
   public static void cleanUp(int n) {
     Debug.log(3, me + "cleanUp: %d", n);
     ScreenHighlighter.closeAll();
-    Observing.stopRunningObservers();
+    Observing.cleanUp();
     if (CommandArgs.isIDE()) {
       //TODO reset selected options to defaults
     }
diff --git a/Basics/src/main/java/org/sikuli/basics/Settings.java b/Basics/src/main/java/org/sikuli/basics/Settings.java
index a53a0cd..8259615 100644
--- a/Basics/src/main/java/org/sikuli/basics/Settings.java
+++ b/Basics/src/main/java/org/sikuli/basics/Settings.java
@@ -230,7 +230,7 @@ public class Settings {
   public static float WaitScanRate = 3f; // frames per second
   public static float ObserveScanRate = 3f; // frames per second
   public static int ObserveMinChangedPixels = 50; // in pixels
-  public static int WaitForVanish = 1; // wait 1 second for visual to vanish after action
+  public static int RepeatWaitTime = 1; // wait 1 second for visual to vanish after action
   public static double MinSimilarity = 0.7;
   public static boolean CheckLastSeen = true;
   public static float CheckLastSeenSimilar = 0.95f;
diff --git a/Jython/src/main/java/org/sikuli/scriptrunner/JythonScriptRunner.java b/Jython/src/main/java/org/sikuli/scriptrunner/JythonScriptRunner.java
index 7f8b222..660e970 100644
--- a/Jython/src/main/java/org/sikuli/scriptrunner/JythonScriptRunner.java
+++ b/Jython/src/main/java/org/sikuli/scriptrunner/JythonScriptRunner.java
@@ -56,9 +56,9 @@ public class JythonScriptRunner implements IScriptRunner {
   private static String[] SCRIPT_HEADER = new String[]{
     "# -*- coding: utf-8 -*- ",
     "import sys",
-    "print '[debug] Running Jython:', sys.version.split('\\n')[0]",
     "from __future__ import with_statement",
     "from sikuli import *",
+    "Debug.log(3, 'Running Jython: ' + sys.version.split('\\n')[0])",
     "use() #resetROI()",
     "setShowActions(False)"
   };

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/sikuli.git



More information about the pkg-java-commits mailing list