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

Gilles Filippini pini at moszumanska.debian.org
Sun Jun 29 19:26:26 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 4e442655aaaec5b59bc19d8292143221494f09fb
Author: Raimund Hocke <rmhdevelop at me.com>
Date:   Wed Feb 26 19:20:16 2014 +0100

    ongoing: getting observe to work
---
 .../main/java/org/sikuli/script/ObserveChange.java |   3 +-
 .../main/java/org/sikuli/script/ObserveEvent.java  |  66 +++--
 API/src/main/java/org/sikuli/script/Observer.java  | 330 +++++++++++----------
 API/src/main/java/org/sikuli/script/Observing.java | 105 +++++--
 API/src/main/java/org/sikuli/script/Region.java    |  93 +++---
 API/src/main/java/org/sikuli/script/SikuliX.java   |   1 +
 Basics/src/main/resources/Lib/sikuli/Region.py     |  16 +-
 7 files changed, 384 insertions(+), 230 deletions(-)

diff --git a/API/src/main/java/org/sikuli/script/ObserveChange.java b/API/src/main/java/org/sikuli/script/ObserveChange.java
index 7d7ba39..0c2ca74 100755
--- a/API/src/main/java/org/sikuli/script/ObserveChange.java
+++ b/API/src/main/java/org/sikuli/script/ObserveChange.java
@@ -12,10 +12,11 @@ import java.util.List;
  * INTERNAL USE
  */
 public class ObserveChange extends ObserveEvent {
-   public ObserveChange(List<Match> results, Region r){
+   public ObserveChange(List<Match> results, Region r, int eventIndex){
       type = Type.CHANGE;
       setChanges(results);
       setRegion(r);
+      setIndex(eventIndex);
    }
 
 	@Override
diff --git a/API/src/main/java/org/sikuli/script/ObserveEvent.java b/API/src/main/java/org/sikuli/script/ObserveEvent.java
index 2dd2361..1713b4b 100755
--- a/API/src/main/java/org/sikuli/script/ObserveEvent.java
+++ b/API/src/main/java/org/sikuli/script/ObserveEvent.java
@@ -21,9 +21,10 @@ public class ObserveEvent {
   public Type type;
 
   private Region region = null;
+  private Object pattern = null;
   private Match match = null;
+  private int index = -1;
   private List<Match> changes = null;
-  private Object pattern = null;
 
   public ObserveEvent() {
   }
@@ -50,7 +51,7 @@ public class ObserveEvent {
   }
 
   protected void setRegion(Region r) {
-    region = new Region(r);
+    region = r;
   }
 
   /**
@@ -62,7 +63,21 @@ public class ObserveEvent {
   }
 
   protected void setMatch(Match m) {
-    match = new Match(m);
+    if (null != m) {
+      match = new Match(m);
+    }
+  }
+
+  /**
+   *
+   * @return the index in the observer map in Observer (CHANGE)
+   */
+  public int getIndex() {
+    return index;
+  }
+
+  public void setIndex(int index) {
+    this.index = index;
   }
 
   /**
@@ -74,8 +89,10 @@ public class ObserveEvent {
   }
 
   protected void setChanges(List<Match> c) {
-		changes = new ArrayList<Match>();
-    changes.addAll(c);
+    if (c != null) {
+      changes = new ArrayList<Match>();
+      changes.addAll(c);
+    }
   }
 
   /**
@@ -83,18 +100,23 @@ public class ObserveEvent {
    * @return the used pattern for this event's observing
    */
   public Pattern getPattern() {
-    if (pattern.getClass().isInstance("")) {
-      return (new Pattern((String) pattern));
-    } else {
-      return (new Pattern((Pattern) pattern));
+    if (null != pattern) {
+      if (pattern.getClass().isInstance("")) {
+        return (new Pattern((String) pattern));
+      } else {
+        return (new Pattern((Pattern) pattern));
+      }
     }
+    return null;
   }
 
   protected void setPattern(Object p) {
-    if (p.getClass().isInstance("")) {
-			pattern = new Pattern((String) p);
-    } else {
-			pattern = new Pattern((Pattern) p);
+    if (null != p) {
+      if (p.getClass().isInstance("")) {
+        pattern = new Pattern((String) p);
+      } else {
+        pattern = new Pattern((Pattern) p);
+      }
     }
   }
 
@@ -112,16 +134,15 @@ public class ObserveEvent {
    * @param secs
    */
   public void repeat(long secs) {
-    region.getEvtMgr().repeat(type, pattern, match, secs);
+    region.getObserver().repeat(type, pattern, match, secs);
   }
 
   /**
-   * only for (APPEAR, VANISH)
    * @return the number how often this event has already been triggered until now
    */
   public int getCount() {
     if (type == Type.CHANGE) {
-      return 0;
+      return region.getObserver().getChangedCount(index);
     } else {
       return region.getEvtMgr().getCount(pattern);
     }
@@ -134,9 +155,18 @@ public class ObserveEvent {
     region.stopObserver();
   }
 
+  public void stopObserver(String msg) {
+    region.stopObserver(msg);
+  }
+
   @Override
   public String toString() {
-    return String.format("SikuliEvent(%s) on %s with %s having last match: %s",
-            type, region, pattern, match);
+    if (type == Type.CHANGE) {
+      return String.format("Event(%s) on: %s with: %d count: %d", 
+            type, region, index, getCount());
+    } else {
+      return String.format("Event(%s) on: %s with: %s match: %s count: %d",
+            type, region, pattern, match, getCount());
+    }
   }
 }
diff --git a/API/src/main/java/org/sikuli/script/Observer.java b/API/src/main/java/org/sikuli/script/Observer.java
index c2e1c88..ed907ad 100755
--- a/API/src/main/java/org/sikuli/script/Observer.java
+++ b/API/src/main/java/org/sikuli/script/Observer.java
@@ -17,68 +17,76 @@ import org.sikuli.natives.Mat;
 import org.sikuli.natives.Vision;
 
 /**
- * INTERNAL USE
- * implements the observe action for a region and calls the ObserverCallBacks
+ * INTERNAL USE implements the observe action for a region and calls the ObserverCallBacks
  */
 public class Observer {
 
+  private static String me = "Observer";
+  private static int lvl = 3;
+
+  private static void log(int level, String message, Object... args) {
+    Debug.logx(level, "", me + ": " + message, args);
+  }
+
   protected enum State {
+
     FIRST, UNKNOWN, MISSING, APPEARED, VANISHED, REPEAT
   }
-  private Region _region;
-  private Mat _lastImgMat = null;
-  private org.opencv.core.Mat _lastImageMat = null;
-  private Map<Object, State> _state;
-  private Map<Object, Long> _wait;
-  private Map<Object, Integer> _count;
-  private Map<Object, Match> _lastMatch;
-  private Map<Object, String> _names;
-//  private Map<Object, SikuliEventObserver> _appearOb, _vanishOb;
-  private Map<Object, Object> _appearOb, _vanishOb;
-//  private Map<Integer, SikuliEventObserver> _changeOb;
-  private Map<Integer, Object> _changeOb;
-  private Map<Integer, Integer> _countc;
-  private Map<Integer, String> _cnames;
-  private int _minChanges;
+  private Region observedRegion;
+  private Mat lastImgMat = null;
+  private org.opencv.core.Mat lastImageMat = null;
+  private Map<Object, State> eventStates;
+  private Map<Object, Long> repeatWaitTimes;
+  private Map<Object, Integer> happenedCount;
+  private Map<Object, Match> lastMatches;
+  private Map<Object, String> eventNames;
+  private Map<Object, Object> appearCallBacks, vanishCallBacks;
+  private Map<Integer, Object> changeCallBacks;
+  private Map<Integer, Integer> changedCount;
+  private Map<Integer, String> onChangeNames;
+  private int minChanges;
   private boolean sthgLeft;
+  private boolean shouldCheckChanges;
 
   public Observer(Region region) {
-    _region = region;
-    _state = new HashMap<Object, State>();
-    _wait = new HashMap<Object, Long>();
-    _count = new HashMap<Object, Integer>();
-    _lastMatch = new HashMap<Object, Match>();
-    _names = new HashMap<Object, String>();
-//    _appearOb = new HashMap<Object, SikuliEventObserver>();
-//    _vanishOb = new HashMap<Object, SikuliEventObserver>();
-//    _changeOb = new HashMap<Integer, SikuliEventObserver>();
-    _appearOb = new HashMap<Object, Object>();
-    _vanishOb = new HashMap<Object, Object>();
-    _changeOb = new HashMap<Integer, Object>();
-    _countc = new HashMap<Integer, Integer>();
-    _cnames = new HashMap<Integer, String>();
+    observedRegion = region;
+    eventStates = new HashMap<Object, State>();
+    repeatWaitTimes = new HashMap<Object, Long>();
+    happenedCount = new HashMap<Object, Integer>();
+    lastMatches = new HashMap<Object, Match>();
+    eventNames = new HashMap<Object, String>();
+    appearCallBacks = new HashMap<Object, Object>();
+    vanishCallBacks = new HashMap<Object, Object>();
+    changeCallBacks = new HashMap<Integer, Object>();
+    changedCount = new HashMap<Integer, Integer>();
+    onChangeNames = new HashMap<Integer, String>();
   }
 
   public void initialize() {
-    Debug.log(2, "SikuliEventManager: resetting observe states for " + _region.toStringShort());
+    log(3, "resetting observe states for " + observedRegion.toStringShort());
     sthgLeft = true;
-    for (Object ptn : _state.keySet()) {
-      _state.put(ptn, State.FIRST);
-      _count.put(ptn, 0);
+    shouldCheckChanges = true;
+    for (Object ptn : eventStates.keySet()) {
+      eventStates.put(ptn, State.FIRST);
+      happenedCount.put(ptn, 0);
     }
-    for (int n : _changeOb.keySet()) {
-      _countc.put(n, 0);
+    for (int n : changeCallBacks.keySet()) {
+      changedCount.put(n, 0);
     }
   }
 
   public void setRegion(Region reg) {
-    _region = reg;
+    observedRegion = reg;
   }
 
   public int getCount(Object ptn) {
-    return _count.get(ptn);
+    return happenedCount.get(ptn);
   }
 
+  public int getChangedCount(int index) {
+    return changedCount.get(index);
+  }
+  
   private <PSC> float getSimiliarity(PSC ptn) {
     float similarity = -1f;
     if (ptn instanceof Pattern) {
@@ -91,64 +99,67 @@ public class Observer {
   }
 
   public <PSC> void addAppearObserver(PSC ptn, ObserverCallBack ob, String name) {
-    _appearOb.put(ptn, ob);
-    _state.put(ptn, State.FIRST);
-    _names.put(ptn, name);
+    appearCallBacks.put(ptn, ob);
+    eventStates.put(ptn, State.FIRST);
+    eventNames.put(ptn, name);
   }
 
   public <PSC> void removeAppearObserver(PSC ptn) {
-    Observing.remove(_names.get(ptn));
-    _names.remove(ptn);
-    _appearOb.remove(ptn);
-    _state.remove(ptn);
+    Observing.remove(eventNames.get(ptn));
+    eventNames.remove(ptn);
+    appearCallBacks.remove(ptn);
+    eventStates.remove(ptn);
   }
 
   public <PSC> void addVanishObserver(PSC ptn, ObserverCallBack ob, String name) {
-    _vanishOb.put(ptn, ob);
-    _state.put(ptn, State.FIRST);
-    _names.put(ptn, name);
+    vanishCallBacks.put(ptn, ob);
+    eventStates.put(ptn, State.FIRST);
+    eventNames.put(ptn, name);
   }
 
   public <PSC> void removeVanishObserver(PSC ptn) {
-    Observing.remove(_names.get(ptn));
-    _names.remove(ptn);
-    _vanishOb.remove(ptn);
-    _state.remove(ptn);
+    Observing.remove(eventNames.get(ptn));
+    eventNames.remove(ptn);
+    vanishCallBacks.remove(ptn);
+    eventStates.remove(ptn);
   }
 
   private void callAppearObserver(Object ptn, Match m) {
-    ObserveAppear se = new ObserveAppear(ptn, m, _region);
-    Object ao = _appearOb.get(ptn);
-    Observing.addEvent(_names.get(ptn), se);
-    if (ao != null && ao instanceof ObserverCallBack) {
-      ((ObserverCallBack)_appearOb.get(ptn)).appeared(se);
+    log(lvl, "appeared: %s with: %s\nat: %s", eventNames.get(ptn), ptn, m);
+    ObserveAppear observeEvent = new ObserveAppear(ptn, m, observedRegion);
+    Object callBack = appearCallBacks.get(ptn);
+    Observing.addEvent(eventNames.get(ptn), observeEvent);
+    if (callBack != null && callBack instanceof ObserverCallBack) {
+      log(lvl, "running call back");
+      ((ObserverCallBack) appearCallBacks.get(ptn)).appeared(observeEvent);
     }
   }
 
   private void callVanishObserver(Object ptn, Match m) {
-    ObserveVanish se = new ObserveVanish(ptn, m, _region);
-    Object ao = _vanishOb.get(ptn);
-    Observing.addEvent(_names.get(ptn), se);
-    if (ao != null && ao instanceof ObserverCallBack) {
-      ((ObserverCallBack)_vanishOb.get(ptn)).vanished(se);
+    log(lvl, "vanished: %s with: %s\nat: %s", eventNames.get(ptn), ptn, m);
+    ObserveVanish observeEvent = new ObserveVanish(ptn, m, observedRegion);
+    Object callBack = vanishCallBacks.get(ptn);
+    Observing.addEvent(eventNames.get(ptn), observeEvent);
+    if (callBack != null && callBack instanceof ObserverCallBack) {
+      log(lvl, "running call back");
+      ((ObserverCallBack) vanishCallBacks.get(ptn)).vanished(observeEvent);
     }
   }
 
   private void checkPatterns(ScreenImage simg) {
     Finder finder = null;
     if (Settings.UseImageFinder) {
-      finder = new ImageFinder(_region);
+      finder = new ImageFinder(observedRegion);
       ((ImageFinder) finder).setIsMultiFinder();
-    }
-    else {
-      finder = new Finder(simg, _region);
+    } else {
+      finder = new Finder(simg, observedRegion);
     }
     String imgOK;
-    Debug.log(3, "observe: checkPatterns entry: sthgLeft: %s isObserving: %s", sthgLeft, _region.isObserving());
-    for (Object ptn : _state.keySet()) {
-      if (_state.get(ptn) != State.FIRST &&
-          _state.get(ptn) != State.UNKNOWN &&
-          _state.get(ptn) != State.REPEAT) {
+    log(lvl + 1, "checkPatterns entry: sthgLeft: %s isObserving: %s", sthgLeft, observedRegion.isObserving());
+    for (Object ptn : eventStates.keySet()) {
+      if (eventStates.get(ptn) != State.FIRST
+              && eventStates.get(ptn) != State.UNKNOWN
+              && eventStates.get(ptn) != State.REPEAT) {
         continue;
       }
       imgOK = null;
@@ -157,7 +168,7 @@ public class Observer {
         Image img = Image.create((String) ptn);
         if (img.isValid()) {
           imgOK = finder.find(img);
-        } else if (img.isText()){
+        } else if (img.isText()) {
           imgOK = finder.findText((String) ptn);
         }
       } else if (ptn instanceof Pattern) {
@@ -167,24 +178,24 @@ public class Observer {
       }
       if (null == imgOK) {
         Debug.error("EventMgr: checkPatterns: Image not valid", ptn);
-        _state.put(ptn, State.MISSING);
+        eventStates.put(ptn, State.MISSING);
         continue;
       }
-      if (_state.get(ptn) == State.REPEAT) {
-        Debug.log(3, "repeat: checking");
-        if (_lastMatch.get(ptn).exists(ptn) != null) {
-          if ((new Date()).getTime() > _wait.get(ptn)) {
-            _state.put(ptn, State.APPEARED);
-            Debug.log(3, "repeat: vanish timeout");
+      if (eventStates.get(ptn) == State.REPEAT) {
+        log(lvl, "repeat: checking");
+        if (lastMatches.get(ptn).exists(ptn) != null) {
+          if ((new Date()).getTime() > repeatWaitTimes.get(ptn)) {
+            eventStates.put(ptn, State.APPEARED);
+            log(lvl, "repeat: vanish timeout");
             // time out
           } else {
             sthgLeft = true;
           }
           continue; // not vanished within given time or still there
         } else {
-          _state.put(ptn, State.UNKNOWN);
+          eventStates.put(ptn, State.UNKNOWN);
           sthgLeft = true;
-          Debug.log(3, "repeat: has vanished");
+          log(lvl, "repeat: has vanished");
           continue; // has vanished, repeat
         }
       }
@@ -194,43 +205,43 @@ public class Observer {
         m = finder.next();
         if (m.getScore() >= getSimiliarity(ptn)) {
           hasMatch = true;
-          _lastMatch.put(ptn, m);
+          lastMatches.put(ptn, m);
         }
       }
       if (hasMatch) {
-        Debug.log(2, "EventMgr: checkPatterns: " + ptn.toString() + " match: " +
-                m.toStringShort() + " in " + _region.toStringShort());
-      } else if (_state.get(ptn) == State.FIRST) {
-        Debug.log(2, "EventMgr: checkPatterns: " + ptn.toString() + " match: " +
-                "NO" + " in " + _region.toStringShort());
-        _state.put(ptn, State.UNKNOWN);
+        log(lvl + 1, "checkPatterns: " + ptn.toString() + " match: "
+                + m.toStringShort() + " in " + observedRegion.toStringShort());
+      } else if (eventStates.get(ptn) == State.FIRST) {
+        log(lvl + 1, "checkPatterns: " + ptn.toString() + " match: "
+                + "NO" + " in " + observedRegion.toStringShort());
+        eventStates.put(ptn, State.UNKNOWN);
       }
-      if (_appearOb.containsKey(ptn)) {
-        if (_state.get(ptn) != State.APPEARED) {
+      if (appearCallBacks.containsKey(ptn)) {
+        if (eventStates.get(ptn) != State.APPEARED) {
           if (hasMatch) {
-            _state.put(ptn, State.APPEARED);
-            _count.put(ptn, _count.get(ptn) + 1);
+            eventStates.put(ptn, State.APPEARED);
+            happenedCount.put(ptn, happenedCount.get(ptn) + 1);
             callAppearObserver(ptn, m);
           } else {
             sthgLeft = true;
           }
         }
-      } else if (_vanishOb.containsKey(ptn)) {
-        if (_state.get(ptn) != State.VANISHED) {
+      } else if (vanishCallBacks.containsKey(ptn)) {
+        if (eventStates.get(ptn) != State.VANISHED) {
           if (!hasMatch) {
-            _state.put(ptn, State.VANISHED);
-            _count.put(ptn, _count.get(ptn) + 1);
-            callVanishObserver(ptn, _lastMatch.get(ptn));
+            eventStates.put(ptn, State.VANISHED);
+            happenedCount.put(ptn, happenedCount.get(ptn) + 1);
+            callVanishObserver(ptn, lastMatches.get(ptn));
           } else {
             sthgLeft = true;
           }
         }
       }
-      if (!_region.isObserving()) {
+      if (!observedRegion.isObserving()) {
         break;
       }
     }
-    Debug.log(3, "observe: checkPatterns exit: sthgLeft: %s isObserving: %s", sthgLeft, _region.isObserving());
+    log(lvl + 1, "checkPatterns exit: sthgLeft: %s isObserving: %s", sthgLeft, observedRegion.isObserving());
   }
 
   public void repeat(ObserveEvent.Type type, Object pattern, Match match, long secs) {
@@ -239,33 +250,33 @@ public class Observer {
     } else if (type == ObserveEvent.Type.VANISH) {
       Debug.error("EventMgr: repeat: not supported for VANISH");
     } else if (type == ObserveEvent.Type.APPEAR) {
-      _state.put(pattern, State.REPEAT);
+      eventStates.put(pattern, State.REPEAT);
       if (secs <= 0) {
-        secs = (long) _region.getWaitForVanish();
+        secs = (long) observedRegion.getWaitForVanish();
       }
-      _wait.put(pattern, (new Date()).getTime() + 1000 * secs);
-      Debug.log(2, "EventMgr: repeat: requested for APPEAR: " +
-              pattern.toString() + " at " + match.toStringShort() + " after " + secs + " seconds");
+      repeatWaitTimes.put(pattern, (new Date()).getTime() + 1000 * secs);
+      log(lvl, "repeat: requested for APPEAR: "
+              + pattern.toString() + " at " + match.toStringShort() + " after " + secs + " seconds");
       sthgLeft = true;
     }
   }
 
   public void addChangeObserver(int threshold, ObserverCallBack ob, String name) {
-    _changeOb.put(new Integer(threshold), ob);
-    _minChanges = getMinChanges();
-    _cnames.put(threshold, name);
+    changeCallBacks.put(new Integer(threshold), ob);
+    minChanges = getMinChanges();
+    onChangeNames.put(threshold, name);
   }
 
   public void removeChangeObserver(int threshold) {
-    Observing.remove(_cnames.get(threshold));
-    _names.remove(threshold);
-    _changeOb.remove(new Integer(threshold));
-    _minChanges = getMinChanges();
+    Observing.remove(onChangeNames.get(threshold));
+    eventNames.remove(threshold);
+    changeCallBacks.remove(new Integer(threshold));
+    minChanges = getMinChanges();
   }
 
   private int getMinChanges() {
     int min = Integer.MAX_VALUE;
-    for (Integer n : _changeOb.keySet()) {
+    for (Integer n : changeCallBacks.keySet()) {
       if (n < min) {
         min = n;
       }
@@ -273,88 +284,101 @@ public class Observer {
     return min;
   }
 
-  private void callChangeObserver(FindResults results) throws AWTException {
-    for (Integer n : _changeOb.keySet()) {
+  private int callChangeObserver(FindResults results) {
+    int activeChangeCallBacks = 0;
+    log(lvl, "changes: %d in: %s", results.size(), observedRegion);
+    for (Integer n : changeCallBacks.keySet()) {
+      if (changedCount.get(n) == -1) {
+        continue;
+      }
+      activeChangeCallBacks++;
       List<Match> changes = new ArrayList<Match>();
       for (int i = 0; i < results.size(); i++) {
         FindResult r = results.get(i);
         if (r.getW() * r.getH() >= n) {
-          changes.add(_region.toGlobalCoord(new Match(r, _region.getScreen())));
+          changes.add(observedRegion.toGlobalCoord(new Match(r, observedRegion.getScreen())));
         }
       }
       if (changes.size() > 0) {
-        _countc.put(n, _countc.get(n) + 1);
-        ObserveChange se = new ObserveChange(changes, _region);
-        Object ao = _changeOb.get(n);
-        Observing.addEvent(_cnames.get(n), se);
-        if (ao instanceof ObserverCallBack) {
-          ((ObserverCallBack)_changeOb.get(n)).changed(se);
+        changedCount.put(n, changedCount.get(n) + 1);
+        ObserveChange observeEvent = new ObserveChange(changes, observedRegion, n);
+        Object callBack = changeCallBacks.get(n);
+        Observing.addEvent(onChangeNames.get(n), observeEvent);
+        if (callBack != null && callBack instanceof ObserverCallBack) {
+          log(lvl, "running call back");
+          ((ObserverCallBack) changeCallBacks.get(n)).changed(observeEvent);
+        } else {
+          // onChange only repeated if CallBack given
+          changedCount.put(n, -1);
+          activeChangeCallBacks--;
         }
       }
     }
+    return activeChangeCallBacks;
   }
 
-  private void checkChanges(ScreenImage img) {
+  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 == null) {
+        lastImageMat = new org.opencv.core.Mat();
       }
-      if (_lastImageMat.empty()) {
-        _lastImageMat = Image.createMat(img.getImage());
-        return;
+      if (lastImageMat.empty()) {
+        lastImageMat = Image.createMat(img.getImage());
+        return true;
       }
-      ImageFinder f = new ImageFinder(_lastImageMat);
-      f.setMinChanges(_minChanges);
+      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
-        Debug.log(3, "ChangeObserver: processing changes");
+        log(lvl, "TODO: processing changes");
       }
-      _lastImageMat = current;
-    }
-    else {
-      if (_lastImgMat == null) {
-        _lastImgMat = Image.convertBufferedImageToMat(img.getImage());
-        return;
+      lastImageMat = current;
+    } else {
+      if (lastImgMat == null) {
+        lastImgMat = Image.convertBufferedImageToMat(img.getImage());
+        return true;
       }
       FindInput fin = new FindInput();
-      fin.setSource(_lastImgMat);
+      fin.setSource(lastImgMat);
       Mat target = Image.convertBufferedImageToMat(img.getImage());
       fin.setTarget(target);
-      fin.setSimilarity(_minChanges);
+      fin.setSimilarity(minChanges);
       FindResults results = Vision.findChanges(fin);
-      try {
-        callChangeObserver(results);
-      } catch (AWTException e) {
-        Debug.error("EventMgr: checkChanges: ", e.getMessage());
+      if (results.size() > 0) {
+        if (0 == callChangeObserver(results)) changesObserved = false;
       }
-      _lastImgMat = target;
+      lastImgMat = target;
     }
+    return changesObserved;
   }
 
   public boolean update(ScreenImage simg) {
-    Debug.log(3, "observe: update entry: sthgLeft: %s obs? %s", sthgLeft, _region.isObserving());
+    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 (!_region.isObserving()) {
+      if (!observedRegion.isObserving()) {
         return false;
       }
     }
-    if (_region.isObserving()) {
+    if (observedRegion.isObserving()) {
       ret = sthgLeft;
-      if (_changeOb.size() > 0) {
-        checkChanges(simg);
-        if (!_region.isObserving()) {
+      if (shouldCheckChanges && changeCallBacks.size() > 0) {
+        changesObserved = checkChanges(simg);
+        shouldCheckChanges = changesObserved;
+        if (!observedRegion.isObserving()) {
           return false;
         }
-        ret = true;
+        ret = changesObserved;
       }
     }
-    Debug.log(3, "observe: update exit: ret: %s", ret);
+    log(lvl + 1, "update exit: ret: %s", ret);
     return ret;
   }
-}
\ No newline at end of file
+}
diff --git a/API/src/main/java/org/sikuli/script/Observing.java b/API/src/main/java/org/sikuli/script/Observing.java
index 37bd0dd..8023a77 100644
--- a/API/src/main/java/org/sikuli/script/Observing.java
+++ b/API/src/main/java/org/sikuli/script/Observing.java
@@ -9,7 +9,9 @@ package org.sikuli.script;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
+import java.util.Iterator;
 import java.util.List;
+import org.sikuli.basics.Debug;
 
 /**
  * This class implements a container that globally collects
@@ -17,13 +19,20 @@ import java.util.List;
  */
 public class Observing {
 
+  private static String me = "Observing";
+  private static int lvl = 3;
+
+  private static void log(int level, String message, Object... args) {
+    Debug.logx(level, "", me + ": " + message, args);
+  }
+  
   private static class Entry {
 
-    private final Region region;
-    private final String name;
-    private final ObserveEvent.Type type;
-    private final boolean isActive = true;
-    private final ObserverCallBack obs;
+    private Region region;
+    private String name;
+    private ObserveEvent.Type type;
+    private boolean isActive = true;
+    private ObserverCallBack obs;
 
     protected Entry(String name, Region reg, ObserverCallBack obs, ObserveEvent.Type type) {
       this.name = name;
@@ -31,15 +40,40 @@ public class Observing {
       this.obs = obs;
       this.type = type;
     }
+    
+    protected void destroy() {
+      region = null;
+      name = null;
+      type = null;
+      obs = null;
+    }
   }
 
   public static class Event extends ObserveEvent {
-    private Entry observer;
-    private long time;
+    private Entry observer = null;
+    private long time = 0;
+    
+    protected Event() {
+    }
+    
+    protected Event(Event evt) {
+      observer = evt.observer;
+      time = evt.time;
+      setRegion(evt.getRegion());
+      setMatch(evt.getMatch());
+      setChanges(evt.getChanges());
+      setPattern(evt.getPattern());
+      setIndex(evt.getIndex());
+    }
 
     public long getTime() {
       return time;
     }
+    
+    protected void destroy() {
+      observer = null;
+      time = 0;
+    }
   }
 
   private static List<Entry> observers = Collections.synchronizedList(new ArrayList<Entry>());
@@ -93,6 +127,12 @@ public class Observing {
     if (hasName(name, reg)) {
       return false;
     }
+    Iterator<Entry> iter = observers.iterator();
+    while (iter.hasNext()) {
+      if (iter.next() == null) {
+        iter.remove();
+      }
+    }
     return observers.add(new Entry(name, reg, obs, type));
   }
 
@@ -114,6 +154,9 @@ public class Observing {
 
   private static boolean hasName(String name, Region reg) {
     for (Entry obs : observers) {
+      if (obs.name == null) {
+        continue;
+      }
       if (name.equals(obs.name)) {
         if (reg != null && reg == obs.region) {
           return true;
@@ -167,16 +210,16 @@ public class Observing {
     return true;
   }
 
-  private static void remove(Entry obs) {
+  private static synchronized void remove(Entry obs) {
     if (obs.region != null) {
       obs.region.stopObserver();
     }
-    observers.remove(obs);
     for (Event ev:events) {
       if (ev.observer == obs) {
-        events.remove(ev);
+        ev.destroy();
       }
     }
+    obs.destroy();
   }
 
   private static Entry get(Region reg, String name) {
@@ -200,9 +243,23 @@ public class Observing {
    * @return success
    */
   public static synchronized boolean clear() {
+    log(lvl, "*** requested ***: remove all observers");
     for (Entry e : observers) {
       remove(e);
     }
+    Iterator<Entry> itero = observers.iterator();
+    while (itero.hasNext()) {
+      if (itero.next() == null) {
+        itero.remove();
+      }
+    }
+    Iterator<Event> itere = events.iterator();
+    while (itere.hasNext()) {
+      if (itere.next() == null) {
+        itere.remove();
+      }
+    }
+    log(lvl, "as requested: removed all observers");
     return true;
   }
 
@@ -259,6 +316,7 @@ public class Observing {
    * @return the time of creation
    */
   public static synchronized long addEvent(String name, Object pev) {
+    long t = 0;
     if (pev instanceof ObserveEvent) {
       ObserveEvent evt = (ObserveEvent) new Event();
       ObserveEvent event = (ObserveEvent) pev;
@@ -273,9 +331,15 @@ public class Observing {
     ev.observer = get(null, name);
     ev.time = new Date().getTime();
     if (events.add(ev)) {
-      return ev.time;
+      t = ev.time;
     }
-    return 0;
+    Iterator<Event> iter = events.iterator();
+    while (iter.hasNext()) {
+      if (iter.next() == null) {
+        iter.remove();
+      }
+    }
+    return t;
   }
 
   /**
@@ -294,27 +358,32 @@ public class Observing {
     Event event = null;
     if (obs != null) {
       for (Event ev:events) {
-        if (ev.observer == obs) {
+        if (ev.observer == null) {
+          continue;
+        }
+        if (ev.observer.name.equals(obs.name)) {
           if (event == null) {
             event = ev;
             continue;
           }
           if (ev.time > event.time) {
-            events.remove(event);
+            event.destroy();
             event = ev;
           }
         }
       }
     }
     if (null != event && remove) {
-      events.remove(event);
+      Event ev = new Event(event);
+      event.destroy();
+      event = ev;
     }
     return event;
   }
 
   /**
    * remove and return the latest events for that region <br>
-   * earlier events are removed
+   * earlier events are removed as well
    *
    * @return the array of events or size 0 array if none
    */
@@ -335,7 +404,9 @@ public class Observing {
   public static synchronized Event[] getEvents() {
     List<Event> evts = new ArrayList<Event>();
     for (Entry obs:observers) {
-      evts.add(getEvent(obs.name, false));
+      if (obs.name != null) {
+        evts.add(getEvent(obs.name, false));
+      }
     }
     return evts.toArray(new Event[0]);
   }
diff --git a/API/src/main/java/org/sikuli/script/Region.java b/API/src/main/java/org/sikuli/script/Region.java
index 83f5b93..9343f0e 100755
--- a/API/src/main/java/org/sikuli/script/Region.java
+++ b/API/src/main/java/org/sikuli/script/Region.java
@@ -25,12 +25,12 @@ import org.sikuli.basics.Settings;
 public class Region {
 
   private static String me = "Region";
-  private static String mem = "";
   private static int lvl = 3;
 
   private static void log(int level, String message, Object... args) {
     Debug.logx(level, "", me + ": " + message, args);
   }
+  
   /**
    * The Screen containing the Region
    */
@@ -79,14 +79,14 @@ public class Region {
   /**
    * The {@link Observer} Singleton instance
    */
-  private Observer evtMgr = null;
+  private Observer regionObserver = null;
 
   public Observer getEvtMgr() {
-    return evtMgr;
+    return regionObserver;
   }
 
   public void setEvtMgr(Observer em) {
-    evtMgr = em;
+    regionObserver = em;
   }
   /**
    * The last found {@link Match} in the Region
@@ -328,7 +328,7 @@ public class Region {
   public Region(int X, int Y, int W, int H) {
     this(X, Y, W, H, null);
     this.rows = 0;
-    Debug.log(3, "Region: init: (%d, %d, %d, %d)", X, Y, W, H);
+    log(lvl, "Region: init: (%d, %d, %d, %d)", X, Y, W, H);
   }
 
   /**
@@ -706,6 +706,7 @@ public class Region {
   }
 
   //</editor-fold>
+  
   //<editor-fold defaultstate="collapsed" desc="getters / setters / modificators">
   /**
    *
@@ -1744,7 +1745,7 @@ public class Region {
     if (isOtherScreen()) {
       return this;
     }
-    Debug.history("toggle highlight " + toString() + ": " + toEnable);
+    Debug.action("toggle highlight " + toString() + ": " + toEnable);
     if (toEnable) {
       overlay = new ScreenHighlighter(getScreen());
       overlay.highlight(this);
@@ -1771,7 +1772,7 @@ public class Region {
     if (secs < 0.1) {
       return highlight((int) secs);
     }
-    Debug.history("highlight " + toString() + " for " + secs + " secs");
+    Debug.action("highlight " + toString() + " for " + secs + " secs");
     ScreenHighlighter _overlay = new ScreenHighlighter(getScreen());
     _overlay.highlight(this, secs);
     return this;
@@ -2126,13 +2127,13 @@ public class Region {
   public <PSI> boolean waitVanish(PSI target, double timeout) {
     while (true) {
       try {
-        Debug.log(2, "waiting for " + target + " to vanish");
+        log(lvl, "waiting for " + target + " to vanish");
         RepeatableVanish r = new RepeatableVanish(target);
         if (r.repeat(timeout)) {
-          Debug.log(2, "" + target + " has vanished");
+          log(lvl, "" + target + " has vanished");
           return true;
         }
-        Debug.log(2, "" + target + " has not vanished before timeout");
+        log(lvl, "" + target + " has not vanished before timeout");
         return false;
       } catch (Exception ex) {
         if (ex instanceof IOException) {
@@ -2236,10 +2237,10 @@ public class Region {
         Finder f = new Finder(new Screen().capture(r), r);
         f.find(new Pattern(img).similar(Settings.CheckLastSeenSimilar));
         if (f.hasNext()) {
-          Debug.log(3, "Region: checkLastSeen: still there");
+          log(lvl, "Region: checkLastSeen: still there");
           return f;
         }
-        Debug.log(3, "Region: checkLastSeen: not there");
+        log(lvl, "Region: checkLastSeen: not there");
       }
     }
     if (Settings.UseImageFinder) {
@@ -2459,11 +2460,11 @@ public class Region {
   //</editor-fold>
 
   //<editor-fold defaultstate="collapsed" desc="Observing">
-  private Observer getEventManager() {
-    if (evtMgr == null) {
-      evtMgr = new Observer(this);
+  public Observer getObserver() {
+    if (regionObserver == null) {
+      regionObserver = new Observer(this);
     }
-    return evtMgr;
+    return regionObserver;
   }
 
   /**
@@ -2501,7 +2502,8 @@ public class Region {
 
   private <PSI> String onAppearDo(PSI target, Object observer) {
     String name = Observing.add(this, (ObserverCallBack) observer, ObserveEvent.Type.APPEAR);
-    getEventManager().addAppearObserver(target, (ObserverCallBack) observer, name);
+    getObserver().addAppearObserver(target, (ObserverCallBack) observer, name);
+    log(lvl, "%s: onAppear: %s with: %s", toStringShort(), name, target);
     return name;
   }
 
@@ -2532,7 +2534,8 @@ public class Region {
 
   private <PSI> String onVanishDo(PSI target, Object observer) {
     String name = Observing.add(this, (ObserverCallBack) observer, ObserveEvent.Type.VANISH);
-    getEventManager().addVanishObserver(target, (ObserverCallBack) observer, name);
+    getObserver().addVanishObserver(target, (ObserverCallBack) observer, name);
+    log(lvl, "%s: onVanish: %s with: %s", toStringShort(), name, target);
     return name;
   }
 
@@ -2559,7 +2562,7 @@ public class Region {
    * @return the event's name
    */
   public String onChange(Object observer) {
-    return onChangeDo(rows, observer);
+    return onChangeDo(0, observer);
   }
 
   /**
@@ -2578,7 +2581,8 @@ public class Region {
 
   public String onChangeDo(int threshold, Object observer) {
     String name = Observing.add(this, (ObserverCallBack) observer, ObserveEvent.Type.CHANGE);
-    getEventManager().addChangeObserver(threshold, (ObserverCallBack) observer, name);
+    getObserver().addChangeObserver(threshold, (ObserverCallBack) observer, name);
+    log(lvl, "%s: onChange: %s minSize: %d", toStringShort(), name, threshold);
     return name;
   }
 
@@ -2618,7 +2622,7 @@ public class Region {
   }
 
   private boolean observeDo(double secs) {
-    if (evtMgr == null) {
+    if (regionObserver == null) {
       Debug.error("Region: observe: Nothing to observe (Region might be invalid): " + this.toStringShort());
       return false;
     }
@@ -2627,17 +2631,22 @@ public class Region {
       Debug.error("Region: observe: already running for this region. Only one allowed!");
       return false;
     }
-    Debug.log(2, "Region: observe: starting in " + this.toStringShort() + " for " + secs + " seconds");
+    log(lvl, "observe: starting in " + this.toStringShort() + " for " + secs + " seconds");
     int MaxTimePerScan = (int) (1000.0 / observeScanRate);
     long begin_t = (new Date()).getTime();
-    long stop_t = begin_t + (long) (secs * 1000);
-    evtMgr.initialize();
+    long stop_t;
+    if (secs > Long.MAX_VALUE) {
+      stop_t = Long.MAX_VALUE;
+    } else {
+      stop_t = begin_t + (long) (secs * 1000);
+    }
+    regionObserver.initialize();
     observing = true;
     SikuliX.addRunningObserver(this);
     while (observing && stop_t > (new Date()).getTime()) {
       long before_find = (new Date()).getTime();
       ScreenImage simg = getScreen().capture(x, y, w, h);
-      if (!evtMgr.update(simg)) {
+      if (!regionObserver.update(simg)) {
         observing = false;
         break;
       }
@@ -2651,16 +2660,19 @@ public class Region {
         }
       } catch (Exception e) {
       }
+      log(lvl, "observe: checking again in %s", toStringShort());
     }
+    boolean observeSuccess = false;
     if (observing) {
       observing = false;
-      Debug.log(2, "Region: observe: stopped due to timeout in "
+      log(lvl, "observe: stopped due to timeout in "
               + this.toStringShort() + " for " + secs + " seconds");
     } else {
-      Debug.log(2, "Region: observe: observing has ended for " + this.toStringShort());
+      log(lvl, "observe: ended successfully: " + this.toStringShort());
+      observeSuccess = Observing.hasEvents(this);
     }
     SikuliX.removeRunningObserver(this);
-    return Observing.hasEvents(this);
+    return observeSuccess;
   }
 
   /**
@@ -2675,10 +2687,10 @@ public class Region {
       Debug.error("Region: observeInBackground: already running for this region. Only one allowed!");
       return false;
     }
-    Debug.log(3, "entering observeInBackground for %f secs", secs);
+    log(lvl, "entering observeInBackground for %f secs", secs);
     Thread observeThread = new Thread(new ObserverThread(secs));
     observeThread.start();
-    Debug.log(3, "observeInBackground now running");
+    log(lvl, "observeInBackground now running");
 		return true;
   }
 
@@ -2700,9 +2712,18 @@ public class Region {
    * stops a running observer
    */
   public void stopObserver() {
-    Debug.log(2, "Region: observe: request to stop observer for " + this.toStringShort());
+    log(lvl, "Region: observe: request to stop observer for " + this.toStringShort());
     observing = false;
   }
+
+   /**
+   * stops a running observer printing an info message
+   * @param msg
+   */
+  public void stopObserver(String msg) {
+    Debug.info(msg);
+    stopObserver();
+  }
   //</editor-fold>
 
   //<editor-fold defaultstate="collapsed" desc="Mouse actions - clicking">
@@ -2740,7 +2761,7 @@ public class Region {
    */
   public <PatternFilenameRegionMatchLocation> int hover(PatternFilenameRegionMatchLocation target)
           throws FindFailed {
-    Debug.log(3, "hover: " + target);
+    log(lvl, "hover: " + target);
     return mouseMove(target);
   }
 
@@ -3402,7 +3423,7 @@ public class Region {
       if ((modifiers & KeyModifier.WIN) != 0) {
         modifiers -= KeyModifier.WIN;
         modifiers |= KeyModifier.META;
-        Debug.log(2, "Key.WIN as modifier");
+        log(lvl, "Key.WIN as modifier");
         modWindows = "Windows";
       }
       if (modifiers != 0) {
@@ -3411,7 +3432,7 @@ public class Region {
           modText = modText.replace("Meta", modWindows);
         }
       }
-      Debug.history(modText + "TYPE \"" + showText + "\"");
+      Debug.action(modText + "TYPE \"" + showText + "\"");
       log(lvl, modText + "TYPE \"" + showText + "\"");
       IRobot r = getRobotForRegion();
       int pause = 20 + (Settings.TypeDelay > 1 ? 1000 : (int) (Settings.TypeDelay * 1000));
@@ -3498,7 +3519,7 @@ public class Region {
         return "--- no text ---";
       }
       String textRead = tr.recognize(simg);
-      Debug.log(2, "Region.text: #(" + textRead + ")#");
+      log(lvl, "Region.text: #(" + textRead + ")#");
       return textRead;
     }
     Debug.error("Region.text: text recognition is currently switched off");
@@ -3521,7 +3542,7 @@ public class Region {
         Debug.error("Region.text: text recognition is now switched off");
         return null;
       }
-      Debug.log(2, "Region.listText");
+      log(lvl, "Region.listText");
       return tr.listText(simg, this);
     }
     Debug.error("Region.text: text recognition is currently switched off");
diff --git a/API/src/main/java/org/sikuli/script/SikuliX.java b/API/src/main/java/org/sikuli/script/SikuliX.java
index 84c34b9..25c0bcf 100644
--- a/API/src/main/java/org/sikuli/script/SikuliX.java
+++ b/API/src/main/java/org/sikuli/script/SikuliX.java
@@ -39,6 +39,7 @@ public class SikuliX {
       }
       runningObservers.clear();
     }
+    Observing.clear();
   }
 
   public static void endNormal(int n) {
diff --git a/Basics/src/main/resources/Lib/sikuli/Region.py b/Basics/src/main/resources/Lib/sikuli/Region.py
index 18ac074..860571f 100755
--- a/Basics/src/main/resources/Lib/sikuli/Region.py
+++ b/Basics/src/main/resources/Lib/sikuli/Region.py
@@ -63,19 +63,23 @@ class Region(JRegion):
 
 # observe(): Special setup for Jython
 # assures, that in any case the same region object is used
-    def onAppear(self, target, handler):
+    def onAppear(self, target, handler = None):
+        if not handler:
+            return self.onAppearJ(target, None)
         class AnonyObserver(ObserverCallBack):
             def appeared(self, event):
                 handler(event)
         return self.onAppearJ(target, AnonyObserver())
 
-    def onVanish(self, target, handler):
+    def onVanish(self, target, handler = None):
+        if not handler:
+            return self.onVanishJ(target, None)
         class AnonyObserver(ObserverCallBack):
             def vanished(self, event):
                 handler(event)
-        return self.onVanishJ(self, target, AnonyObserver())
+        return self.onVanishJ(target, AnonyObserver())
 
-    def onChange(self, arg1, arg2=None):
+    def onChange(self, arg1=0, arg2=None):
         if isinstance(arg1, int):
             min_size = arg1
             handler = arg2
@@ -84,10 +88,12 @@ class Region(JRegion):
                 raise Exception("onChange: Invalid parameters set")
             min_size = 0
             handler = arg1
+        if not handler:
+            return self.onChangeJ(min_size, None)
         class AnonyObserver(ObserverCallBack):
             def changed(self, event):
                 handler(event)
         return self.onChangeJ(min_size, AnonyObserver())
 
     def observe(self, time=FOREVER, background=False):
-        self.observeJ(time, background)
\ No newline at end of file
+        return self.observeJ(time, background)
\ No newline at end of file

-- 
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