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 <[email protected]> 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 _______________________________________________ pkg-java-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits

