Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim McNamara <paperless@timmcnamara.co.nz>2010-08-14 01:08:00 (GMT)
committer Tim McNamara <paperless@timmcnamara.co.nz>2010-08-14 01:08:00 (GMT)
commit4384051284e982fd504a1991d86135312f0f9e34 (patch)
treebecffc1c682225df2b9a3d281162fd75de4388da
initial commit
-rw-r--r--Experior.Activity/MANIFEST42
-rw-r--r--Experior.Activity/activity/activity.info7
-rw-r--r--Experior.Activity/activity/sugarbot.svg64
-rwxr-xr-xExperior.Activity/make-manifest2
-rw-r--r--Experior.Activity/master.cfg78
-rwxr-xr-xExperior.Activity/modded-main.py157
-rw-r--r--Experior.Activity/rm2
-rw-r--r--Experior.Activity/sbRpcServer.log46
-rwxr-xr-xExperior.Activity/sbconfig.py13
-rw-r--r--Experior.Activity/sbconfig.pycbin0 -> 227 bytes
-rwxr-xr-xExperior.Activity/sbconfig_sample.py13
-rw-r--r--Experior.Activity/sbconfig_sample.pycbin0 -> 234 bytes
-rwxr-xr-xExperior.Activity/sbdecorators.py148
-rw-r--r--Experior.Activity/sbdecorators.pycbin0 -> 4523 bytes
-rwxr-xr-xExperior.Activity/sbexecutionengine.py112
-rw-r--r--Experior.Activity/sbexecutionengine.pycbin0 -> 3734 bytes
-rwxr-xr-xExperior.Activity/sbgui.py321
-rw-r--r--Experior.Activity/sbgui.pycbin0 -> 8134 bytes
-rwxr-xr-xExperior.Activity/sblog.py24
-rw-r--r--Experior.Activity/sblog.pycbin0 -> 913 bytes
-rwxr-xr-xExperior.Activity/sbpython.py561
-rw-r--r--Experior.Activity/sbpython.pycbin0 -> 16442 bytes
-rwxr-xr-xExperior.Activity/sbpython_script.py0
-rwxr-xr-xExperior.Activity/sbrpcserver.py419
-rw-r--r--Experior.Activity/sbrpcserver.pycbin0 -> 13729 bytes
-rwxr-xr-xExperior.Activity/script_calculate.py35
-rw-r--r--Experior.Activity/script_calculate.pycbin0 -> 954 bytes
-rwxr-xr-xExperior.Activity/script_terminal.py11
-rw-r--r--Experior.Activity/script_terminal.pycbin0 -> 531 bytes
-rwxr-xr-xExperior.Activity/setup.py41
-rwxr-xr-xExperior.Activity/sugarbot.py207
-rw-r--r--Experior.Activity/sugarbot.pycbin0 -> 6435 bytes
-rwxr-xr-xExperior.Activity/sugarbotlauncher.py298
-rw-r--r--Experior.Activity/svn-commit.tmp6
-rwxr-xr-xExperior.Activity/test_rpcserver.py143
-rw-r--r--Experior.Activity/test_rpcserver.pycbin0 -> 5480 bytes
-rwxr-xr-xExperior.Activity/test_sbexecutionengine.py110
-rw-r--r--Experior.Activity/test_sbexecutionengine.pycbin0 -> 5600 bytes
-rwxr-xr-xExperior.Activity/test_sbgui.py84
-rw-r--r--Experior.Activity/test_sbgui.pycbin0 -> 3770 bytes
-rwxr-xr-xExperior.Activity/test_sugarbot.py118
-rw-r--r--Experior.Activity/test_sugarbot.pycbin0 -> 5915 bytes
-rwxr-xr-xExperior.Activity/test_widgetIdentifier.py254
-rw-r--r--Experior.Activity/test_widgetIdentifier.pycbin0 -> 11702 bytes
-rwxr-xr-xExperior.Activity/widgetIdentifier.py260
-rw-r--r--Experior.Activity/widgetIdentifier.pycbin0 -> 9052 bytes
46 files changed, 3576 insertions, 0 deletions
diff --git a/Experior.Activity/MANIFEST b/Experior.Activity/MANIFEST
new file mode 100644
index 0000000..1115bb7
--- /dev/null
+++ b/Experior.Activity/MANIFEST
@@ -0,0 +1,42 @@
+test_sugarbot.pyc
+test_sbexecutionengine.pyc
+sblog.pyc
+sbexecutionengine.py
+test_widgetIdentifier.py
+test_sbgui.pyc
+sugarbot.py
+test_sbgui.py
+sbgui.py
+test_widgetIdentifier.pyc
+
+script_terminal.py
+sbrpcserver.pyc
+sbconfig_sample.pyc
+MANIFEST
+test_rpcserver.pyc
+MANIFEST~
+sbrpcserver.py
+sbpython_script.py
+activity/activity.info
+script_calculate.py
+sbexecutionengine.pyc
+setup.py
+test_sbexecutionengine.py
+sugarbot.pyc
+sbdecorators.pyc
+make-manifest
+sbgui.pyc
+widgetIdentifier.pyc
+sugarbotlauncher.py
+script_terminal.pyc
+sblog.py
+master.cfg
+sbdecorators.py
+sbpython.pyc
+test_rpcserver.py
+script_calculate.pyc
+test_sugarbot.py
+modded-main.py
+widgetIdentifier.py
+sbpython.py
+sbconfig_sample.py
diff --git a/Experior.Activity/activity/activity.info b/Experior.Activity/activity/activity.info
new file mode 100644
index 0000000..75dbed0
--- /dev/null
+++ b/Experior.Activity/activity/activity.info
@@ -0,0 +1,7 @@
+[Activity]
+name = sugarbot
+service_name = org.laptop.sugarbot
+class = sugarbot.sugarbot
+icon = sugarbot
+activity_version = 1
+show_launcher = yes
diff --git a/Experior.Activity/activity/sugarbot.svg b/Experior.Activity/activity/sugarbot.svg
new file mode 100644
index 0000000..c5ba0c2
--- /dev/null
+++ b/Experior.Activity/activity/sugarbot.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="40.310001"
+ height="45.539135"
+ id="svg2">
+ <defs
+ id="defs4" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="translate(-260.87975,-345.59506)"
+ id="layer1">
+ <g
+ transform="translate(-104.55079,4.5456865)"
+ id="g3080">
+ <path
+ d="m 365.9103,385.76896 c -0.85229,-0.61039 -0.57298,-0.75127 0.86971,-0.43866 1.98057,0.42915 2.0354,0.28739 0.80564,-2.08296 -1.61231,-3.10774 -0.41136,-5.88074 3.12997,-7.22716 1.34156,-0.51006 2.4392,-1.67381 2.4392,-2.58611 0,-2.78275 2.24941,-9.35466 3.03557,-8.86878 0.40624,0.25106 0.67693,-0.31532 0.60152,-1.25863 -0.0754,-0.94331 0.38791,-1.72597 1.02958,-1.73924 0.64166,-0.0133 1.54166,-0.43377 2,-0.93445 0.48416,-0.52889 0.30957,-0.60891 -0.41667,-0.19098 -1.77933,1.02396 -1.5517,-0.90342 0.28692,-2.42933 0.84531,-0.70155 1.41101,-2.01881 1.2571,-2.92726 -0.1539,-0.90845 0.56029,-2.9339 1.58709,-4.501 1.60229,-2.4454 1.99561,-2.61932 2.77481,-1.22696 1.07102,1.91379 7.63438,5.2289 8.5465,4.31677 0.347,-0.347 0.0644,-0.63091 -0.62802,-0.63091 -0.69242,0 -2.32941,-0.84203 -3.63776,-1.87118 -2.37438,-1.86768 -2.37507,-1.87456 -0.37246,-3.6869 1.10349,-0.99865 1.76038,-2.45672 1.45975,-3.24016 -0.37394,-0.97448 -0.0572,-1.23665 1.00258,-0.82996 0.88745,0.34055 1.79231,-0.039 2.11833,-0.88866 0.60674,-1.58113 3.89544,-2.03599 4.7479,-0.65668 0.74258,1.20152 -0.46156,5.17354 -1.56839,5.17354 -0.51831,0 -0.66427,-0.45 -0.32435,-1 0.33992,-0.55 -0.30852,-1 -1.44098,-1 -1.13246,0 -2.05902,0.47656 -2.05902,1.05902 0,0.58246 0.5625,0.72107 1.25,0.30804 1.36828,-0.82204 -1.07323,2.62534 -2.75,3.88296 -0.57471,0.43105 -0.0225,1.01765 1.29842,1.3793 3.40751,0.93292 2.40846,3.87068 -1.31631,3.87068 -1.64016,0 -3.7423,-0.33872 -4.67142,-0.7527 -0.92912,-0.41399 -1.93656,-0.35265 -2.23875,0.13631 -0.60738,0.98274 2.65182,2.08153 6.23708,2.10273 1.51564,0.009 2.09145,0.44316 1.67584,1.26366 -0.34825,0.6875 0.0523,0.40773 0.89021,-0.6217 1.48824,-1.82851 1.59957,-1.82812 4.82416,0.0168 4.55328,2.60507 8.15438,9.95308 7.24733,14.78807 -0.84308,4.494 -4.24193,9.6565 -7.39133,11.22664 -2.35042,1.17181 -2.33559,1.19491 1.03001,1.60453 1.87812,0.22859 -0.52274,0.48763 -5.33524,0.57565 -4.8125,0.088 -8.75,-0.21773 -8.75,-0.67945 0,-0.46171 -1.12603,-1.35254 -2.5023,-1.9796 -3.61077,-1.64518 -6.47332,-6.93458 -6.59214,-12.18091 l -0.10191,-4.5 -1.24783,4.5 c -1.05113,3.79063 -1.01685,4.76965 0.21746,6.21055 0.87342,1.01961 1.28511,2.93828 1.0192,4.75 -0.2968,2.02222 -0.0218,3.03945 0.8217,3.03945 0.69728,0 1.47286,0.3375 1.72351,0.75 0.65352,1.07551 -11.07818,1.05281 -12.58221,-0.0243 z m 8.81074,-3.93429 c 0.34785,-1.09599 0.13775,-2.4874 -0.46688,-3.09203 -0.79912,-0.79912 -1.09934,-0.49854 -1.09934,1.10066 0,1.28889 -0.62121,2.2 -1.5,2.2 -1.81035,0 -2.01237,-2.65034 -0.25,-3.27976 0.6875,-0.24554 0.92337,-0.79716 0.52417,-1.22584 -1.01964,-1.09489 -3.77417,1.40703 -3.77417,3.42804 0,4.06418 5.32829,4.76928 6.56622,0.86893 z m 21.944,0.76881 c 8.68458,-3.62865 9.99506,-17.90688 2.11728,-23.0686 -3.19692,-2.0947 -4.22394,-1.45626 -5.09084,3.1647 -0.52905,2.82005 -0.32216,3.88426 0.88664,4.56073 2.05198,1.14835 2.02512,2.78299 -0.0457,2.78299 -1.39808,0 -1.43265,0.23397 -0.25,1.69196 0.93256,1.14966 0.97181,1.45126 0.12245,0.94098 -0.6875,-0.41304 -1.25351,-0.38692 -1.2578,0.058 -0.0114,1.184 -4.655,3.14193 -5.74653,2.42298 -0.51268,-0.33768 -1.00371,-2.63531 -1.09118,-5.10586 -0.23858,-6.73803 -1.89954,-11.03969 -3.96413,-10.2666 -1.52943,0.5727 -1.54756,0.44853 -0.19036,-1.30427 1.39261,-1.79854 1.37298,-1.83754 -0.27417,-0.54473 -0.97579,0.76588 -1.57668,1.58998 -1.33531,1.83135 0.24137,0.24137 -0.41288,2.31475 -1.45387,4.6075 -2.41,5.30792 -2.42221,9.41217 -0.0388,13.02735 4.10605,6.22802 10.57971,8.13989 17.61233,5.20148 z m -1.94593,-5.26705 c -0.54268,-1.4252 -0.42782,-1.54006 0.5598,-0.5598 0.68342,0.67834 0.99067,1.48524 0.68278,1.79313 -0.30789,0.30789 -0.86705,-0.24711 -1.24258,-1.23333 z m -12.56429,-0.68614 c 0,-0.21616 0.69837,-0.661 1.55194,-0.98855 0.88992,-0.34149 1.29132,-0.17385 0.94098,0.39301 -0.58726,0.95021 -2.49292,1.40545 -2.49292,0.59554 z m 14.50708,-1.59554 c -0.35034,-0.56686 0.0511,-0.7345 0.94098,-0.39301 1.73242,0.66479 2.04939,1.38156 0.61096,1.38156 -0.51754,0 -1.21592,-0.44485 -1.55194,-0.98855 z m -13.69458,-2.69456 c 0.72187,-0.28888 1.58437,-0.25335 1.91667,0.079 0.33229,0.33229 -0.25834,0.56864 -1.3125,0.52522 -1.16495,-0.048 -1.4019,-0.28495 -0.60417,-0.60417 z m 5.14855,-10.4527 c -0.97243,-3.39067 -1.68486,-4.47372 -2.44366,-3.71491 -0.64963,0.64962 1.73283,6.85072 2.63204,6.85072 0.39103,0 0.30626,-1.41112 -0.18838,-3.13581 z m 2.33763,0.47176 c -0.44681,-1.16435 -0.26507,-1.43321 0.60521,-0.89535 0.92626,0.57246 0.90582,0.22284 -0.0801,-1.36961 -1.07588,-1.73779 -1.38649,-1.8401 -1.6584,-0.54623 -0.35546,1.69146 0.43565,4.47524 1.2718,4.47524 0.275,0 0.21265,-0.74882 -0.13855,-1.66405 z m -6.00099,-11.00256 c -0.46859,-1.22112 -0.73371,-1.25231 -1.42154,-0.16724 -1.26394,1.99392 -1.05071,2.83806 0.56071,2.21971 0.79027,-0.30326 1.17765,-1.22687 0.86083,-2.05247 z m -3.54769,34.00433 c 0.6875,-0.27741 1.8125,-0.27741 2.5,0 0.6875,0.27741 0.125,0.50438 -1.25,0.50438 -1.375,0 -1.9375,-0.22697 -1.25,-0.50438 z m 5.25,-38.73073 c 0,-0.76616 0.68541,-1.65603 1.52314,-1.9775 1.24266,-0.47685 1.32825,-0.22033 0.46481,1.39302 -1.24059,2.31806 -1.98795,2.53779 -1.98795,0.58448 z"
+ id="path3094"
+ style="fill:#b9b9b9;fill-opacity:1" />
+ <path
+ d="m 367.82465,386.15919 c -0.89097,-1.94287 -0.65553,-7.42819 0.37197,-8.66625 1.45948,-1.75857 5.11427,-1.89357 6.7582,-0.24964 1.52892,1.52892 1.48962,4.83919 -0.0818,6.88924 -1.24268,1.62118 -6.5363,3.14328 -7.04837,2.02665 z m 5.74778,-2.43199 c 0.98993,-0.72385 1.63844,-2.09762 1.44113,-3.05282 -0.40184,-1.94539 -2.43711,-1.83636 -2.21985,0.11892 0.0764,0.6875 -0.48611,1.25 -1.25,1.25 -1.72823,0 -1.84137,-2.67173 -0.13889,-3.27976 0.6875,-0.24554 0.92337,-0.79716 0.52417,-1.22584 -1.01964,-1.09489 -3.77417,1.40703 -3.77417,3.42804 0,1.64033 1.79846,4.07756 3.00887,4.07756 0.33488,0 1.41881,-0.59224 2.40874,-1.3161 z m 8.39489,1.63299 c 0.72187,-0.28888 1.58437,-0.25335 1.91667,0.079 0.33229,0.33229 -0.25834,0.56864 -1.3125,0.52522 -1.16495,-0.048 -1.4019,-0.28495 -0.60417,-0.60417 z m 0.57581,-2.32045 c -2.26142,-1.60291 -4.60642,-4.17035 -5.21109,-5.70541 -1.60043,-4.06293 -1.85184,-13.56616 -0.37194,-14.05946 0.66395,-0.22131 0.98999,-0.75382 0.72453,-1.18333 -0.26546,-0.42952 0.40674,-1.58583 1.49377,-2.56958 1.08703,-0.98375 1.97642,-3.04233 1.97642,-4.57463 0,-1.5323 0.44485,-3.06093 0.98855,-3.39695 0.5684,-0.35129 0.73358,0.0535 0.38865,0.95232 -0.41743,1.08781 -0.15488,1.39252 0.86321,1.00184 0.94507,-0.36266 1.31701,-1.51737 1.05051,-3.26134 -0.34062,-2.22899 -0.22545,-2.40639 0.66032,-1.01712 1.18639,1.86078 6.56348,4.81722 8.76141,4.81722 0.77296,0 1.15489,0.40531 0.84872,0.9007 -0.58132,0.94059 -6.79379,0.69173 -8.46147,-0.33896 -0.52894,-0.3269 -1.23898,-0.14573 -1.57786,0.4026 -0.35134,0.56848 1.12323,1.27511 3.4309,1.64412 2.22588,0.35594 4.04706,1.03964 4.04706,1.51935 0,0.4797 0.45,0.87219 1,0.87219 0.55,0 1,-0.675 1,-1.5 0,-1.98231 0.84879,-1.88956 4.81018,0.52563 6.21243,3.78762 8.24808,14.63881 3.93982,21.00157 -4.97289,7.34433 -13.30775,8.96911 -20.36169,3.96924 z m 14.70557,-0.54499 c 8.22962,-4.2557 9.14582,-17.97216 1.53362,-22.95987 -3.19459,-2.09317 -4.37167,-1.37218 -5.23009,3.20358 -0.53959,2.87625 -0.30156,3.90176 1.1524,4.96492 1.74646,1.27704 1.74807,1.33992 0.0343,1.33992 -1.09252,0 -1.59624,0.5261 -1.28365,1.34068 0.8169,2.1288 -0.72791,3.7195 -3.83428,3.9482 -2.73037,0.20101 -2.87111,0.008 -2.93905,-4.03888 -0.0693,-4.12712 0.78475,-5.54222 1.81056,-3 0.27741,0.6875 0.53991,0.21094 0.58333,-1.05902 0.0434,-1.26996 0.49655,-2.05092 1.00695,-1.73548 1.71279,1.05856 2.27926,-3.39109 0.64036,-5.03 -1.42448,-1.42448 -1.57418,-1.35539 -1.63175,0.75307 l -0.0634,2.32143 -0.90439,-2.25 c -0.85367,-2.12382 -2.96884,-3.166 -2.96884,-1.4628 0,0.43295 -0.93402,0.85755 -2.07559,0.94354 -1.70105,0.12814 -1.85941,-0.10414 -0.87756,-1.28719 2.0948,-2.52408 0.40076,-1.55221 -2.12254,1.2177 -1.33337,1.46369 -1.86181,2.33713 -1.17431,1.94098 1.61295,-0.9294 1.57469,-0.45341 -0.24384,3.03346 -5.95688,11.4218 6.97793,23.81942 18.58772,17.81576 z m -11.47034,-18.99011 c -0.96498,-2.51469 -0.68031,-3.16355 0.49853,-1.13634 0.58369,1.00375 0.8506,2.03566 0.59313,2.29313 -0.25747,0.25747 -0.74872,-0.26309 -1.09166,-1.15679 z m 6.37646,7.53866 c 0,-0.55 -0.7875,-0.99311 -1.75,-0.98469 -1.49555,0.0131 -1.5319,0.15626 -0.25,0.98469 1.88721,1.21961 2,1.21961 2,0 z m 5.8125,14.31689 c 0.72187,-0.28888 1.58437,-0.25335 1.91667,0.079 0.33229,0.33229 -0.25834,0.56864 -1.3125,0.52522 -1.16495,-0.048 -1.4019,-0.28495 -0.60417,-0.60417 z M 373.31271,373.0433 c 0,-1.375 0.22698,-1.9375 0.50439,-1.25 0.27741,0.6875 0.27741,1.8125 0,2.5 -0.27741,0.6875 -0.50439,0.125 -0.50439,-1.25 z m 0.92106,-4.58333 c 0.048,-1.16495 0.28494,-1.4019 0.60416,-0.60417 0.28887,0.72187 0.25335,1.58437 -0.0789,1.91667 -0.33229,0.33229 -0.56864,-0.25834 -0.52522,-1.3125 z m 15.42105,-17.41667 c -1.72598,-1.90718 -1.72862,-2.08989 -0.057,-3.93699 0.96412,-1.06534 1.45731,-2.41534 1.09597,-3 -0.36133,-0.58465 -0.22856,-1.06301 0.29505,-1.06301 1.32152,0 2.3202,2.93409 1.4773,4.34024 -0.38237,0.63787 0.17867,0.49838 1.24675,-0.30998 1.30918,-0.99083 1.15933,-0.59132 -0.45986,1.22606 l -2.40183,2.6958 2.40183,0.96055 c 2.21804,0.88706 2.24152,0.96541 0.30681,1.02394 -1.15226,0.0349 -2.9095,-0.83661 -3.90499,-1.93661 z m -3.5,-4.37756 c 0,-0.20765 0.7875,-0.99515 1.75,-1.75 1.58606,-1.24387 1.62143,-1.2085 0.37755,0.37756 -1.30636,1.66575 -2.12755,2.19548 -2.12755,1.37244 z m 10.57654,-0.79948 c 0.45359,-1.30828 0.1243,-1.55749 -1.49755,-1.13337 -2.19579,0.57422 -2.60919,-0.30463 -1.19385,-2.53798 0.95072,-1.50021 4.25585,-1.23222 4.79547,0.38883 0.19049,0.57224 -0.33582,1.92224 -1.16959,3 -1.14452,1.47947 -1.37347,1.54869 -0.93448,0.28252 z"
+ id="path3092"
+ style="fill:#a3a3a3;fill-opacity:1" />
+ <path
+ d="m 368.22516,383.67474 c -1.54963,-2.89551 -1.12737,-5.56631 1.102,-6.97016 2.51057,-1.58091 6.83615,0.68967 6.79586,3.56728 -0.0755,5.39139 -5.56729,7.75759 -7.89786,3.40288 z m 5.72966,0.16856 c 1.66988,-1.66988 1.49734,-4.30834 -0.38382,-5.86957 -3.11745,-2.58725 -7.02399,2.42735 -4.37631,5.61761 1.46542,1.76572 3.15684,1.85525 4.76013,0.25196 z m -3.3,-2.8 c -0.33992,-0.55 -0.16803,-1 0.38197,-1 0.55,0 1.27811,0.45 1.61803,1 0.33992,0.55 0.16803,1 -0.38197,1 -0.55,0 -1.27811,-0.45 -1.61803,-1 z m 12.32801,2.21298 c -5.51305,-4.0732 -7.00044,-7.23142 -6.65819,-14.13741 0.16637,-3.35684 0.69807,-5.65722 1.23142,-5.32759 0.51625,0.31906 0.66751,-0.12643 0.33614,-0.98998 -0.34654,-0.90307 0.21851,-2.31309 1.33006,-3.31903 1.06291,-0.96192 1.93256,-3.00264 1.93256,-4.53494 0,-1.5323 0.44485,-3.06093 0.98855,-3.39695 0.56686,-0.35034 0.7345,0.0511 0.39301,0.94098 -0.38017,0.99069 -0.0357,1.55194 0.95243,1.55194 2.00027,0 3.05787,-1.69373 1.42224,-2.27769 -0.69093,-0.24667 -0.97168,-0.75716 -0.62389,-1.13441 0.64909,-0.70408 3.52032,0.73748 12.51422,6.28303 5.98424,3.68983 8.42648,7.94639 8.1934,14.2802 -0.14467,3.93123 -0.1946,4.01275 -0.51994,0.84887 -0.19795,-1.925 -0.5758,-4.47782 -0.83967,-5.67293 -0.69475,-3.1466 -5.35191,-8.32707 -7.48591,-8.32707 -1.00528,0 -1.98571,-0.47381 -2.17874,-1.0529 -0.49247,-1.4774 -8.09126,-3.07154 -9.22706,-1.93574 -0.55082,0.55082 0.73111,1.17604 3.23094,1.57578 2.27924,0.36447 3.91778,1.0288 3.64121,1.4763 -0.27657,0.4475 0.23896,1.22878 1.14562,1.73617 1.30221,0.72875 1.41804,1.3193 0.55144,2.81146 -1.04494,1.79923 -1.09848,1.78789 -1.12744,-0.23862 -0.0353,-2.46676 -2.46281,-4.84128 -3.98661,-3.89952 -0.57409,0.35481 -1.0438,0.15699 -1.0438,-0.43959 0,-2.03012 -5.75773,1.83859 -7.90346,5.31045 -3.79852,6.14614 -2.17349,14.37552 3.63837,18.42527 6.11645,4.26199 11.63381,3.70263 17.37816,-1.76184 4.0849,-3.88587 4.9474,-3.96627 2.32085,-0.21634 -2.12969,3.04056 -8.6373,6.21719 -12.64408,6.1721 -1.96303,-0.0221 -4.77078,-1.13119 -6.96183,-2.75 z m -1.82801,-23.71298 c 1.29174,-1.375 2.12363,-2.5 1.84863,-2.5 -0.275,0 -1.55689,1.125 -2.84863,2.5 -1.29175,1.375 -2.12363,2.5 -1.84863,2.5 0.275,0 1.55688,-1.125 2.84863,-2.5 z m 5.44069,14.40404 c -0.37254,-0.60278 0.11479,-1.84028 1.08296,-2.75 1.63827,-1.53939 1.72002,-1.53809 1.17936,0.0187 -0.46904,1.35055 -0.063,1.59007 2.10803,1.24364 2.56846,-0.40984 2.60197,-0.36156 0.74783,1.07729 -2.29281,1.77927 -4.17871,1.93049 -5.11818,0.4104 z m 4.22913,-4.3928 c -1.04239,-0.76832 -1.68806,-2.26684 -1.5,-3.48132 0.32749,-2.11497 0.35822,-2.11156 3.77446,0.41887 2.14272,1.58713 2.83552,2.55121 1.83333,2.55121 -0.88602,0 -1.76094,0.41855 -1.94428,0.93011 -0.18333,0.51157 -1.15691,0.32307 -2.16351,-0.41887 z m 1.08018,-17.17352 c 0.6875,-0.27741 1.8125,-0.27741 2.5,0 0.6875,0.27741 0.125,0.50438 -1.25,0.50438 -1.375,0 -1.9375,-0.22697 -1.25,-0.50438 z m -3.10231,-2.09875 c -0.90789,-1.469 2.20801,-4.50832 3.94038,-3.84355 1.56241,0.59956 1.55468,0.78936 -0.10694,2.62543 -1.89682,2.09596 -3.06206,2.46623 -3.83344,1.21812 z m 3.35231,-1.73897 c 0.71755,-0.86459 0.81474,-1.5 0.22943,-1.5 -0.5585,0 -1.27447,0.675 -1.59106,1.5 -0.31658,0.825 -0.41982,1.5 -0.22943,1.5 0.19039,0 0.90637,-0.675 1.59106,-1.5 z m -6,-1.87756 c 0,-0.20765 0.7875,-0.99515 1.75,-1.75 1.58606,-1.24387 1.62143,-1.2085 0.37755,0.37756 -1.30636,1.66575 -2.12755,2.19548 -2.12755,1.37244 z m 4.5,-2.62244 c -0.33992,-0.55 -0.14148,-1 0.44098,-1 0.58246,0 1.05902,0.45 1.05902,1 0,0.55 -0.19844,1 -0.44098,1 -0.24254,0 -0.7191,-0.45 -1.05902,-1 z m 2.5,0 c 0,-0.55 0.675,-1 1.5,-1 0.825,0 1.5,0.45 1.5,1 0,0.55 -0.675,1 -1.5,1 -0.825,0 -1.5,-0.45 -1.5,-1 z"
+ id="path3090"
+ style="fill:#8c8c8c;fill-opacity:1" />
+ <path
+ d="m 368.39537,384.05687 c -1.78788,-2.86285 -1.52986,-3.87163 0.31615,-1.23608 0.85619,1.22238 2.18067,2.22251 2.9433,2.22251 0.76263,0 2.08711,-1.00013 2.9433,-2.22251 0.85618,-1.22238 1.5567,-1.74212 1.5567,-1.15498 0,1.48664 -3.36019,4.37749 -5.08819,4.37749 -0.7869,0 -1.98896,-0.89389 -2.67126,-1.98643 z m 16.21683,0.12351 c -5.51869,-3.36541 -8.45738,-7.80034 -8.45738,-12.76346 0,-2.46012 0.68656,-5.80059 1.52568,-7.42328 0.83912,-1.62269 1.21938,-2.95034 0.84501,-2.95034 -0.37437,0 0.12033,-0.88509 1.09932,-1.96686 0.979,-1.08178 1.77999,-3.11499 1.77999,-4.51824 0,-1.40326 0.3886,-2.79154 0.86355,-3.08508 0.47495,-0.29353 0.57804,0.21032 0.22909,1.11967 -0.47591,1.24018 -0.16067,1.55648 1.26145,1.26568 1.25015,-0.25563 1.77661,-1.05509 1.54564,-2.34715 -0.34458,-1.92769 -0.3162,-1.92864 1.75,-0.0588 1.15515,1.04539 2.10027,1.59959 2.10027,1.23154 0,-0.99277 8.0096,4.28766 11.75,7.74633 1.7875,1.65286 3.25,3.40145 3.25,3.88576 0,0.48431 -1.1786,-0.52013 -2.61912,-2.23208 -4.11404,-4.88927 -13.32636,-8.76644 -17.25102,-7.2604 -1.10249,0.42306 -0.17629,1.01708 2.87134,1.8415 3.54185,0.95812 3.86066,1.19524 1.4988,1.11471 -4.04923,-0.13805 -6.9074,1.56847 -9.41062,5.61876 -5.26279,8.51538 -0.15219,19.229 10.08909,21.15028 3.86575,0.72522 6.68056,-0.29482 10.70871,-3.88062 1.61938,-1.44156 2.23764,-1.64259 1.92225,-0.62504 -0.67791,2.18719 -7.82283,5.96504 -11.30943,5.97981 -1.65,0.007 -4.36918,-0.82224 -6.04262,-1.84273 z m -2.95738,-25.13708 c 0.99549,-1.1 1.58497,-2 1.30997,-2 -0.275,0 -1.31448,0.9 -2.30997,2 -0.99549,1.1 -1.58498,2 -1.30998,2 0.275,0 1.31449,-0.9 2.30998,-2 z m -11,22 c -0.33992,-0.55 -0.14148,-1 0.44098,-1 0.58246,0 1.05902,0.45 1.05902,1 0,0.55 -0.19844,1 -0.44098,1 -0.24254,0 -0.7191,-0.45 -1.05902,-1 z m -3.5,-1.94098 c 0,-0.51754 0.44485,-1.21592 0.98855,-1.55194 0.56686,-0.35034 0.7345,0.0511 0.39301,0.94098 -0.66479,1.73242 -1.38156,2.04939 -1.38156,0.61096 z m 8,0.19098 c 0,-0.59583 -1.2375,-1.53531 -2.75,-2.08772 -1.5125,-0.55241 -2.04851,-1.03991 -1.19113,-1.08333 2.07496,-0.10509 5.63733,2.55818 4.68956,3.50596 -0.41164,0.41163 -0.74843,0.26092 -0.74843,-0.33491 z m 12.45888,-5.31653 c -0.36253,-0.58659 -0.44468,-1.281 -0.18255,-1.54313 0.26212,-0.26213 0.74306,0.21781 1.06875,1.06653 0.67618,1.76211 0.0998,2.07206 -0.8862,0.4766 z m 2.16941,-0.72588 c -0.26935,-0.43583 0.38882,-0.8586 1.4626,-0.93948 1.07378,-0.0809 1.69105,0.2757 1.37171,0.79241 -0.70857,1.14648 -2.16978,1.22229 -2.83431,0.14707 z m 2.10955,-2.80308 c -0.39627,-0.39627 -0.16189,-1.39807 0.52084,-2.22622 1.08202,-1.3125 0.95258,-1.35188 -1.00868,-0.30683 -1.2375,0.6594 -2.25,0.78122 -2.25,0.27071 0,-1.75623 3.16583,-2.13942 5.30376,-0.64196 1.6926,1.18554 1.7978,1.49979 0.50208,1.49979 -0.90155,0 -1.79855,0.47812 -1.99334,1.0625 -0.19479,0.58437 -0.67839,0.73828 -1.07466,0.34201 z m 12.42005,-2.40451 c 0,-1.375 0.22698,-1.9375 0.50439,-1.25 0.27741,0.6875 0.27741,1.8125 0,2.5 -0.27741,0.6875 -0.50439,0.125 -0.50439,-1.25 z m -12.15789,-5.44098 c 0,-0.79254 0.40803,-1.69317 0.90674,-2.00138 0.49871,-0.30822 0.67122,0.34022 0.38337,1.44098 -0.61061,2.33499 -1.29011,2.63015 -1.29011,0.5604 z m 0.8125,-10.24213 c 0.72187,-0.28888 1.58437,-0.25335 1.91667,0.079 0.33229,0.33229 -0.25834,0.56864 -1.3125,0.52522 -1.16495,-0.048 -1.4019,-0.28495 -0.60417,-0.60417 z m -3.8125,-2.12576 c 0,-0.44488 0.64471,-1.68238 1.43268,-2.75 1.07332,-1.45424 1.72225,-1.65591 2.58713,-0.804 0.87217,0.85908 0.85085,1.32477 -0.0872,1.90451 -0.80038,0.49466 -0.98806,0.35708 -0.52811,-0.38713 0.39244,-0.63498 0.23697,-1.15451 -0.34549,-1.15451 -0.97104,0 -1.47219,1.38327 -1.17744,3.25 0.0651,0.4125 -0.33158,0.75 -0.88158,0.75 -0.55,0 -1,-0.36399 -1,-0.80887 z m -3,-3.56869 c 0,-0.20765 0.7875,-0.99515 1.75,-1.75 1.58606,-1.24387 1.62143,-1.2085 0.37755,0.37756 -1.30636,1.66575 -2.12755,2.19548 -2.12755,1.37244 z m 7,-2.62244 c 0,-0.55 0.675,-1 1.5,-1 0.825,0 1.5,0.45 1.5,1 0,0.55 -0.675,1 -1.5,1 -0.825,0 -1.5,-0.45 -1.5,-1 z"
+ id="path3088"
+ style="fill:#767676;fill-opacity:1" />
+ <path
+ d="m 368.80981,384.21456 c -0.91025,-1.00581 -1.64131,-2.24331 -1.62458,-2.75 0.0167,-0.50669 0.50516,-0.10504 1.0854,0.89256 0.58025,0.9976 2.02907,2.20657 3.21959,2.68661 1.4653,0.59083 1.64931,0.89327 0.56959,0.93618 -0.87726,0.0349 -2.33976,-0.75954 -3.25,-1.76535 z m 20.10667,1.12148 c 1.24391,-0.23919 3.04391,-0.23011 4,0.0202 0.95609,0.25029 -0.0617,0.446 -2.26166,0.4349 -2.2,-0.0111 -2.98225,-0.21589 -1.73834,-0.45508 z m 6.97167,-1.41683 c 0.67834,-0.68342 1.48524,-0.99067 1.79313,-0.68278 0.30789,0.30788 -0.24711,0.86705 -1.23333,1.24258 -1.4252,0.54268 -1.54006,0.42782 -0.5598,-0.5598 z m -21.16904,-1.16904 c 0.37553,-0.98622 0.93469,-1.54122 1.24258,-1.23333 0.30789,0.30789 6.4e-4,1.11479 -0.68278,1.79313 -0.98762,0.98026 -1.10248,0.8654 -0.5598,-0.5598 z m 5.19412,-2.45687 c -1.43867,-1.5125 -2.87555,-4.1 -3.19307,-5.75 l -0.5773,-3 1.13074,3 c 0.6219,1.65 2.28379,4.2375 3.69307,5.75 1.40928,1.5125 2.33733,2.75 2.06233,2.75 -0.275,0 -1.67709,-1.2375 -3.11577,-2.75 z m 9.84289,-7.08609 c -0.25451,-0.41181 0.40608,-0.81419 1.46798,-0.89417 2.29656,-0.173 2.4986,0.29836 0.46274,1.0796 -0.80738,0.30982 -1.67621,0.22638 -1.93072,-0.18543 z m -13.44341,-4.16391 c 0,-1.375 0.22698,-1.9375 0.50439,-1.25 0.27741,0.6875 0.27741,1.8125 0,2.5 -0.27741,0.6875 -0.50439,0.125 -0.50439,-1.25 z m 16.61056,-0.16845 c 0.5811,-0.5811 1.64682,-0.85979 2.36826,-0.61931 0.74895,0.24964 0.29565,0.70294 -1.05655,1.05655 -1.66335,0.43497 -2.05378,0.30483 -1.31171,-0.43724 z m -13.34413,-7.97578 c 0.15312,-0.74567 0.73616,-2.48077 1.29564,-3.85577 0.55948,-1.375 0.76571,-3.16026 0.45829,-3.96724 -0.4913,-1.28966 -0.36595,-1.28966 1.03567,0 0.87704,0.80698 1.5252,1.91724 1.44035,2.46724 -0.0849,0.55 0.52073,0.85536 1.34573,0.67857 0.91235,-0.1955 1.10823,0.006 0.5,0.51498 -0.55,0.46003 -2.20467,1.88977 -3.67704,3.1772 -1.54143,1.34782 -2.55894,1.76567 -2.39864,0.98502 z m 2.70323,-2.60577 c 1.24388,-1.58606 1.20851,-1.62143 -0.37755,-0.37755 -0.9625,0.75484 -1.75,1.54234 -1.75,1.75 0,0.82303 0.82119,0.2933 2.12755,-1.37245 z m 4.87245,-4.52182 c 0,-0.46542 -0.375,-0.61445 -0.83333,-0.33119 -0.45834,0.28327 -0.83334,-0.0728 -0.83334,-0.7912 0,-1.01928 0.62245,-1.07129 2.83334,-0.23678 3.27756,1.23714 3.75105,2.57582 0.83333,2.35604 -1.1,-0.0829 -2,-0.53145 -2,-0.99687 z m -1,-7.10574 c 0,-0.20765 0.7875,-0.99515 1.75,-1.75 1.58606,-1.24387 1.62143,-1.2085 0.37755,0.37756 -1.30636,1.66575 -2.12755,2.19548 -2.12755,1.37244 z m 7,-2.62244 c 0,-0.55 0.675,-1 1.5,-1 0.825,0 1.5,0.45 1.5,1 0,0.55 -0.675,1 -1.5,1 -0.825,0 -1.5,-0.45 -1.5,-1 z"
+ id="path3086"
+ style="fill:#606060;fill-opacity:1" />
+ <path
+ d="m 369.02726,384.2933 c -1.19261,-1.5207 -1.1759,-1.60381 0.12756,-0.63427 0.825,0.61365 2.175,1.36562 3,1.67105 1.25475,0.46453 1.23389,0.56823 -0.12756,0.63427 -0.89515,0.0434 -2.24515,-0.70855 -3,-1.67105 z m 7.69185,-8.95687 c -0.54268,-1.4252 -0.42782,-1.54006 0.5598,-0.5598 0.68342,0.67834 0.99067,1.48524 0.68278,1.79313 -0.30789,0.30789 -0.86705,-0.24711 -1.24258,-1.23333 z m 2.81733,-14.68749 c 0.11332,-0.77213 0.74491,-2.05318 1.40353,-2.84677 0.65863,-0.79359 0.8639,-1.79994 0.45617,-2.23633 -0.40772,-0.4364 0.27118,-0.26666 1.50868,0.37719 1.2375,0.64385 2.25,1.40636 2.25,1.69447 0,0.28811 -0.46971,0.23354 -1.04381,-0.12127 -1.24911,-0.772 -4.15047,1.4037 -3.42887,2.57128 0.27792,0.44968 0.0875,1.07583 -0.42322,1.39145 -0.51069,0.31563 -0.83581,-0.0579 -0.72248,-0.83002 z m 6.49082,-8.35564 c -1.24387,-1.58606 -1.2085,-1.62143 0.37756,-0.37755 0.9625,0.75484 1.75,1.54234 1.75,1.75 0,0.82303 -0.82119,0.2933 -2.12756,-1.37245 z"
+ id="path3084"
+ style="fill:#494949;fill-opacity:1" />
+ <path
+ d="m 380.65482,358.0433 c 0.99549,-1.1 2.03497,-2 2.30997,-2 0.275,0 -0.31448,0.9 -1.30997,2 -0.99549,1.1 -2.03498,2 -2.30998,2 -0.275,0 0.31449,-0.9 1.30998,-2 z"
+ id="path3082"
+ style="fill:#333333;fill-opacity:1" />
+ </g>
+ </g>
+</svg>
diff --git a/Experior.Activity/make-manifest b/Experior.Activity/make-manifest
new file mode 100755
index 0000000..69e5c8a
--- /dev/null
+++ b/Experior.Activity/make-manifest
@@ -0,0 +1,2 @@
+find . -type f | sed 's,^./,,g' > MANIFEST
+chmod -R a+x *.py \ No newline at end of file
diff --git a/Experior.Activity/master.cfg b/Experior.Activity/master.cfg
new file mode 100644
index 0000000..ff0d4c5
--- /dev/null
+++ b/Experior.Activity/master.cfg
@@ -0,0 +1,78 @@
+# -*- python -*-
+# ex: set syntax=python:
+
+# This is a sample buildmaster config file. It must be installed as
+# 'master.cfg' in your buildmaster's base directory (although the filename
+# can be changed with the --basedir option to 'mktap buildbot master').
+
+# It has one job: define a dictionary named BuildmasterConfig. This
+# dictionary has a variety of keys to control different aspects of the
+# buildmaster. They are documented in docs/config.xhtml .
+
+import os.path
+#from buildbot.changes.freshcvs import FreshCVSSource
+from buildbot.scheduler import Scheduler, Periodic
+from buildbot.process import buildstep, factory
+from buildbot.status import html
+from buildbot.buildslave import BuildSlave
+from buildbot.changes.pb import PBChangeSource
+from buildbot.scheduler import Scheduler, Periodic
+from buildbot.process import buildstep
+from buildbot.steps.shell import ShellCommand
+from buildbot.steps.source import SVN
+from buildbot.status import html
+s = factory.s
+c = BuildmasterConfig = {}
+
+####### BUILDSLAVES
+c['slaves'] = [BuildSlave("bot1name", "bot1passwd")]
+c['slavePortnum'] = 9989
+
+c['change_source'] = PBChangeSource()
+
+####### SCHEDULING
+
+periodic = Periodic("every_6_hours", ["sugarbot_trunk"], 6*60*60)
+# periodic = Periodic("every_30_minutes", ["sugarbot_trunk"], 30*60)
+c['schedulers'] = [periodic]
+
+####### SVN
+source = s(SVN, mode='update',
+baseURL='http://sugarbot.googlecode.com/svn/',
+defaultBranch='trunk/sugarbot')
+
+####### NOSE
+class NoseTest(ShellCommand):
+ name = "nose tests"
+ description = ["running nose tests"]
+ descriptionDone = [name]
+
+nose_tests = s(NoseTest, command="/usr/bin/nosetests")
+
+###### SUGARBOT
+class SugarbotTest(ShellCommand):
+ name = "sugarbot tests"
+ description = ["running sugarbot tests"]
+ description = [name]
+sugarbot_tests = s(SugarbotTest, command="/usr/bin/env python sugarbotlauncher.py")
+
+####### BUILDFACTORY
+f = factory.BuildFactory([source,nose_tests,sugarbot_tests])
+
+c['builders'] = [
+{'name':'sugarbot_trunk',
+'slavename':'sugarbot',
+'builddir':'test-APP-linux',
+'factory':f },
+]
+
+c['status'] = []
+
+####### STATUS
+c['status'].append(html.WebStatus(http_port=8010))
+
+####### PROJECT INFO
+c['projectName'] = "sugarbot"
+c['projectURL'] = "http://code.google.com/p/sugarbot/"
+c['buildbotURL'] = "http://localhost:8010/"
+c['bots']=[("sugarbot","password")]
diff --git a/Experior.Activity/modded-main.py b/Experior.Activity/modded-main.py
new file mode 100755
index 0000000..e700e85
--- /dev/null
+++ b/Experior.Activity/modded-main.py
@@ -0,0 +1,157 @@
+# Copyright (C) 2006, Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import sys
+import os
+from ConfigParser import ConfigParser
+import gettext
+
+# HACK we need to import numpy before gtk otherwise we traceback in
+# some locales. See http://dev.laptop.org/ticket/5559.
+import numpy
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+
+from sugar import env
+from sugar import logger
+from sugar.profile import get_profile
+
+from view.Shell import Shell
+from model.shellmodel import ShellModel
+from shellservice import ShellService
+from hardware import hardwaremanager
+from intro import intro
+import logsmanager
+import config
+
+def _start_matchbox():
+ cmd = ['matchbox-window-manager']
+
+ cmd.extend(['-use_titlebar', 'no'])
+ cmd.extend(['-theme', 'sugar'])
+ cmd.extend(['-kbdconfig', os.path.join(config.data_path, 'kbdconfig')])
+
+ gobject.spawn_async(cmd, flags=gobject.SPAWN_SEARCH_PATH)
+
+def _save_session_info():
+ # Save our DBus Session Bus address somewhere it can be found
+ #
+ # WARNING!!! this is going away at some near future point, do not rely on it
+ #
+ session_info_file = os.path.join(env.get_profile_path(), "session.info")
+ f = open(session_info_file, "w")
+
+ cp = ConfigParser()
+ cp.add_section('Session')
+ cp.set('Session', 'dbus_address', os.environ['DBUS_SESSION_BUS_ADDRESS'])
+ cp.set('Session', 'display', gtk.gdk.display_get_default().get_name())
+ cp.write(f)
+
+ f.close()
+
+def _setup_translations():
+ locale_path = os.path.join(config.prefix, 'share', 'locale')
+ domain = 'sugar'
+
+ gettext.bindtextdomain(domain, locale_path)
+ gettext.textdomain(domain)
+
+def check_cm(bus_name):
+ try:
+ import dbus
+ bus = dbus.SessionBus()
+ bus_object = bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
+ name = bus_object.GetNameOwner(bus_name, dbus_interface='org.freedesktop.DBus')
+ if name:
+ return True
+ except dbus.DBusException:
+ pass
+ return False
+
+def _shell_started_cb():
+ # Unfreeze the display
+ hw_manager = hardwaremanager.get_manager()
+ hw_manager.set_dcon_freeze(0)
+
+def main():
+ gobject.idle_add(_shell_started_cb)
+
+ logsmanager.setup()
+ logger.start('shell')
+
+ _save_session_info()
+ _start_matchbox()
+ _setup_translations()
+
+ hw_manager = hardwaremanager.get_manager()
+ hw_manager.startup()
+
+ icons_path = os.path.join(config.data_path, 'icons')
+ gtk.icon_theme_get_default().append_search_path(icons_path)
+
+ # Do initial setup if needed
+ if not get_profile().is_valid():
+ win = intro.IntroWindow()
+ win.show_all()
+ gtk.main()
+
+ if os.environ.has_key("SUGAR_TP_DEBUG"):
+ # Allow the user time to start up telepathy connection managers
+ # using the Sugar DBus bus address
+ import time
+ from telepathy.client import ManagerRegistry
+
+ registry = ManagerRegistry()
+ registry.LoadManagers()
+
+ debug_flags = os.environ["SUGAR_TP_DEBUG"].split(',')
+ for cm_name in debug_flags:
+ if cm_name not in ["gabble", "salut"]:
+ continue
+
+ try:
+ cm = registry.services[cm_name]
+ except KeyError:
+ print RuntimeError("%s connection manager not found!" % cm_name)
+
+ while not check_cm(cm['busname']):
+ print "Waiting for %s on: DBUS_SESSION_BUS_ADDRESS=%s" % \
+ (cm_name, os.environ["DBUS_SESSION_BUS_ADDRESS"])
+ try:
+ time.sleep(5)
+ except KeyboardInterrupt:
+ print "Got Ctrl+C, continuing..."
+ break
+
+ model = ShellModel()
+ shell = Shell(model)
+ service = ShellService(shell)
+
+ if os.environ.has_key("SUGARBOT_EMULATOR"):
+ sys.path.append(os.environ['SUGARBOT_PATH'])
+ from sugarbotlauncher import SugarbotLauncher
+ sbLauncher = SugarbotLauncher(shell, model)
+
+ try:
+ gtk.main()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
+
+ session_info_file = os.path.join(env.get_profile_path(), "session.info")
+ os.remove(session_info_file) \ No newline at end of file
diff --git a/Experior.Activity/rm b/Experior.Activity/rm
new file mode 100644
index 0000000..1d5c9ee
--- /dev/null
+++ b/Experior.Activity/rm
@@ -0,0 +1,2 @@
+./.svn
+./activity/.svn
diff --git a/Experior.Activity/sbRpcServer.log b/Experior.Activity/sbRpcServer.log
new file mode 100644
index 0000000..e71d6c7
--- /dev/null
+++ b/Experior.Activity/sbRpcServer.log
@@ -0,0 +1,46 @@
+08-07 18:48 sbRpcServer INFO Listening on port 54321
+08-07 18:48 sbRpcServer INFO Kill: True Restart: True
+08-07 18:48 sbRpcServer INFO Added script script_calculate.py [Activity Calculate]
+08-07 18:48 sbRpcServer INFO Added script script_terminal.py [Activity Terminal]
+08-07 18:55 sbRpcServer INFO Listening on port 54321
+08-07 18:55 sbRpcServer INFO Kill: True Restart: True
+08-07 18:55 sbRpcServer INFO Added script script_calculate.py [Activity Calculate]
+08-07 18:55 sbRpcServer INFO Added script script_calculate.pyc [Activity Calculate]
+08-07 18:55 sbRpcServer INFO Added script script_terminal.py [Activity Terminal]
+08-07 18:55 sbRpcServer INFO Added script script_terminal.pyc [Activity Terminal]
+08-08 11:29 sbRpcServer INFO Listening on port 54321
+08-08 11:29 sbRpcServer INFO Kill: True Restart: True
+08-08 11:29 sbRpcServer INFO Added script script_calculate.py [Activity Calculate]
+08-08 11:29 0 INFO Starting script_calculate.py
+08-08 11:38 sbRpcServer INFO Listening on port 54321
+08-08 11:38 sbRpcServer INFO Kill: True Restart: True
+08-08 11:38 sbRpcServer INFO Added script script_calculate.py [Activity Calculate]
+08-08 11:38 0 INFO Starting script_calculate.py
+08-08 11:39 0 INFO Starting script_calculate.py
+08-08 11:40 0 INFO Starting script_calculate.py
+08-08 11:40 0 INFO Starting script_calculate.py
+08-08 11:42 0 INFO Starting script_calculate.py
+08-08 11:43 0 INFO Getting Script: script_calculate.py
+08-08 11:43 0 ERROR Execution failed:
+Traceback (most recent call last):
+ File "/home/tim/Activities/sugarbot.activity/sbexecutionengine.py", line 86, in executePy
+ sugarbot_main(self.widgets)
+ File "Sugarbot Script: 'script_calculate.py'", line 8, in sugarbot_main
+ File "/home/tim/Activities/sugarbot.activity/sbpython.py", line 548, in __getitem__
+ raise WidgetDoesNotExist, which
+WidgetDoesNotExist: 'The widget Share with: could not be identified.'
+
+08-14 11:23 sbRpcServer INFO Listening on port 54321
+08-14 11:23 sbRpcServer INFO Kill: True Restart: True
+08-14 11:23 sbRpcServer INFO Added script script_calculate.py [Activity Calculate]
+08-14 11:24 0 INFO Starting script_calculate.py
+08-14 11:24 0 INFO Getting Script: script_calculate.py
+08-14 11:24 0 ERROR Execution failed:
+Traceback (most recent call last):
+ File "/home/tim/Activities/sugarbot.activity/sbexecutionengine.py", line 86, in executePy
+ sugarbot_main(self.widgets)
+ File "Sugarbot Script: 'script_calculate.py'", line 8, in sugarbot_main
+ File "/home/tim/Activities/sugarbot.activity/sbpython.py", line 548, in __getitem__
+ raise WidgetDoesNotExist, which
+WidgetDoesNotExist: 'The widget Share with: could not be identified.'
+
diff --git a/Experior.Activity/sbconfig.py b/Experior.Activity/sbconfig.py
new file mode 100755
index 0000000..dfd84b4
--- /dev/null
+++ b/Experior.Activity/sbconfig.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+# The host that the sugarbot clients should connect to in order to retrieve
+# the commands that they need to execute.
+host = "localhost"
+
+# The port to connect over. This is the same port that the XML-RPC server
+# will be listening on.
+port = 54321
+
+# Client name.
+clientName = "testClientName" \ No newline at end of file
diff --git a/Experior.Activity/sbconfig.pyc b/Experior.Activity/sbconfig.pyc
new file mode 100644
index 0000000..910601e
--- /dev/null
+++ b/Experior.Activity/sbconfig.pyc
Binary files differ
diff --git a/Experior.Activity/sbconfig_sample.py b/Experior.Activity/sbconfig_sample.py
new file mode 100755
index 0000000..dfd84b4
--- /dev/null
+++ b/Experior.Activity/sbconfig_sample.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+# The host that the sugarbot clients should connect to in order to retrieve
+# the commands that they need to execute.
+host = "localhost"
+
+# The port to connect over. This is the same port that the XML-RPC server
+# will be listening on.
+port = 54321
+
+# Client name.
+clientName = "testClientName" \ No newline at end of file
diff --git a/Experior.Activity/sbconfig_sample.pyc b/Experior.Activity/sbconfig_sample.pyc
new file mode 100644
index 0000000..d88c2a6
--- /dev/null
+++ b/Experior.Activity/sbconfig_sample.pyc
Binary files differ
diff --git a/Experior.Activity/sbdecorators.py b/Experior.Activity/sbdecorators.py
new file mode 100755
index 0000000..fcc85c9
--- /dev/null
+++ b/Experior.Activity/sbdecorators.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+sbpython.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+
+"""
+One of three degrees of enforcement may be specified by passing
+the 'debug' keyword argument to the decorator:
+ 0 -- NONE: No type-checking. Decorators disabled.
+ 1 -- MEDIUM: Print warning message to stderr. (Default)
+ 2 -- STRONG: Raise TypeError with message.
+If 'debug' is not passed to the decorator, the default level is used.
+
+Example usage:
+ >>> NONE, MEDIUM, STRONG = 0, 1, 2
+ >>>
+ >>> @accepts(int, int, int)
+ ... @returns(float)
+ ... def average(x, y, z):
+ ... return (x + y + z) / 2
+ ...
+ >>> average(5.5, 10, 15.0)
+ TypeWarning: 'average' method accepts (int, int, int), but was given
+ (float, int, float)
+ 15.25
+ >>> average(5, 10, 15)
+ TypeWarning: 'average' method returns (float), but result is (int)
+ 15
+
+Needed to cast params as floats in function def (or simply divide by 2.0).
+
+ >>> TYPE_CHECK = STRONG
+ >>> @accepts(int, debug=TYPE_CHECK)
+ ... @returns(int, debug=TYPE_CHECK)
+ ... def fib(n):
+ ... if n in (0, 1): return n
+ ... return fib(n-1) + fib(n-2)
+ ...
+ >>> fib(5.3)
+ Traceback (most recent call last):
+ ...
+ TypeError: 'fib' method accepts (int), but was given (float)
+
+"""
+import sys
+
+def accepts(*types, **kw):
+ """ Function decorator. Checks that inputs given to decorated function
+ are of the expected type.
+
+ Parameters:
+ types -- The expected types of the inputs to the decorated function.
+ Must specify type for each parameter.
+ kw -- Optional specification of 'debug' level (this is the only valid
+ keyword argument, no other should be given).
+ debug = ( 0 | 1 | 2 )
+
+ """
+ if not kw:
+ # default level: MEDIUM
+ debug = 1
+ else:
+ debug = kw['debug']
+ try:
+ def decorator(f):
+ def newf(*args):
+ if debug == 0:
+ return f(*args)
+ assert len(args) == len(types)
+ argtypes = tuple(map(type, args))
+ if argtypes != types:
+ msg = info(f.__name__, types, argtypes, 0)
+ if debug == 1:
+ print >> sys.stderr, 'TypeWarning: ', msg
+ elif debug == 2:
+ raise TypeError, msg
+ return f(*args)
+ newf.__name__ = f.__name__
+ return newf
+ return decorator
+ except KeyError, key:
+ raise KeyError, key + "is not a valid keyword argument"
+ except TypeError, msg:
+ raise TypeError, msg
+
+def returns(ret_type, **kw):
+ """ Function decorator. Checks that return value of decorated function
+ is of the expected type.
+
+ Parameters:
+ ret_type -- The expected type of the decorated function's return value.
+ Must specify type for each parameter.
+ kw -- Optional specification of 'debug' level (this is the only valid
+ keyword argument, no other should be given).
+ debug=(0 | 1 | 2)
+
+ """
+ try:
+ if not kw:
+ # default level: MEDIUM
+ debug = 1
+ else:
+ debug = kw['debug']
+ def decorator(f):
+ def newf(*args):
+ result = f(*args)
+ if debug == 0:
+ return result
+ res_type = type(result)
+ if res_type != ret_type:
+ msg = info(f.__name__, (ret_type,), (res_type,), 1)
+ if debug == 1:
+ print >> sys.stderr, 'TypeWarning: ', msg
+ elif debug == 2:
+ raise TypeError, msg
+ return result
+ newf.__name__ = f.__name__
+ return newf
+ return decorator
+ except KeyError, key:
+ raise KeyError, key + "is not a valid keyword argument"
+ except TypeError, msg:
+ raise TypeError, msg
+
+def info(fname, expected, actual, flag):
+ """ Convenience function returns nicely formatted error/warning msg. """
+ format = lambda types: ', '.join([str(t).split("'")[1] for t in types])
+ expected, actual = format(expected), format(actual)
+ msg = "'%s' method " % fname \
+ + ("accepts", "returns")[flag] + " (%s), but " % expected\
+ + ("was given", "result is")[flag] + " (%s)" % actual
+ return msg
diff --git a/Experior.Activity/sbdecorators.pyc b/Experior.Activity/sbdecorators.pyc
new file mode 100644
index 0000000..2edb9c5
--- /dev/null
+++ b/Experior.Activity/sbdecorators.pyc
Binary files differ
diff --git a/Experior.Activity/sbexecutionengine.py b/Experior.Activity/sbexecutionengine.py
new file mode 100755
index 0000000..bb67fe0
--- /dev/null
+++ b/Experior.Activity/sbexecutionengine.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+sbexecutionengine.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+import gobject
+import logging
+import os
+import pygtk
+import sys
+import threading
+import time
+import traceback
+
+pygtk.require('2.0')
+import gtk
+
+from sbpython import *
+
+class sbExecutionEngine:
+ """
+ Responsible for communications with the XML-RPC server regarding command
+ retrieval, as well as parsing and execution of those commands.
+ """
+ def __init__(self, sbGUI, xmlRpcServer):
+ self.sbgui = sbGUI
+ self.rpc = xmlRpcServer
+ self.widgets = sbwidgets
+
+ self.delayedExecution = False
+ self.executionComplete = False
+ self.lastCommand = None
+
+ self.log = logging.getLogger("ExecutionEngine")
+
+ try:
+ self.id = os.environ['SUGARBOT_ID']
+ except KeyError:
+ self.log.error("Sugarbot ID is not set. Using default 0. ")
+ self.id = 0
+
+ def killSugarbot(self):
+ """
+ Kills the sugarbot activity.
+ """
+ self.log.info("Attempting to kill sugarbot")
+ sys.exit(0)
+
+ def executePy(self):
+ """
+ Executes the Sugarbot pâ—Šython script.
+
+ Executes the Sugarbot python script provided by the XML-RPC server.
+ Regards any unhandled exceptions as fatal errors, and reports them
+ to the server. Also handles the termination of Sugarbot if the
+ auto-restart flag has been set by the XML-RPC server.
+ """
+ self.script = self.rpc.getScript(self.id)
+ self.log.info("Executing Script:\n%s" % self.script)
+
+ self.widgets.gui = self.sbgui
+
+ # Execute the actual python script.
+ try:
+ exec self.script
+
+ # t = threading.Thread(args=(self.widgets,))
+ # t.run = sugarbot_main
+ # t.start()
+
+ sugarbot_main(self.widgets)
+ self.rpc.success(self.id)
+
+ # Something bad happened. Report it, and log it.
+ except:
+ text = "Execution failed:\n%s" % traceback.format_exc()
+ text = self.rpc.fail(text, self.id)
+ self.log.error( text )
+
+ # Regarless of the success status, check to see if we need to restart
+ # sugarbot or not.
+ finally:
+ restart = self.rpc.getRestartFlag()
+ self.log.info("Got restart flag: " + str(restart))
+
+ if restart:
+ self.killSugarbot()
+
+
+ def isComplete(self):
+ """
+ Returns true if execution is complete.
+
+ Returns true if execution is complete, i.e. there are no more
+ commands that can be executed.
+ """
+ return self.executionComplete \ No newline at end of file
diff --git a/Experior.Activity/sbexecutionengine.pyc b/Experior.Activity/sbexecutionengine.pyc
new file mode 100644
index 0000000..3fc714f
--- /dev/null
+++ b/Experior.Activity/sbexecutionengine.pyc
Binary files differ
diff --git a/Experior.Activity/sbgui.py b/Experior.Activity/sbgui.py
new file mode 100755
index 0000000..3593f38
--- /dev/null
+++ b/Experior.Activity/sbgui.py
@@ -0,0 +1,321 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+sbgui.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+import gobject
+import os
+import pygtk
+import sys
+import time
+pygtk.require('2.0')
+import gtk
+import logging
+import sugar
+
+from gobject import idle_add
+from gtk import gdk
+from gtk.gdk import event_handler_set
+from sbexecutionengine import sbExecutionEngine
+from sugar import graphics
+from sugar.graphics.toolbutton import Palette
+from widgetIdentifier import *
+
+class sbGUI(gobject.GObject):
+ """
+ Responsible for tracking all identifiable* widgets instantiated by GTK.
+
+ *Identifiable widgets are widgets for which a valid identifier can be
+ found, via any of the identifiers enumerated by widgetIdentifier.identifiers.
+ """
+ def __init__(self,sugarbotInstance,rpcServer):
+ """
+ Initialize internal variables, and register self as an event handler.
+ """
+ # Necessary, due to inheritance
+ gobject.GObject.__init__(self)
+
+ # Get the RPC server connection and the sugarbot instance, as well
+ # as the execution engine.
+ self.sugarbot = sugarbotInstance
+ self.rpc = rpcServer
+ self.engine = sbExecutionEngine(self,self.rpc)
+ self.log = logging.getLogger('sbGUI')
+
+ # Keep track of the amount of idle time...
+ self.idletime = 0
+ self.idletimeout= 6
+
+ # In order to keep track of all of the windows, we set up a
+ # dict of Windows. For each window, the key is its id (as provided
+ # by id(theWindowObject). The value of each dictionary entry is a
+ # dictionary of Widgets, set up the same way -- the id() of the
+ # widget is the key, and the
+ self.trackedWidgets = {} # Maps id(object) -> widget
+ self.names = {} # Maps identifier -> widget
+
+ # Register one of our methods to intercept all GTK events
+ self.registerEventHandler()
+
+
+ def eventHandler(self,event=None):
+ """ Intercepts all GDK events. We then send them off to a separate
+ handler method (to keep things clean), and then have GTK execute
+ whatever the event is supposed to do.
+ """
+ if event is not None:
+ gtk.main_do_event(event)
+ self.handleEvent(event)
+
+ if event.type is not gtk.gdk.EXPOSE:
+ self.idletime = 0
+
+ return True
+
+
+ def getWidgetIdentifier(self,widget):
+ """
+ Returns the Widget's unique identifier (for example, a button's
+ label, or a gkt.Entry's name), or None if it does not have one.
+ Also, this function filters out many uninitialized identifiers,
+ such as "GtkToolbar" or "GtkButton"
+ @param widget - The widget whose identifier is to be retrieved.
+ """
+ if not isinstance(widget,gtk.Widget):
+ raise "_getWidgetName must take a gtk.Widget object as its argument"
+
+ # ---- GENERIC APPROACH ----
+ # Assuming that the widget was named explicitly by the developers,
+ # getting the name should be very straightforward, with no specialized
+ # cases or special name-detecting.
+ widId = widgetIdentifier(widget)
+ ident = widId.getIdentifier()
+
+ if ident is not None:
+ return ident
+
+ # ---- SPECIALIZED APPROACH ----
+ # Check to see if we have an identifier for the specific type
+ # of widget before we iterate through all of the different identifiers
+ # hoping to get a hit.
+ if widgetIdentifier.identifiers.has_key(widget.__class__):
+ widId = widgetIdentifier.identifiers[widget.__class__](widget)
+ ident = widId.getIdentifier()
+
+ if ident is not None:
+ return ident
+
+ # ---- BRUTE FORCE ----
+ # The widget was not named explicitly by the developers, and we do
+ # not have a case for the specific widget class.
+ # Iterate through all of our potential identifiers, since we
+ # very likely have a widget class that it inherits from.
+ # This method is undesirable, since the identifiers in the dictionary
+ # widgetIdentifiers may be in a different order each time the
+ # program is run, due to the non-ordered nature of dictionaries.
+ for identifier in widgetIdentifier.identifiers:
+ if isinstance(widget, identifier):
+ widId = widgetIdentifier.identifiers[identifier](widget)
+ ident = widId.getIdentifier()
+
+ if ident is not None:
+ break
+
+ # At this point, we either have a valid widget identifier, or None.
+ return ident
+
+
+ def addWidget(self,widget):
+ """
+ Add a widget to be tracked internally. Widgets are tracked by their
+ id(). Additionally, add it to the names{} dictionary, so that we
+ can quickly look up widgets by the name.
+ """
+
+ # Don't do anything if we already have this widget by ID
+ if self.trackedWidgets.has_key(id(widget)):
+ return
+
+ # Make sure we are working on a widget
+ if not isinstance(widget, gtk.Widget):
+ return
+
+ # Containers might have children. Check them all.
+ if isinstance(widget, gtk.Container): # gtk.Container can have
+ for child in widget.get_children(): # any number of children
+ self.addWidget(child)
+
+ if isinstance(widget, gtk.Bin): # gtk.Bin can only have
+ self.addWidget(widget.get_child()) # one child.
+
+ if isinstance(widget, gtk.Notebook): # gtk.Notebook can have
+ numPages = widget.get_n_pages() # many children.
+ for count in range(0, numPages):
+ page = widget.get_nth_page(count)
+ self.addWidget(page)
+ return
+
+
+ # Get the widget's identifier & id. If the widget cannot be reliably
+ # identified, there is no use in tracking it.
+ identifier = self.getWidgetIdentifier(widget)
+ _id = id(widget)
+ if identifier is None:
+ return
+
+ # Simply keep track of the widgets by ID
+ self.trackedWidgets[_id]=widget
+
+ # Keep track of the widgets by identifier.
+ # Check to see if it's already being tracked.
+ if self.names.has_key(identifier):
+ raise KeyError, "Already tracking a widget by identifier %s" \
+ % identifier
+
+ # Track the little bugger
+ else:
+ self.log.debug("Tracking widget id %i by identifier %s" % (_id, identifier))
+ self.names[identifier] = widget
+
+
+ def delWidget(self,widget):
+ """
+ Remove a widget from internal tracking. Widgets can be removed by
+ their id() or by the gtk.Widget object.
+
+ TODO: I don't think this function ever gets called.
+ """
+ if not isinstance(widget, gtk.Widget):
+ raise "Called delWidget on non-Widget object"
+ return
+
+ # Get id(widget)
+ identifier = self.getWidgetIdentifier(widget)
+ _id = id(widget)
+
+ # Remove the widget from the trackedWidgets dict if it is tracked.
+ if self.trackedWidgets.has_key(_id):
+ del self.trackedWidgets[_id]
+ del self.names[identifier]
+
+ else: # Tried to call delWidget on non-tracked Widget
+ return
+
+ def getWidgetByName(self,widgetName):
+ """
+ Checks to see if we are tracking a Widget with a given name.
+ If so, return the Widget. If not, return None.
+ """
+ if widgetName in self.names:
+ return self.names[widgetName]
+ return None
+
+ def handleEvent_firehose(self,event):
+ """
+ For exploratory testing. Don't bother trying to figure out what this
+ does, it will change without notification.
+ Pretty much just outputs a firehose of events. Useful for exploratory
+ testing, and that's pretty much it.
+ """
+ if not hasattr(self,'classes'):
+ self.classes = []
+
+ eventType = event.type
+ print "----------------------------------------"
+ print event.type
+ if event.window:
+ # print event.window
+ try:
+ widget = event.window.get_user_data()
+ print widget.__class__
+ self.classes[widget.__class__] = 1
+ except:
+ raise
+ print "----------------------------------------"
+ print ""
+ print ""
+
+ def handleEvent(self,event):
+ """
+ Handles all GDK events. We first filter them so that we know
+ they pertain to a window, and then we further drill down based on the
+ type of action. This method is used to achieve two goals:
+ [1] Build a database of all windows and widgets
+ [2] Allow us to see actions as they happen. This could lead to
+ recording functionality in the future.
+ """
+ try:
+ # Does the event have a Window that it belongs to?
+ if (not event.window):
+ return
+
+ # Get some information on the widget. If it doesn't work, just
+ # gracefully fail. Exceptions happen with the following events:
+ # (maybe more, but these are what I've observed):
+ # - GDK_OWNER_CHANGE
+ widget = event.window.get_user_data()
+ eventType = event.type
+
+ # -------- HANDLE WIDGET INSTANTIATION --------
+ # MAP events are generated when a widget is initially displayed
+ # on the screen. In most cases, any naming or configuration that
+ # is going to be performed *has been* performed.
+ if eventType == gdk.MAP:
+ self.addWidget(widget)
+
+ # -------- HANDLE WIDGET DESTRUCTION --------
+ # UNMAP events are generated when a widget
+ # is being taken off the screen. Generally, this will happen at
+ # the end of an application's execution. However, to maintain
+ # flexibility (e.g. the possibility of dialog windows), handle
+ # the UNMAP event here.
+ elif eventType == gdk.UNMAP:
+ self.delWidget(widget)
+ except ValueError:
+ pass
+ except: # Oops!
+ raise
+
+ def idleHandler(self, event=None):
+
+ if self.engine.isComplete():
+ return False
+
+ if self.idletime is 0:
+ self.idletime = time.time()
+ self.lasttime = self.idletime
+
+ if self.lasttime + 1 < time.time():
+ self.lasttime += 1
+
+ if self.idletime + self.idletimeout < time.time():
+ self.engine.executePy()
+ self.idletime = 0
+
+ return True
+
+ def registerEventHandler(self):
+ """
+ Registers the method self.eventHandler as the function that
+ will receive all GDK events. This allows us to snoop on GDK.
+ """
+ if not event_handler_set:
+ raise NotImplementedError
+ else:
+ gobject.idle_add(self.idleHandler)
+ event_handler_set(self.eventHandler)
diff --git a/Experior.Activity/sbgui.pyc b/Experior.Activity/sbgui.pyc
new file mode 100644
index 0000000..85c5d38
--- /dev/null
+++ b/Experior.Activity/sbgui.pyc
Binary files differ
diff --git a/Experior.Activity/sblog.py b/Experior.Activity/sblog.py
new file mode 100755
index 0000000..928c96c
--- /dev/null
+++ b/Experior.Activity/sblog.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+sblog.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+import logging
+
+log = logging.getLogger("")
+log.setLevel(logging.DEBUG)
diff --git a/Experior.Activity/sblog.pyc b/Experior.Activity/sblog.pyc
new file mode 100644
index 0000000..621892c
--- /dev/null
+++ b/Experior.Activity/sblog.pyc
Binary files differ
diff --git a/Experior.Activity/sbpython.py b/Experior.Activity/sbpython.py
new file mode 100755
index 0000000..b80554f
--- /dev/null
+++ b/Experior.Activity/sbpython.py
@@ -0,0 +1,561 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+sbpython.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+
+import sys
+import time
+import gtk
+import logging
+from gtk import gdk
+import gobject
+from sbdecorators import *
+
+import sugar
+from sugar import graphics
+from sugar.graphics.toolcombobox import ToolComboBox
+
+class NotSupportedError(NotImplementedError):
+ def __init__(self, widget=None, command=None):
+ self.widget = widget
+ self.command = command
+ def __str__(self):
+ return repr('The widget %s [%s] does not support the command(s) %s' \
+ % (self.widget, self.widget.__class__, self.command))
+
+class WidgetDoesNotExist(ValueError):
+ def __init__(self, widget=None):
+ self.widget = widget
+ def __str__(self):
+ return repr('The widget %s could not be identified.' % self.widget)
+
+
+class wrappedWidget(object):
+ raiseExceptions = True
+
+ def __init__(self, widget, name):
+ self.widget = widget
+ self.name = name
+ self.log = logging.getLogger('w(%s)' % name)
+
+ def __getitem__(self, index):
+ """
+ Returns the indexed item.
+
+ For ComboBox and similar items, this will effectively be the n'th object.
+ Uses a helper function for each class type.
+ """
+ indexMethods = \
+ {
+ gtk.ComboBox: self.getList_GtkComboBox,
+ ToolComboBox: self.getList_SugarGraphicsCombo,
+ # gtk.Container: self.getList_Container
+ }
+
+ for classType in indexMethods:
+ if isinstance(self.widget, classType):
+ return indexMethods[classType]()[index]
+
+ def notSupportedError(self, args):
+ """
+ Wrapper for raising NotSupportedError exceptions.
+ """
+ if self.raiseExceptions:
+ raise NotSupportedError, (self.widget, args)
+ return None
+
+ def supportsSignal(self, signalName):
+ """
+ Checks to see if a GTK object supports a signal.
+
+ Checks to see if a GTK object supports a signal, via the
+ gobject.signal_lookup method. Returns True if it is supported,
+ false otherwise.
+ """
+ return gobject.signal_lookup(signalName, self.widget.__class__) != 0
+
+ def click(self):
+ """
+ Simulates a user click.
+
+ Simulates a user click by:
+ 1) Emitting a 'clicked' signal
+ 2) Calling the 'activate' method
+ """
+ self.log.info("Clicking %s" % self.name)
+
+ widgetClass = self.widget.__class__
+
+ clickedSignal = 'clicked'
+ activateMethod = 'activate'
+
+ # Attempt to emit the 'clicked' signal.
+ if self.supportsSignal(clickedSignal):
+ self.widget.emit(clickedSignal)
+ return True
+
+ # Attempt to simply 'activate' the widget.
+ elif hasattr(self.widget, activateMethod):
+ getattr(self.widget, activateMethod)()
+ return True
+
+ # Fail gracefully
+ return self.notSupportedError((clickedSignal, activateMethod))
+
+
+ def getText(self):
+ """
+ Returns the text in the widget.
+
+ Returns whatever text is being stored by the widget. This function
+ gives priority to Widget functions in the following order:
+ 1) get_text method
+ 2) label (same as getLabel)
+ 3) title (same as getTitle)
+ """
+ self.log.info("Getting text for %s" % self.name)
+
+ getText = "get_text"
+
+ # Get the text from the widget
+ # try: return self.__simpleGetter(getText)
+ # except NotSupportedError: pass
+ if hasattr(self.widget, getText):
+ return getattr(self.widget, getText)()
+
+ # Special handling for sugar ToolComboBox
+ if isinstance(self.widget, ToolComboBox):
+ logging.fatal("YES!!!")
+ return self.widget.combo.get_active_item()[0]
+
+ # Try the label
+ try: return self.label
+ except NotSupportedError: pass
+
+ # Try the title
+ try: return self.title
+ except NotSupportedError: pass
+
+ # Fail
+ return self.notSupportedError((getText,"label","title"))
+
+ def typeText(self, val):
+ """
+ Simulates user text entry.
+
+ Simulates a user typing into a widget. Inserts the text at the
+ current insertion location, via:
+ 1) Emits the 'insert-at-cursor' signal.
+ """
+ self.log.info("Adding text for %s to %s" % (self.name, val))
+
+ terminalMethod = "feed_child"
+ insertAtCursor = 'insert-at-cursor'
+
+ if self.supportsSignal(insertAtCursor):
+ self.widget.emit(insertAtCursor, val)
+ return True
+
+ # --- TERMINAL.ACTIVITY HACK ---
+ # vte.Terminal-specific typing
+ if hasattr(self.widget, terminalMethod):
+ self.widget.feed_child(val)
+ return True
+
+ return self.notSupportedError(insertAtCursor, terminalMethod)
+
+ def setText(self, val):
+ """
+ Sets the text for the widget.
+
+ Sets the text for the widget to the user-provided string.
+ Uses the following procedures to attempt to set the text:
+ 1) Calls 'set_text' method
+ 2) Set the 'label' property
+ 3) Set the 'title' property
+ 4) A Terminal-specific method, 'feed_child'
+ 5) Set the text via 'typeText'
+ """
+ self.log.info("Setting text for %s to %s" % (self.name, val))
+
+ setText = "set_text"
+
+ # --- GENERAL APPROACH ---
+ # Try simply setting the text...
+ try:
+ self.__simpleSetter(setText, val)
+ return True
+ except NotSupportedError: pass
+ # if hasattr(self.widget, setText):
+ # getattr(self.widget, setText)(val)
+ # return True
+
+ # Try setting the label
+ try:
+ self.label = val
+ return True
+ except NotSupportedError: pass
+
+ # Try setting the title
+ try:
+ self.title = val
+ return True
+ except NotSupportedError: pass
+
+ # --- TEXT APPENDING ---
+ # Try to just insert the text at the given point...
+ try:
+ self.typeText(val)
+ return True
+ except NotSupportedError:
+ pass
+
+ # Fail
+ return self.notSupportedError((setText,"label","title"))
+
+ def delete(self, numberOfTimes, deleteType):
+ """
+ Simulates user pressing the 'delete' key.
+
+ Simulates user pressing the 'delete' key a given number of times,
+ with a flexible deletion type (e.g. characters, words, lines)
+ """
+ # Note that we must negate numberOfTimes here, because it is
+ # re-negated inside of the 'backspace' call.
+ return backspace(-numberOfTimes, deleteType)
+
+ def backspace(self, numberOfTimes=1, deleteType=gtk.DELETE_CHARS):
+ """
+ Simulates the backspace keypress.
+
+ Simulates the backspace keypress. numberOfTimes times.
+ If numberOfTimes is negative, simulate the 'delete' keypress.
+ """
+ backspace = 'backspace'
+ deleteFromCursor = 'delete-from-cursor'
+
+ # Try the 'deleteFromCursor' approach, as it is very flexible in the
+ # number of ways to delete content.
+ if self.supportsSignal(deleteFromCursor):
+ self.widget.emit(deleteFromCursor, deleteType, -numberOfTimes)
+
+ # Try the standard 'backspace' command. Note that this will not work
+ # for negative quantities.
+ elif self.supportsSignal(backspace) and numberOfTimes >= 0:
+ for i in range(0, numberOfTimes):
+ self.widget.emit(backspace)
+ return True
+
+ else:
+ return self.notSupportedError((backspace, deleteFromCursor))
+
+ def doFocus(self, setFocus=None):
+ """
+ Either sets or gets the focus for the widget.
+ """
+ if setFocus is None:
+ return self.widget.flags() & gtk.HAS_FOCUS
+ elif setFocus:
+ self.widget.grab_focus()
+ return True
+
+ def getInfo(self):
+ """
+ Returns a bunch of information about the widget.
+ """
+ def getClasses(object):
+ """
+ Returns a list containing the class that the object is an instance of,
+ and all of the classes that the instance inherits from.
+ For example:
+ >>> class A: pass
+ >>> class B(A): pass
+ >>> class C(B): pass
+ >>> x = C()
+ >>> list = getClasses(x)
+ >>> list
+ [<class __main__.C at 0x6a1e0>, <class __main__.B at 0x6a1b0>,
+ <class __main__.A at 0x6a180>]
+ >>> for i in list:
+ ... print "Is instance of " + str(i) + "? " + str(isinstance(x,i))
+ ...
+ Is instance of __main__.C? True
+ Is instance of __main__.B? True
+ Is instance of __main__.A? True
+ """
+ # If the passed object is an instance of a class, it will have a
+ # __class__ attribute.
+ if hasattr(object,"__class__"):
+ recursionData = [object.__class__]
+
+ # Include the lowest-level class in the heirarchy tree
+ # Iterate through all of the base classes
+ for _class in object.__class__.__bases__:
+ if not _class is object:
+ recursionData.append(_class)
+ recursionData.extend(getClasses(_class))
+ # Otherwise, the object -is- a class, and it will have a __bases__
+ # attribute.
+ elif hasattr(object,"__bases__"):
+ # Iterate through all of the base classes. Note that we do NOT add
+ # the class itself here, as that is only done above, on the first
+ # call.
+ for _class in object.__bases__:
+ recursionData.append(_class)
+ recursionData.extend(getClasses(_class))
+ return recursionData
+
+ # ------ BEGIN INFO() METHOD -------
+ infoStr = "\n%s" % getClasses(self.widget)
+
+ l = dir(self.widget)
+ for i in l:
+ infoStr+= "\n> %s" % i
+
+ return infoStr
+
+ def __simpleGetter(self, method):
+ """
+ Wrapper for simple 'get' methods
+
+ Wrapper for simple 'get' methods (like get_label), that fails gracefully
+ if the method is not available for the widget object.
+ """
+ self.log.info("Getting %s for %s" % (method, self.name))
+ if hasattr(self.widget, method):
+ return getattr(self.widget, method)
+
+ return self.notSupportedError(method)
+
+ def __simpleSetter(self, method, val):
+ """
+ Wrapper for simple 'set' methods
+
+ Wrapper for simple 'set' methods (like get_label), that fails
+ gracefully if the method is not available for the widget object.
+ """
+ self.log.info("Setting %s to %s for %s" % (method, val, self.name))
+ if hasattr(self.widget, method):
+ getattr(self.widget, method)(val)
+ return True
+
+ return self.notSupportedError(method)
+
+ def getTitle(self):
+ """
+ Returns the widget's title.
+ """
+ return self.__simpleGetter('get_title')
+
+ def setTitle(self, val):
+ """
+ Sets the widget's title
+ """
+ return self.__simpleSetter('set_title', val)
+
+ def getLabel(self):
+ """
+ Returns the widget's label.
+ """
+ return self.__simpleGetter('get_label')
+
+ def setLabel(self, val):
+ """
+ Sets the widget's label
+ """
+ return self.__simpleSetter('set_label', val)
+
+ def getListFormat(self, item):
+ """
+ Converts a ComboBox or ToolComboBox's entries into a list
+
+ Converts a ComboBox or ToolComboBox's entries into a list. This is
+ useful in enumerating the entries in a ComboBox for selection.
+ """
+ retVal = []
+
+ if isinstance(item, ToolComboBox):
+ retVal = self.getList_GtkComboBox(item)
+ elif isinstance(item, gtk.ComboBox):
+ retVal = self.getList_SugarGraphicsCombo()
+
+ return retVal
+
+ def getList_GtkComboBox(self, combo):
+ """
+ getListFormat handler for gtk.ComboBo objects.
+ """
+ index = combo.get_active()
+ if index == -1:
+ index = 0
+
+ model = combo.get_model()
+ row = model.iter_nth_child(None, index)
+
+ if not row:
+ return None
+
+ listOfValues = []
+
+ for i in range(0, len(model)):
+ try:
+ item = model[i]
+ listOfValues.append(item)
+ except IndexError:
+ break
+ return listOfValues
+
+ def getList_SugarGraphicsCombo(self):
+ """
+ getListFormat handler for sugar.graphics.ComboBox objects.
+ """
+ tempList = self.getList_GtkComboBox(self.widget.combo)
+
+ returnList = []
+ for entry in tempList:
+ returnList.append(entry[1])
+
+ return returnList
+
+ def getSelected_SugarGraphicsCombo(self):
+ """
+ getSelected handler for sugar.graphics.combo* objects.
+ """
+ active = self.getSelected_ComboBox(self.widget.combo)
+
+ if len(active) > 1:
+ return active[1]
+ elif len(active) == 1:
+ return active[0]
+ return active
+
+ def getSelected_ComboBox(self, combo=None):
+ """
+ getSelected handler for gtk.ComboBox objects.
+ """
+ if combo is None:
+ combo = self.widget
+
+ index = combo.get_active()
+ if index == -1:
+ index = 0
+
+ row = combo.get_model().iter_nth_child(None, index)
+ if not row:
+ return None
+ return combo.get_model()[row]
+
+ def getSelected(self):
+ """
+ Returns the item selected in a gtk.ComboBox or sugar.graphics.ToolComboBox
+ """
+ self.log.info("Getting selected entry")
+ # Handle for the ComboBox...
+ if isinstance(self.widget, gtk.ComboBox):
+ return self.getSelected_ComboBox(self.widget)
+
+ # Special handling for sugar ToolComboBox
+ if isinstance(self.widget, ToolComboBox):
+ return self.getSelected_SugarGraphicsCombo()
+
+ try: return self.__simpleGetter('get_active_text')
+ except NotSupportedError: pass
+
+ try:
+ i = self.widget.get_active()
+ mod = self.widget.get_model()
+ return mod[i]
+ except:
+ pass
+
+ return self.notSupportedError('get_active_text', 'get_model')
+
+ def setSelected(self, val):
+ """
+ Sets the item selected in a gtk.ComboBox or sugar.graphics.ToolComboBox
+ """
+ self.log.info("Setting selected entry")
+ # If textual: Enumerate all of the selections
+ # If numeric: set selected
+ combo = self.widget
+
+ # Special handling for ToolComboBox
+ if isinstance(self.widget, ToolComboBox):
+ combo = self.widget.combo
+
+ if isinstance(combo, gtk.ComboBox):
+ # If we were provided with a string, get the numerical offset of
+ # the provided entry.
+ if isinstance(val, str):
+ l = self.getListFormat(combo)
+ if val in l:
+ val = l.index(val)
+
+ # Use the index to set the active combobox item
+ if isinstance(val, int):
+ combo.set_active(val)
+ return
+
+ return self.notSupportedError('set_active')
+
+
+ text = property(getText, setText)
+ title = property(getTitle, setTitle)
+ label = property(getLabel, setLabel)
+
+ focus = property(doFocus, doFocus)
+ selected = property(getSelected, setSelected)
+ info = property(getInfo)
+
+
+class widgetRegistry():
+ gui = None
+
+ def __init__(self):
+ self.widgets = {}
+ self.log = logging.getLogger('wrappedWidget')
+ self.log.info("Instantiated widgetRegistry")
+
+ def __getitem__(self, which):
+ """
+ Allows us to select widgets like a dictionary.
+ """
+
+ # If we do not already have the Widget wrapped in a wrappedWidget,
+ # do so now.
+ if which not in self.widgets:
+ widget = self.gui.getWidgetByName(which)
+
+ self.log.info("Fetched widget %s [%s]" % (which, which.__class__))
+
+ if widget is None:
+ raise WidgetDoesNotExist, which
+
+ wrapped = wrappedWidget(widget, which)
+ self.setWidget(which, wrapped)
+
+ # Return the wrappedWidget object.
+ return self.widgets[which]
+
+ def setWidget(self, which, value):
+ self.widgets[which]=value
+
+# Create the 'sbwidgets' instance.
+if not globals().has_key("sbwidgets"):
+ sbwidgets = widgetRegistry() \ No newline at end of file
diff --git a/Experior.Activity/sbpython.pyc b/Experior.Activity/sbpython.pyc
new file mode 100644
index 0000000..a62324e
--- /dev/null
+++ b/Experior.Activity/sbpython.pyc
Binary files differ
diff --git a/Experior.Activity/sbpython_script.py b/Experior.Activity/sbpython_script.py
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/Experior.Activity/sbpython_script.py
diff --git a/Experior.Activity/sbrpcserver.py b/Experior.Activity/sbrpcserver.py
new file mode 100755
index 0000000..e521a18
--- /dev/null
+++ b/Experior.Activity/sbrpcserver.py
@@ -0,0 +1,419 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+sbrpcserver.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+import binascii
+import logging
+import optparse
+import os
+import random
+import sblog
+import sys
+import time
+import xmlrpclib
+
+from SimpleXMLRPCServer import SimpleXMLRPCServer
+try:
+ from sbconfig import host, port
+except ImportError:
+ from sbconfig_sample import host, port
+
+def proxyString():
+ return "http://%s:%s/" % (host, str(port))
+
+def rebuildMarshalledObject(obj, dictionary):
+ for key in dictionary:
+ setattr(obj, key, dictionary[key])
+
+class sugarbotSession():
+ def __init__(self,ID=0):
+ self.id = ID
+ # self.responses = []
+ self.responses = {}
+ self.currentScript = -1
+ self.scriptName = ""
+ self.failureText = {}
+ # self.log = logging.getLogger("%s" % ID)
+
+ def getSuccessValue(self):
+ retval = 0
+
+ failed = [self.responses[k] for k in self.responses if not self.responses[k]]
+ if failed:
+ retval = 1
+ return retval
+
+ log = property(lambda self: logging.getLogger(str(self.id)))
+
+class sbRpcServer(SimpleXMLRPCServer):
+ sugarbotActivityVar = 'sugarActivityName'
+
+ """
+ Sugarbot RPC Server
+
+ Responsible for listening on the XML-RPC port (defined as
+ sbconfig.port). The object loads the scripts provided
+ on the command-line as individual text lines. It then provides those
+ lines of text over XML-RPC to the XML-RPC client. The client is
+ responsible for parsing the lines into meaningful objects/functions.
+
+ The list of files, as well as each file's contents, are kept entirely in
+ memory. This may lead to issues in the future with particularly large
+ script files, but this is currently not a problem.
+ """
+ def __init__(self, args=[], xmlport=port, kill=False, restart=False):
+ # Random port?
+ if xmlport is None:
+ xmlport = random.randint(1024,65000)
+ self.port = xmlport
+
+ # Create the RPC server
+ SimpleXMLRPCServer.__init__(self, (host, xmlport),
+ allow_none=True, logRequests=False)
+
+ # Create the logger
+ self.log = self.initializeLogging()
+ self.log.info("Listening on port %i" % xmlport)
+
+ # A listing of the filenames for each script
+ self.listOfScripts = []
+
+ # Keep list of all of the clients
+ self.clients = {0: sugarbotSession(0)}
+
+ # Misc other stuffs...
+ self.kill = kill
+ self.restart = restart
+ self.log.info("Kill: %s\tRestart: %s" % (kill,restart))
+
+ # All of the arguments should be filenames for files to parse.
+ for arg in args:
+ self.addScript(arg)
+
+ # Register all of the functions so that callers can use them
+ self.registerFunctions()
+
+ # Initialize the random seed for generating client ID's
+ self.initRandomSeed()
+
+ def testConnectivity(self):
+ """
+ This function exists so that the client can test the connection to the
+ XML-RPC server. The xmlrpclib throws a socket.error if a function is
+ called when the ServerProxy object is not connected.
+ This provides a simple method so that we don't have to worry
+ about screwing with the internal state of other stuff.
+ """
+ pass
+
+ def initRandomSeed(self):
+ """
+ Initializes the random seed using os.urandom.
+ """
+ # Initialize the random seed...
+ seed = 0
+ try:
+ seed = long(binascii.hexlify(os.urandom(64)), 16)
+ except NotImplementedError:
+ seed = time.time()
+ random.seed(seed)
+
+ def generateSessionID(self):
+ """
+ In the event a client does not specify an identifier, provide one.
+ """
+ return random.randint(0, sys.maxint)
+
+ def initializeLogging(self):
+ """
+ Initialize logging for the sbRpcServer object. This provides logging
+ of INFO and above to the terminal, and all statements go to
+ a file named sbRpcServer.log.
+ """
+ if __name__ == '__main__':
+ logging.basicConfig(level=logging.DEBUG,
+ format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
+ datefmt='%m-%d %H:%M',
+ filename='sbRpcServer.log')
+
+ # define a Handler which writes INFO messages or higher to the sys.stderr
+ console = logging.StreamHandler()
+ console.setLevel(logging.INFO)
+ # set a format which is simpler for console use
+ formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
+ # tell the handler to use this format
+ console.setFormatter(formatter)
+ # add the handler to the root logger
+ logging.getLogger('').addHandler(console)
+
+ return logging.getLogger('sbRpcServer')
+
+ def registerFunctions(self):
+ """
+ Register the functions for use with the XML server.
+ Recommended internal use only.
+ """
+ self.register_function(self.addScript)
+ self.register_function(self.completionStatus)
+ self.register_function(self.fail)
+ self.register_function(self.generateSessionID)
+ self.register_function(self.getActivityName)
+ self.register_function(self.getKillFlag)
+ self.register_function(self.getRestartFlag)
+ self.register_function(self.getScript)
+ self.register_function(self.numberOfScripts)
+ self.register_function(self.resetClientState)
+ self.register_function(self.startScript)
+ self.register_function(self.success)
+ self.register_function(self.testConnectivity)
+
+ def numberOfScripts(self):
+ """
+ Returns the number of scripts for execution.
+ """
+ return len(self.listOfScripts)
+
+ def haveClient(self,ID):
+ """
+ Determine whether or not we have a given client in tracking.
+ """
+ return self.clients.has_key(ID)
+
+ def getClient(self, ID):
+ """
+ Returns the sugarbotSession object corresponding to the provided ID.
+
+ If such a sugarbotSession object does not exist, it is created.
+ """
+ if not self.haveClient(ID):
+ self.clients[ID] = sugarbotSession(ID)
+
+ return self.clients[ID]
+
+ def completionStatus(self,ID=0):
+ """
+ Returns the completion status of all of the scripts as a list.
+ For example, if there were a total of three scripts, and the second
+ script had a command that did not complete successfully, the return
+ value would be:
+ [True, False, True]
+
+ If no failures were reported:
+ [True, True, True]
+
+ All values are initialized to False. If a script is still running,
+ then at least one of the result-values will be False.
+
+ Removes the client from tracking. When the client re-connects, it
+ will effectively have a clean slate.
+ """
+ retval = []
+ if self.haveClient(ID):
+ retval = self.clients[ID]
+ self.resetClientState(ID)
+ else:
+ retval = None
+
+ return retval
+
+ def resetClientState(self, ID=0):
+ """
+ Clears a client from tracking.
+
+ When the client re-connects, it will start with a clean slate.
+ """
+ if self.haveClient(ID):
+ client = self.getClient(ID)
+
+ # Get a completed ratio
+ r = client.responses
+ successes = len([r[k] for k in r if r[k] is True])
+ completed = len(r)
+ overall = len(self.listOfScripts)
+ self.clients[ID].log.info("Disconnected [%s\%s\%s]" % \
+ (successes, completed, overall))
+ del self.clients[ID]
+
+ def scriptOutOfBounds(self,ID):
+ """
+ Checks to see if a client's script index is out-of-bounds.
+ """
+ client = self.getClient(ID)
+
+ if client.currentScript < 0:
+ return True
+
+ if client.currentScript >= len(self.listOfScripts):
+ return True
+
+ def success(self, ID=0):
+ """
+ This method is called after the successful completion of a script
+ """
+ client = self.getClient(ID)
+ client.log.info("Success (%s)" % client.scriptName)
+ client.responses[client.scriptName] = True
+
+ def modifyTraceBackText(self, text, ID=0):
+ """
+ Replaces '<string>' with the script name in a backtrace report.
+
+ This is useful in determining _which_ script failed execution.
+ """
+ client = self.getClient(ID)
+
+ if "File \"<string>\"" in text:
+ # Get the text..
+ replacementText = "Sugarbot Script: '%s'" % client.scriptName
+
+ # Replace the string with the filename
+ text = text.replace("<string>", replacementText)
+ return text
+
+ def fail(self, status="No status provided", ID=0):
+ """
+ This method is called if, for some reason, the client needs to disconnect
+ prematurely. A status message/reason is required.
+ """
+ client = self.getClient(ID)
+
+ # If the client is sending us exception text, replace that select
+ # portions of the text to be more useful.
+ status = self.modifyTraceBackText(status, ID)
+
+ # Print the error
+ client.log.error("%s" % status)
+ client.responses[client.scriptName] = False
+ client.failureText[client.scriptName] = status
+
+ return status
+
+ def startScript(self,ID=0):
+ """
+ Increments the internal script counter, looping back to the first
+ script if necessary. This should be the first method that a client
+ calls.
+ """
+ # Get the client. This will create it if it does not exist.
+ client = self.getClient(ID)
+
+ # Next script! (Note that the value is initialized to be -1)
+ client.currentScript += 1
+
+ # Prevent overflows if, for some reason, we loop back to script 0
+ if self.scriptOutOfBounds(ID):
+ client.currentScript = 0
+
+ # Update the client's script name
+ client.scriptName = self.listOfScripts[client.currentScript]
+
+ # Pretty status message...
+ client.log.info("Starting %s" % client.scriptName)
+
+ # Make room for another response (default to failure)
+ client.responses[client.scriptName] = False
+
+ return True
+
+ def getScript(self,ID=0):
+ """
+ Returns the script that the client should execute.
+ """
+ client = self.getClient(ID)
+ client.log.info("Getting Script: %s" % client.scriptName )
+
+ f = open(self.listOfScripts[client.currentScript])
+ listOfLines = f.readlines()
+ longString = ''
+ for line in listOfLines:
+ longString += line
+
+ f.close()
+
+ return longString
+
+ def getActivityName(self, ID=0, which=None):
+ """
+ Imports from the specified script file in order to
+ """
+ client = self.getClient(ID)
+ if which is None:
+ which = client.currentScript
+
+ if which == -1:
+ raise IndexError, "Invalid script index. If calling " + \
+ "getActivityNameMake without arguments, make sure that " + \
+ "startScript gets called first."
+
+ try:
+ moduleName = self.listOfScripts[which]
+ index = moduleName.find(".py")
+ if index is not -1:
+ moduleName = moduleName[:index]
+
+ execStr = 'from %s import %s' % \
+ (moduleName, self.sugarbotActivityVar)
+
+ evalStr = '%s' % self.sugarbotActivityVar
+
+ exec execStr
+ return eval(evalStr)
+ except:
+ raise
+
+ def getKillFlag(self):
+ return self.kill
+
+ def getRestartFlag(self):
+ return self.restart
+
+ def addScript(self,scriptPath):
+ """
+ Adds a script to the internal list of scripts. This causes the parser
+ to load the script contents into memory for fast/easy access.
+ """
+ self.listOfScripts.append(scriptPath)
+
+ activityName = self.getActivityName(which=len(self.listOfScripts)-1 )
+ self.log.info("Added script %s [Activity %s]" \
+ % (scriptPath, activityName) )
+
+
+def main(argv=None):
+ p = optparse.OptionParser()
+ p.add_option('--no-restart', dest='restart', action='store_false',default=True,
+ help='do NOT restart sugarbot after execution has completed')
+ p.add_option('--no-kill', dest='kill', action='store_false',default=True,
+ help='do NOT kill sugar after all sugarbot scripts have executed')
+
+ (options,args) = p.parse_args()
+
+ if len(args) < 1:
+ p.print_help()
+ return 1
+
+ server = sbRpcServer(args, kill=options.kill, restart=options.restart)
+
+ try:
+ server.serve_forever()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
+
+if __name__ == '__main__':
+ main() \ No newline at end of file
diff --git a/Experior.Activity/sbrpcserver.pyc b/Experior.Activity/sbrpcserver.pyc
new file mode 100644
index 0000000..4704065
--- /dev/null
+++ b/Experior.Activity/sbrpcserver.pyc
Binary files differ
diff --git a/Experior.Activity/script_calculate.py b/Experior.Activity/script_calculate.py
new file mode 100755
index 0000000..93f0fa4
--- /dev/null
+++ b/Experior.Activity/script_calculate.py
@@ -0,0 +1,35 @@
+import time
+import logging
+
+sugarActivityName = 'Calculate'
+
+def sugarbot_main(widgets):
+ # Test 'selected' functionality.
+ assert widgets['Share with:'].selected == "Private"
+ widgets['Share with:'].selected = "My Neighborhood"
+ assert widgets['Share with:'].selected == "My Neighborhood"
+
+ # Test widget fetching/assignment
+ one = widgets['1']
+ plus = widgets['+']
+ enter = widgets['enter']
+
+ for i in range(0,5):
+ # Test click
+ one.click()
+ plus.click()
+ one.click()
+
+ # Test Entry text assignment
+ assert widgets['TextEntry'].text == '1+1'
+
+ enter.click()
+
+ assert len(widgets['TextEntry'].text) == 0
+
+ time.sleep(1)
+
+ # More Entry text assignment
+ widgets['TextEntry'].text = "1+5"
+ assert widgets['TextEntry'].text == '1+5'
+ enter.click()
diff --git a/Experior.Activity/script_calculate.pyc b/Experior.Activity/script_calculate.pyc
new file mode 100644
index 0000000..e079466
--- /dev/null
+++ b/Experior.Activity/script_calculate.pyc
Binary files differ
diff --git a/Experior.Activity/script_terminal.py b/Experior.Activity/script_terminal.py
new file mode 100755
index 0000000..f45e6eb
--- /dev/null
+++ b/Experior.Activity/script_terminal.py
@@ -0,0 +1,11 @@
+import time
+import logging
+
+sugarActivityName = 'Terminal'
+
+def sugarbot_main(widgets):
+ #assert 1
+ term = widgets['VteTerminal']
+ term.typeText("whoami\r")
+ term.typeText("ls -la\r")
+ term.typeText("exit\r") \ No newline at end of file
diff --git a/Experior.Activity/script_terminal.pyc b/Experior.Activity/script_terminal.pyc
new file mode 100644
index 0000000..9c63aa1
--- /dev/null
+++ b/Experior.Activity/script_terminal.pyc
Binary files differ
diff --git a/Experior.Activity/setup.py b/Experior.Activity/setup.py
new file mode 100755
index 0000000..a74cffd
--- /dev/null
+++ b/Experior.Activity/setup.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+setup.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+import sys
+
+from sugar.activity import bundlebuilder
+bundlebuilder.start()
+
+
+#try:
+ #if len(sys.argv) < 2 or sys.argv[1] == "install":
+ #from sugar.activity import bundlebuilder
+ #bundlebuilder.start("sugarbot")
+ #elif sys.argv[1] == "test":
+ ## nosetests
+ #pass
+#except ImportError:
+ #import os
+ #os.system("find ./ | sed 's,^./,sugarbot.activity/,g' > MANIFEST")
+ #os.system('rm sugarbot.xo')
+ #os.chdir('..')
+ #os.system('zip -r sugarbot.xo sugarbot.activity')
+ #os.system('mv sugarbot.xo ./sugarbot.activity')
+ #os.chdir('sugarbot.activity')
diff --git a/Experior.Activity/sugarbot.py b/Experior.Activity/sugarbot.py
new file mode 100755
index 0000000..717ffed
--- /dev/null
+++ b/Experior.Activity/sugarbot.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+sugarbot.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+import gobject
+import gtk
+import logging
+import os
+import sblog
+import socket
+import sys
+
+from xmlrpclib import ServerProxy
+
+from sugar.activity import activity
+#from sugar.activity import registry
+from jarabe.model.bundleregistry import get_registry
+
+from sbrpcserver import sbRpcServer, proxyString
+
+# For reading GDK.Event's
+from sbgui import sbGUI
+
+class sugarbot(activity.Activity):
+ def __dynamicImport(self, fullname, path=None):
+ """
+ Handles emulation of the target Activity.
+
+ Dynamically modifies the module-search path, and imports an object from
+ a module. Some fancy work is done to get that to work properly.
+ @param fullname: The module to import, example calculate.Calculate.
+ @param path: If necessary, the path to the imported module.
+ """
+ module = None
+ module_name = ""
+ class_name = ""
+
+ if fullname is None:
+ return self.__parentClass
+
+ try:
+ # <hack>=========================================================
+ # This could probably be cleaned up or refactored into separate
+ # functions. However, the code is short enough that it is not
+ # likely worth it.
+ if path != None:
+ sys.path.append(path)
+
+ splitted_module = fullname.rsplit('.', 1)
+
+ if len(splitted_module) >= 2:
+ module_name = splitted_module[0]
+ class_name = splitted_module[1]
+
+ if module_name is not None and class_name is not None and \
+ len(module_name) > 0 and len(class_name) > 0:
+ module = __import__(module_name)
+
+ for comp in module_name.split('.')[1:]:
+ module = getattr(module, comp)
+ # </hack>========================================================
+ except ImportError:
+ raise ImportError, \
+ "Error in sugarbot._dynamicImport(%s,%s)" % (fullname,path)
+
+ finally:
+ if hasattr(module, class_name):
+ self.__parentClass = getattr(module, class_name)
+ else: # Failsafe
+ self.__parentClass = activity.Activity
+
+ return self.__parentClass
+
+ def __cloneActivity(self,sugarHandle):
+ """
+ Starts the cloned activity, where self.__parentClass is the activity
+ class. This is performed by [1] inheriting from the parentClass,
+ and [2] calling parentClass.__init__.
+ """
+ if self.__parentClass is None:
+ raise AttributeError, "self.__parentClass not defined properly."
+
+ else:
+ sugarbot.__bases__ = (self.__parentClass,)
+ self.__parentClass.__init__(self,sugarHandle)
+
+ def __getActivityList(self):
+ """
+ Gets a list of activities from the registry. Stores this list in
+ self.__activityList.
+ """
+ # Prevent looking up all of the activities multiple times.
+ if not hasattr(self,"__activityList"):
+ #self.__activityList = registry.get_registry().get_activities()
+ self.__activityList = get_registry()._bundles
+ return self.__activityList
+
+ # If we didn't get any activities, something went wrong.
+ if len(self.__activityList) < 1:
+ raise "Activity list is empty. Cannot get activity info!"
+
+ return None
+
+ def __selectActivity(self,name):
+ """
+ Selects an activity from the activityList by name. This allows
+ simpler access to the list of activities.
+ (For example, one can specify only 'Calculate' instead of
+ 'org.laptop.Calculate' or 'calculate.Calculate').
+ @param name: The name of the activity (e.g. 'Calculate')
+ """
+ # Get the list of activities if it does not already exist
+ activityList = self.__getActivityList()
+
+ # Initialization of some variables...
+ self.__path = None
+ self.__importClass = None
+ self.__className = None
+
+ # Iterate through the activity list
+ for activity in activityList:
+ if activity.get_name() == name:
+ self.__path = activity.get_path()
+ self.__importClass = activity.get_command().split()[-1]
+ self.__className = self.__importClass.split(".")[-1]
+ self.log.debug("Importing class %s" % name)
+ return
+
+ # If we ever get here, that means we didn't find anything...
+ if (self.__path is None) and (self.__importClass is None) and \
+ (self.__className is None):
+ raise NameError, "Could not find '%s' in activity list." % name
+
+ def __initializeScript(self):
+ """
+ Initialize the script on the XML-RPC server.
+ Returns the name of the Activity that should be instantiated
+ """
+ rpc = self.__xmlRPC
+
+ try:
+ self.sessID = os.environ['SUGARBOT_ID']
+ except KeyError:
+ self.sessID = 0
+
+ # Start the script
+ if not rpc.startScript(self.sessID):
+ rpc.fail("Could not start the script!", self.sessID)
+ exit()
+
+ # Get our activity name
+ activityName = rpc.getActivityName(self.sessID)
+ if activityName is None:
+ rpc.fail('Bad activity name provided', self.sessID)
+ exit()
+
+ self.log.info("Activity is %s" % activityName)
+ return activityName
+
+
+ def __init__(self, handle):
+ """
+ Performs setup, and runs the specified activity.
+ """
+ self.log = logging.getLogger('sugarbot')
+
+ # Set up threading...
+ gtk.gdk.threads_init()
+
+ # Handle is set to 'None' for testing purposes via Nose. Obviously,
+ # if Sugar sets the handle to None, there are other problems...
+ if handle is None:
+ return
+
+ try:
+ # Create the RPC connection object
+ self.__xmlRPC = ServerProxy(proxyString())
+
+ # Set up the sbGUI object for automation
+ self.__sbgui = sbGUI(self, self.__xmlRPC)
+
+ # Get our activity name
+ activityName = self.__initializeScript()
+
+ # Actually clone the activity
+ self.__selectActivity(activityName)
+ self.__dynamicImport(self.__importClass,self.__path)
+ self.__cloneActivity(handle)
+ except socket.error:
+ sys.log.error("====== COULD NOT CONNECT TO XML-RPC SERVER ======")
+ sys.exit(-1)
diff --git a/Experior.Activity/sugarbot.pyc b/Experior.Activity/sugarbot.pyc
new file mode 100644
index 0000000..86dddaa
--- /dev/null
+++ b/Experior.Activity/sugarbot.pyc
Binary files differ
diff --git a/Experior.Activity/sugarbotlauncher.py b/Experior.Activity/sugarbotlauncher.py
new file mode 100755
index 0000000..29d8d7c
--- /dev/null
+++ b/Experior.Activity/sugarbotlauncher.py
@@ -0,0 +1,298 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+sugarbot-launcher.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+import logging
+import os
+import signal
+import sys
+import socket
+
+from subprocess import Popen
+from time import time,sleep
+from xmlrpclib import ServerProxy
+
+# Set the Sugarbot path env var if it has not already been set
+if not os.environ.has_key('SUGARBOT_PATH'):
+ os.environ['SUGARBOT_PATH']=os.getcwd()
+
+# Add the sugarbot path to the include-path
+sys.path.append(os.environ['SUGARBOT_PATH'])
+
+# Import sugar-specific stuff
+from sbrpcserver import proxyString, rebuildMarshalledObject, sugarbotSession
+try:
+ from sbconfig import clientName
+except ImportError:
+ from sbconfig_sample import clientName
+
+class SugarProcessHandler():
+ """
+ Handles launching and monitoring of the Sugar process.
+ """
+ def __init__(self):
+ # Set the environment variable to emulate, and the executed scripts.
+ os.environ['SUGARBOT_EMULATOR']='1'
+
+ # Get the connection to the XML-RPC server
+ self.xml = self.connectToXMLRPC()
+ logging.info("Connected to XML-RPC server %s" % proxyString())
+
+ # Get our ID and reset the state
+ self.ID = self.getSugarbotClientID()
+ self.xml.resetClientState(self.ID)
+ logging.info("Using session ID %s" % self.ID)
+
+ def getSugarbotClientID(self):
+ """
+ Retrieves whatever ID we should be using. This is either set by the
+ environment variables, the configuration file, or generated by the
+ server.
+ """
+ # If we have not specified a sugarbot ID, specify one now
+ if not os.environ.has_key('SUGARBOT_ID'):
+ if not clientName:
+ os.environ['SUGARBOT_ID']=str(xml.generateSessionID())
+ else:
+ os.environ['SUGARBOT_ID']=clientName
+
+ return os.environ['SUGARBOT_ID']
+
+ def connectToXMLRPC(self):
+ """
+ Connects to the ML-RPC server, tests connectivity.
+ """
+ xml = ServerProxy(proxyString())
+ try:
+ xml.testConnectivity()
+ except:
+ logging.fatal('Could not connect to the XML-RPC server')
+ sys.exit(1)
+
+ return xml
+
+ def launchSugar(self):
+ """
+ Launches the sugar-emulator process and waits for it to finish.
+ """
+ # Launch the process
+ self.pid = Popen('sugar-emulator')
+ self.waitForSugarbotExecution()
+
+ def waitForSugarbotExecution(self):
+ """
+ Waits a certain amount of time for Sugar to quit.
+
+ If Sugar does not die in the alloted time, it is killed.
+ """
+ # Wait five minutes for the tests to execute? Why not.
+ start = time()
+ wait = 60*5
+ done = start + wait
+
+ # We've waited long enough. Kill it!
+ while self.pid.poll() is None and done > time():
+ sleep(0.1)
+ if self.pid.poll() is None:
+ logging.fatal("Had to send SIGTERM to Sugar process")
+ os.kill(self.pid.pid, signal.SIGTERM)
+
+ def getReturnValue(self):
+ """
+ Determines whether all of the tests succeeded, or there was a failure.
+
+ 0 = All tests succeeded
+ 1 = At least one failure
+ """
+ # Get the completion status...
+ sessionDict = self.xml.completionStatus(self.ID)
+ if sessionDict is None:
+ logging.error("Could not get completion status from XMLRPC server")
+ return -1
+
+ session = sugarbotSession()
+ rebuildMarshalledObject(session, sessionDict)
+
+ # Get whatever the return value should be.
+ retval = session.getSuccessValue()
+
+ # Print out the completion statuses all pretty-like
+ status = ""
+ logging.info("Script completion statuses:")
+ for script in session.responses:
+ logging.info("\t%s: %s" % (session.responses[script], script))
+
+ # if session.failureText.has_key(script) and \
+ # not session.responses[script]:
+ if not session.responses[script]:
+ logging.info("================ [%s] ================", script)
+ for line in session.failureText[script].split('\n'):
+ if len(line) > 0:
+ logging.info(line)
+ logging.info("================ [%s] ================", script)
+
+
+ # Check the number of scripts to make sure they all executed
+ numScripts = self.xml.numberOfScripts()
+ if( numScripts > len(session.responses) ):
+ retval = False
+ logging.warning("Only executed %i/%i scripts" % \
+ (numScripts,len(session.responses)) )
+
+ return retval
+
+def main():
+ s = SugarProcessHandler()
+ s.launchSugar()
+
+ retval = s.getReturnValue()
+ logging.info("Returning %s" % retval)
+
+ return retval
+
+if __name__ == "__main__":
+ main()
+
+else:
+ import pygtk
+ pygtk.require('2.0')
+ import gtk
+ import gobject
+ import time
+
+ from view.Shell import Shell
+ from model.shellmodel import ShellModel
+ from shellservice import ShellService
+
+ from view.frame.activitiestray import ActivitiesTray
+ from view.frame.activitybutton import ActivityButton
+
+ class SugarbotLauncher:
+ """
+ Autmates the launching and re-launching of Sugarbot from the main Sugar
+ GUI. This automation is handled by simulating a click on the Sugarbot
+ activity icon in the Sugar Pane.
+ """
+ activityName = "sugarbot"
+
+ def __init__(self, shell, shellModel):
+ gtk.gdk.event_handler_set(self.eventHandler)
+ self.model = shellModel
+ self.numberOfScripts = 0
+ self.shell = shell
+ self.sugarbotIsRunning = False
+ self.timesLaunched = 0
+ self.xml = ServerProxy(proxyString())
+
+ home = self.model.get_home()
+ home.connect('activity-started', self._activity_started_cb)
+ home.connect('activity-removed', self._activity_removed_cb)
+ home.connect('active-activity-changed', self._activity_active_cb)
+ home.connect('pending-activity-changed', self._activity_pending_cb)
+
+ def isSugarbotActivity(self,activity):
+ """
+ Checks to see if an 'Activity' object is the sugarbot activity.
+ """
+ if activity._activity_info.name == self.activityName:
+ if self.numberOfScripts <= 0:
+ self.doSetup(activity)
+ return True
+ return False
+
+ def doSetup(self, activity):
+ """
+ Prepares for launching the activity, given its information.
+ """
+ path = activity._activity_info.path
+ sys.path.append(path)
+
+ try:
+ self.numberOfScripts = self.xml.numberOfScripts()
+ except:
+ logging.fatal("Could not connect to XMLRPC Server")
+ sys.exit(-1)
+
+ def _activity_started_cb(self, model, activity):
+ if self.isSugarbotActivity(activity):
+ self.sugarbotIsRunning = True
+ self.timesLaunched += 1
+
+ def _activity_removed_cb(self, model, activity):
+ if self.isSugarbotActivity(activity):
+ self.sugarbotIsRunning = False
+
+ if self.xml.getKillFlag() and \
+ 1 <= self.numberOfScripts <= self.timesLaunched:
+ logging.info("Sugarbot execution completed successfully")
+ self.killSugar()
+
+ def _activity_active_cb(self, model, activity):
+ pass
+
+ def _activity_pending_cb(self, model, activity):
+ pass
+
+ def killSugar(self):
+ """
+ Sends SIGTERM to the Sugar process.
+ """
+ try:
+ if os.environ.has_key('SUGAR_EMULATOR_PID'):
+ pid = int(os.environ['SUGAR_EMULATOR_PID'])
+ os.kill(pid, signal.SIGTERM)
+ except:
+ raise
+
+ def tryToLaunchSugarbotActivity(self):
+ """
+ Attempts to launch sugarbot.
+ """
+ if self.sugarbotIsRunning or not self.xml.getRestartFlag():
+ # time.sleep(0.1)
+ return
+
+ frame = self.shell.get_frame()
+ frameBottomPanel = frame._bottom_panel
+ bottomPanelChildren = frameBottomPanel._bg.get_children()
+ tray = [k for k in bottomPanelChildren if isinstance(k,ActivitiesTray)]
+
+ if tray:
+ trayIcons = tray[0]._tray.get_children()
+ else:
+ return
+
+ activities = [k for k in trayIcons if isinstance(k, ActivityButton)]
+ sbList = [k for k in activities if \
+ k._activity_info.name == self.activityName]
+
+ if len(sbList) > 0:
+ sbList[0].emit('clicked')
+ self.sugarbotIsRunning = True
+
+ def eventHandler(self, event):
+ """
+ Intercepts GTK calls, to attempt to launch sugarbot.
+
+ Attempts to launch sugarbot at every gdk.Event emitted.
+ """
+ if event is not None:
+ gtk.main_do_event(event)
+ self.tryToLaunchSugarbotActivity()
+
diff --git a/Experior.Activity/svn-commit.tmp b/Experior.Activity/svn-commit.tmp
new file mode 100644
index 0000000..b34bcea
--- /dev/null
+++ b/Experior.Activity/svn-commit.tmp
@@ -0,0 +1,6 @@
+Hacky changes
+
+Committing changes to 0.1 release made to ge things to work.
+--This line, and those below, will be ignored--
+
+M sugarbot.py
diff --git a/Experior.Activity/test_rpcserver.py b/Experior.Activity/test_rpcserver.py
new file mode 100755
index 0000000..919e82c
--- /dev/null
+++ b/Experior.Activity/test_rpcserver.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+test_rpcserver.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+import os
+try:
+ import sbconfig
+except ImportError:
+ import sbconfig_sample
+
+from random import randint
+from sbrpcserver import *
+from xmlrpclib import ServerProxy
+
+class test_rpcServer:
+
+ files = ["fileOne.py", "fileTwo.py"]
+ activityNames = ["activityOne", "activityTwo"]
+ basicScript = \
+"""
+def sugarbot_main(var):
+ assert var
+
+"""
+ scripts = [basicScript + "sugarActivityName = '%s'" % activityNames[0],
+ basicScript + "sugarActivityName = '%s'" % activityNames[1]]
+
+ def __init__(self):
+ self.is_setup = False
+
+ def setUp(self):
+ assert not self.is_setup
+
+ # Generate a random ID
+ self.clientID = randint(1,1000)
+
+ # Create the server object.
+ self.server = sbRpcServer([], None)
+
+ # Create the script file and add it...
+ self.createScriptFiles()
+ for file in self.files:
+ self.server.addScript(file)
+
+ self.is_setup = True
+
+
+ def tearDown(self):
+ assert self.is_setup
+
+ self.server.server_close()
+ self.deleteScriptFiles()
+
+ self.is_setup = False
+
+ def createScriptFiles(self):
+ for i in range(0, len(self.scripts)):
+ f = open(self.files[i],"w+")
+ f.write(self.scripts[i])
+ f.close()
+
+ def deleteScriptFiles(self):
+ for f in self.files:
+ os.remove(f)
+
+ def test_StartScript_Reset(self):
+ self.server.startScript(self.clientID)
+
+ client = self.server.clients[self.clientID]
+ client.currentScript = 999999
+
+ self.server.startScript(self.clientID)
+
+ assert client.currentScript == 0
+ assert client.responses[client.scriptName] == False
+
+ def test_StartScript_Bounds(self):
+ # Check to see if we go beyond the bounds
+ for count in range(0,1+len(self.server.listOfScripts)):
+ self.server.startScript()
+ assert self.server.clients[0].currentScript == 0
+
+ def test_RegisteredFunctions(self):
+ expectedMethods = ['addScript',
+ 'completionStatus',
+ 'fail',
+ 'generateSessionID',
+ 'getActivityName',
+ 'getRestartFlag',
+ 'getScript',
+ 'numberOfScripts',
+ 'startScript',
+ 'success']
+ listedMethods = self.server.system_listMethods()
+
+ for method in expectedMethods:
+ if not method in listedMethods:
+ print method
+ assert 0
+
+ assert not 'NOTREGISTERED' in listedMethods
+
+ def test_getActivityName_IndexError(self):
+ try:
+ self.server.startScript(self.clientID)
+ self.server.getActivityName(self.clientID, 9999)
+ assert 0
+ except IndexError:
+ pass
+
+ def test_getActivityName_WithoutStartingScript(self):
+ try:
+ self.server.getActivityName(self.clientID)
+ assert 0
+ except IndexError:
+ pass
+
+ def test_getActivityName(self):
+ for activity in self.activityNames:
+ self.server.startScript()
+ assert self.server.getActivityName() == activity
+
+ def test_multipleCallsToGetScript(self):
+ for script in self.scripts:
+ self.server.startScript()
+ assert self.server.getScript() == script
+ \ No newline at end of file
diff --git a/Experior.Activity/test_rpcserver.pyc b/Experior.Activity/test_rpcserver.pyc
new file mode 100644
index 0000000..650aed2
--- /dev/null
+++ b/Experior.Activity/test_rpcserver.pyc
Binary files differ
diff --git a/Experior.Activity/test_sbexecutionengine.py b/Experior.Activity/test_sbexecutionengine.py
new file mode 100755
index 0000000..29582c0
--- /dev/null
+++ b/Experior.Activity/test_sbexecutionengine.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+test_sbexecutionengine.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+from sbexecutionengine import *
+
+logging.raiseExceptions = 0
+
+class failException(Exception): pass
+class successException(Exception): pass
+
+class test_sbExecutionEngine:
+
+ class fakeXmlRpc:
+ def __init__(self):
+ self.assertionValue = 1
+ self.restart = False
+ self.kill = False
+ self.status = False
+
+ def success(self, clientID=None):
+ # raise successException
+ # We can't raise exceptions on success, because of the way
+ # sbExecutionEngine works. Any exceptions call fail()
+ self.status = True
+
+ def fail(self, reason=None, clientID=None):
+ raise failException
+
+ def getRestartFlag(self):
+ return self.restart
+
+ def getKillFlag(self):
+ return self.kill
+
+ def getScript(self, dontCare):
+ return \
+"""
+def sugarbot_main(param):
+ assert param
+"""
+
+ def __init__(self):
+ self.is_setup = False
+
+ def setUp(self):
+ assert not self.is_setup
+
+ self.xml = self.fakeXmlRpc()
+ self.ee = sbExecutionEngine(None,self.xml)
+
+ self.is_setup = True
+
+ def tearDown(self):
+ assert self.is_setup
+
+ self.is_setup = False
+
+ def test_setComplete(self):
+ assert not self.ee.isComplete()
+ self.ee.executionComplete = True
+ assert self.ee.isComplete()
+
+ def test_killSugarbot(self):
+ try:
+ self.ee.killSugarbot()
+ assert 0
+ except SystemExit:
+ pass
+
+ def test_executePy_Fail(self):
+ try:
+ self.ee.widgets.__nonzero__ = lambda: False
+ self.ee.executePy()
+ assert 0
+ except failException:
+ pass
+
+ def test_executePy_Success(self):
+ # try:
+ self.ee.widgets.__nonzero__ = lambda: True
+ self.ee.executePy()
+
+ assert self.xml.status == True
+
+ def test_executePy_UnexpectedException(self):
+ try:
+ def raiseException(): raise ValueError
+
+ self.ee.widgets.__nonzero__ = raiseException
+ self.ee.executePy()
+ assert 0
+ except:
+ pass \ No newline at end of file
diff --git a/Experior.Activity/test_sbexecutionengine.pyc b/Experior.Activity/test_sbexecutionengine.pyc
new file mode 100644
index 0000000..363c69c
--- /dev/null
+++ b/Experior.Activity/test_sbexecutionengine.pyc
Binary files differ
diff --git a/Experior.Activity/test_sbgui.py b/Experior.Activity/test_sbgui.py
new file mode 100755
index 0000000..f526d5f
--- /dev/null
+++ b/Experior.Activity/test_sbgui.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+test_sbgui.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+import unittest
+import sbexecutionengine
+
+from sbgui import *
+
+class test_sbgui:
+ class fakeExecutionEngine():
+ def getCommand(self):
+ pass
+ def executeNextCommand(self):
+ pass
+ def isComplete(self):
+ return False
+
+ def __init__(self):
+ self.is_setup = False
+
+ def setUp(self):
+ assert not self.is_setup
+
+ self.gui = sbGUI(None,None)
+ self.gui.engine = self.fakeExecutionEngine()
+ self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+
+ self.is_setup = True
+
+ def tearDown(self):
+ assert self.is_setup
+
+ self.is_setup = False
+
+ def startTimer(self, timer):
+ self.timer = time.time() + timer
+
+ def timeout(self):
+ if time.time() > self.timer:
+ return True
+ return False
+
+ def test_CatchWidgetInstantiation(self):
+ wlabel = "testButton"
+ widget = gtk.Button(label=wlabel)
+
+ self.window.add(widget)
+ widget.show()
+ self.window.show()
+
+ self.startTimer(3.0)
+ while not self.timeout():
+ gtk.main_iteration(False)
+
+ if self.gui.getWidgetByName(wlabel) is widget:
+ return
+ assert 0
+
+ def test_registerEventHandler(self):
+ try:
+ self.gui.registerEventHandler()
+ except NotImplementedError:
+ assert 0
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Experior.Activity/test_sbgui.pyc b/Experior.Activity/test_sbgui.pyc
new file mode 100644
index 0000000..1722516
--- /dev/null
+++ b/Experior.Activity/test_sbgui.pyc
Binary files differ
diff --git a/Experior.Activity/test_sugarbot.py b/Experior.Activity/test_sugarbot.py
new file mode 100755
index 0000000..33b6126
--- /dev/null
+++ b/Experior.Activity/test_sugarbot.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+test_sugarbot.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+from sugarbot import *
+
+class rpcFailure(Exception):
+ pass
+
+class test_sugarbot:
+
+ class cloneTest(activity.Activity):
+ def __init__(self,x):
+ self.clonedProperly = True
+
+ class fakeXmlRpc:
+ activity = "exampleActivity"
+ def startScript(self, *args):
+ return True
+ def fail(self, reason, *args):
+ raise rpcFailure
+
+ class fakeXmlRpcGood(fakeXmlRpc):
+ def getActivityName(self, *args):
+ return self.activity
+
+ class fakeXmlRpcBad(fakeXmlRpc):
+ def getActivityName(self, *args):
+ return None
+
+ def __init__(self):
+ self.is_setup = False
+
+ def setUp(self):
+ assert not self.is_setup
+
+ self.sb = sugarbot(None)
+
+ self.is_setup = True
+
+ def tearDown(self):
+ assert self.is_setup
+
+ sugarbot.__bases__ = (activity.Activity, )
+
+ self.is_setup = False
+
+ def test_dynamicImport1(self):
+ # Attempt to import a valid module
+ assert gobject.GObject == \
+ self.sb._sugarbot__dynamicImport("gobject.GObject")
+
+ def test_dynamicImport2(self):
+ # Attempt to import a module with a bad length or None
+ assert activity.Activity == self.sb._sugarbot__dynamicImport("")
+ assert activity.Activity == self.sb._sugarbot__dynamicImport(None)
+
+ def test_dynamicImport3(self):
+ # Attempt to import a module that does not exist
+ try:
+ assert activity.Activity == \
+ self.sb._sugarbot__dynamicImport("asdf.1231231.##fw")
+ assert 0
+ except ImportError:
+ pass
+
+ def test_cloneActivity1(self):
+ self.sb._sugarbot__parentClass = None
+ try:
+ self.sb._sugarbot__cloneActivity(None)
+ assert 0
+ except AttributeError:
+ pass
+
+ def test_cloneActivity2(self):
+ self.sb._sugarbot__parentClass = self.cloneTest
+ self.sb._sugarbot__cloneActivity(None)
+
+ assert self.cloneTest in sugarbot.__bases__
+ assert self.sb.clonedProperly
+
+ def test_cloneActivity3(self):
+ assert not self.cloneTest in sugarbot.__bases__
+
+ def test_initializeScript1(self):
+ fake = self.fakeXmlRpcGood()
+ self.sb._sugarbot__xmlRPC = fake
+
+ assert fake.activity == self.sb._sugarbot__initializeScript()
+
+ def test_initializeScript2(self):
+ fake = self.fakeXmlRpcBad()
+ self.sb._sugarbot__xmlRPC = fake
+
+ try:
+ self.sb._sugarbot__initializeScript()
+ assert 0
+ except rpcFailure:
+ pass
+
+
+
diff --git a/Experior.Activity/test_sugarbot.pyc b/Experior.Activity/test_sugarbot.pyc
new file mode 100644
index 0000000..464463b
--- /dev/null
+++ b/Experior.Activity/test_sugarbot.pyc
Binary files differ
diff --git a/Experior.Activity/test_widgetIdentifier.py b/Experior.Activity/test_widgetIdentifier.py
new file mode 100755
index 0000000..83f6b3f
--- /dev/null
+++ b/Experior.Activity/test_widgetIdentifier.py
@@ -0,0 +1,254 @@
+from widgetIdentifier import *
+
+class test_widgetIdentifier:
+ def __init__(self):
+ self.is_setup = False
+
+ def setUp(self):
+ assert not self.is_setup
+
+ self.widget = gtk.Button()
+ self.name = "nameExample"
+
+ self.widget.set_name(self.name)
+
+ self.identifier = widgetIdentifier(self.widget)
+
+ self.is_setup = True
+
+ def tearDown(self):
+ assert self.is_setup
+ self.is_setup = False
+
+ def test_init(self):
+ assert self.identifier._widget == self.widget
+
+ def test_getIdentifier(self):
+ assert self.identifier.getIdentifier() == self.name
+
+ def test_checkStoredIdentifier(self):
+ assert not self.identifier.checkStoredIdentifier()
+
+ def test_setIdentifier(self):
+ assert not self.identifier.setIdentifier("GtkAnything")
+
+ name = "x"
+ assert self.identifier.setIdentifier(name) == name
+
+ def test_setWidget(self):
+ self.identifier.setWidget(None)
+ assert not self.identifier.getIdentifier()
+
+ widget = gtk.Label("")
+ name = "asdf"
+ widget.set_name(name)
+ assert not self.identifier.getIdentifier() == name
+
+ self.identifier.setWidget(widget)
+ assert self.identifier.getIdentifier() == name
+
+ def test_getStoredIdentifier(self):
+ assert not self.identifier.getStoredIdentifier() == self.name
+
+ self.identifier.getIdentifier()
+ assert self.identifier.getStoredIdentifier() == self.name
+
+ name = "x"
+ self.identifier.setIdentifier(name)
+ assert self.identifier.getStoredIdentifier() == name
+
+ def test_validateIdentifier(self):
+ assert not self.identifier.validateIdentifier(None)
+ assert not self.identifier.validateIdentifier("")
+ assert not self.identifier.validateIdentifier(1)
+ assert not self.identifier.validateIdentifier("GtkAnything")
+ assert not self.identifier.validateIdentifier("SugarToggleToolButton")
+ assert self.identifier.validateIdentifier("ValidName")
+
+class test_buttonIdentifier:
+ def __init__(self):
+ self.is_setup = False
+
+ def setUp(self):
+ assert not self.is_setup
+
+ self.name = "nameExample"
+ self.widget = gtk.Button()
+
+ self.identifier = buttonIdentifier(self.widget)
+
+ self.is_setup = True
+
+ def tearDown(self):
+ assert self.is_setup
+ self.is_setup = False
+
+ def test_init(self):
+ assert not self.identifier.getIdentifier()
+
+ def test_getIdentifier1(self):
+ self.widget.set_label(self.name)
+ assert self.identifier.getIdentifier() == self.name
+
+ def test_getIdentifier2(self):
+ self.widget.set_name(self.name)
+ assert self.identifier.getIdentifier() == self.name
+
+class test_toolButtonIdentifier:
+ def __init__(self):
+ self.is_setup = False
+
+ def setUp(self):
+ assert not self.is_setup
+
+ self.name = "nameExample"
+ self.widget = gtk.ToolButton()
+
+ self.identifier = toolButtonIdentifier(self.widget)
+
+ self.is_setup = True
+
+ def tearDown(self):
+ assert self.is_setup
+ self.is_setup = False
+
+ def test_init(self):
+ assert not self.identifier.getIdentifier()
+
+ def test_getIdentifier1(self):
+ self.widget.set_name(self.name)
+ assert self.identifier.getIdentifier() == self.name
+
+ def test_getIdentifier2(self):
+ self.widget.set_label(self.name)
+ assert self.identifier.getIdentifier() == self.name
+
+ def test_getIdentifier3(self):
+ self.widget.set_icon_name(self.name)
+ assert self.identifier.getIdentifier() == self.name
+
+ def test_getIdentifier4(self):
+ label = gtk.Label(self.name)
+ self.widget.set_label_widget(label)
+ assert self.identifier.getIdentifier() == self.name
+
+class test_comboBoxIdentifier:
+ def __init__(self):
+ self.is_setup = False
+
+ def setUp(self):
+ assert not self.is_setup
+
+ self.name = "nameExample"
+ self.widget = gtk.ComboBox()
+
+ self.identifier = comboBoxIdentifier(self.widget)
+
+ self.is_setup = True
+
+ def tearDown(self):
+ assert self.is_setup
+ self.is_setup = False
+
+ def test_init(self):
+ assert not self.identifier.getIdentifier()
+
+ def test_getIdentifier1(self):
+ self.widget.set_name(self.name)
+ assert self.identifier.getIdentifier() == self.name
+
+ def test_getIdentifier2(self):
+ self.widget.set_title(self.name)
+ assert self.identifier.getIdentifier() == self.name
+
+class test_entryIdentifier:
+ def __init__(self):
+ self.is_setup = False
+
+ def setUp(self):
+ assert not self.is_setup
+
+ self.name = "nameExample"
+ self.widget = gtk.Entry()
+
+ self.identifier = entryIdentifier(self.widget)
+
+ self.is_setup = True
+
+ def tearDown(self):
+ assert self.is_setup
+ self.is_setup = False
+
+ def test_init(self):
+ assert not self.identifier.getIdentifier()
+
+ def test_getIdentifier1(self):
+ self.widget.set_name(self.name)
+ assert self.identifier.getIdentifier() == self.name
+
+ def test_getIdentifier2(self):
+ self.widget.set_text(self.name)
+ assert self.identifier.getIdentifier() == self.name
+
+# class test_paletteIdentifier:
+# def __init__(self):
+# self.is_setup = False
+#
+# def setUp(self):
+# assert not self.is_setup
+#
+# self.name = "nameExample"
+# # self.widget = gtk.Entry()
+# self.widget = Palette(self.name)
+#
+# self.identifier = paletteIdentifier(self.widget)
+#
+# self.is_setup = True
+#
+# def tearDown(self):
+# assert self.is_setup
+# self.is_setup = False
+#
+# def test_init(self):
+# assert self.identifier.getIdentifier()
+#
+# def test_getIdentifier1(self):
+# otherName = "someOtherName"
+# self.widget.set_name(otherName)
+# assert self.identifier.getIdentifier() == otherName
+#
+# def test_getIdentifier2(self):
+# assert self.identifier.getIdentifier() == self.name
+
+class test_toolComboBoxIdentifier:
+ def __init__(self):
+ self.is_setup = False
+
+ def setUp(self):
+ assert not self.is_setup
+
+ self.name = "nameExample"
+ self.widget = ToolComboBox()
+ self.widget.set_property('label-text', self.name)
+
+ # Set the widget later...
+ self.identifier = toolComboBoxIdentifier(None)
+
+ self.is_setup = True
+
+ def tearDown(self):
+ assert self.is_setup
+ self.is_setup = False
+
+ def test_getIdentifier1(self):
+ otherName = "someOtherName"
+ self.widget.set_name(otherName)
+ self.identifier.setWidget(self.widget)
+ assert self.identifier.getIdentifier() == otherName
+
+ def test_getIdentifier2(self):
+ self.identifier.setWidget(self.widget)
+ assert self.identifier.getIdentifier() == self.name
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Experior.Activity/test_widgetIdentifier.pyc b/Experior.Activity/test_widgetIdentifier.pyc
new file mode 100644
index 0000000..f1385de
--- /dev/null
+++ b/Experior.Activity/test_widgetIdentifier.pyc
Binary files differ
diff --git a/Experior.Activity/widgetIdentifier.py b/Experior.Activity/widgetIdentifier.py
new file mode 100755
index 0000000..c9eb7dd
--- /dev/null
+++ b/Experior.Activity/widgetIdentifier.py
@@ -0,0 +1,260 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+widgetIdentifier.py
+
+This file is part of sugarbot.
+
+sugarbot is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+sugarbot is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with sugarbot. If not, see <http://www.gnu.org/licenses/>.
+"""
+import gobject
+import sys
+import os
+import time
+import pygtk
+pygtk.require('2.0')
+
+import gtk
+from gtk import gdk
+
+import sugar
+from sugar import graphics
+from sugar.graphics.toolbutton import Palette
+from sugar.graphics.icon import Icon
+from sugar.graphics.toolcombobox import ToolComboBox
+
+class widgetIdentifier:
+ """
+ The widgetIdentifier class is used as a basis for classes to identify
+ Widgets. Ideally, all developers would call Widget.set_name() on all
+ widgets created by their Activities. Since this is not always
+ practical or worthwhile, we must rely on other methods to identify
+ widgets.
+
+ This class provides some of the functionality for identifying widgets,
+ such as a list of strings that are default Widget names (e.g. 'GtkButton').
+ """
+ identifiers = { }
+
+ def __init__(self, widget):
+ self.widgetAttribute = "sugarbotWidgetIdentifier"
+
+ self.dontWant = ["GtkToolbar", "GtkToggleButton","GtkButton",
+ "GtkEventBox", "GtkNotebook", "GtkViewport",
+ "HippoCanvas", "GtkTextView", "GtkInvisible",
+ "GtkEntry", "GtkLabel", "GtkVBox", "GtkHBox",
+ "SugarIcon","SugarToolButton","GtkAlignment",
+ "GtkSeparatorToolItem","GtkTable","SugarToolbox",
+ "GtkToggleToolButton","GtkScrolledWindow","GtkCellView",
+ "GtkVSeparator","GtkArrow","GtkToolItem","GtkAccelLabel",
+ "SugarComboBox","SugarToggleToolButton","GtkHSeparator",
+ "GtkHButtonBox","GtkImageMenuItem","GtkSeparatorMenuItem",
+ "GtkSpinButton","GtkDrawingArea","GtkFrame",
+ "GtkColorButton", ""]
+
+ self.dontWantPrefixes = ["Gtk", "sugar+graphics"]
+ self.setWidget(widget)
+
+ def setWidget(self, widget):
+ self._widget = widget
+ # self.getIdentifier()
+
+ def getIdentifierSub(self):
+ """
+ Overridden by inheriting classes.
+ """
+ return None
+
+ def getIdentifier(self):
+ """
+ Returns the Identifier of the Widget set with __init__, or None
+ if we cannot find an identifier. Do not override this function!
+ """
+ # If we have already set the attribute for this widget, just
+ # retrieve it quickly.
+ if self.checkStoredIdentifier():
+ return self.getStoredIdentifier()
+
+ ident = None
+ widget = self._widget
+
+ if hasattr(widget, "get_name"):
+ ident = widget.get_name()
+
+ if not self.validateIdentifier(ident):
+ ident = self.getIdentifierSub()
+
+ return self.setIdentifier(ident)
+
+ def checkStoredIdentifier(self):
+ """
+ Checks to see if we have previously identified this same Widget.
+ If we have, the Widget will have an attribute as defined by
+ widgetIdentifier.widgetAttribute.
+ """
+ if hasattr(self._widget, self.widgetAttribute) \
+ and getattr(self._widget, self.widgetAttribute) is not None:
+ return True
+ return False
+
+ def getStoredIdentifier(self):
+ """
+ If the Widget has a stored identifier (see checkStoredIdentifier),
+ then retrieve the stored identifier's value.
+
+ If the Widget does not have a stored identifier, return None.
+ """
+ if self.checkStoredIdentifier():
+ return getattr(self._widget, self.widgetAttribute)
+ else:
+ return None
+
+ def validateIdentifier(self,ident):
+ """
+ Checks a proposed identifier against a series of criterium. For
+ example, empty strings, and blacklisted strings, as well as
+ blacklisted prefixes, may rule out an identifier for use.
+ """
+ if ident is None:
+ return False
+ elif not isinstance(ident, str):
+ return False
+ elif len(ident) < 1:
+ return False
+ elif ident in self.dontWant:
+ return False
+ else:
+ for prefix in self.dontWantPrefixes:
+ if ident.startswith(prefix):
+ return False
+ return True
+
+ def setIdentifier(self, ident):
+ """
+ Sets the stored identifier for the Widget assigned by __init__.
+ """
+ if self.validateIdentifier(ident):
+ setattr(self._widget, self.widgetAttribute, ident)
+ return ident
+ return None
+widgetIdentifier.identifiers[gtk.Widget] = widgetIdentifier
+
+
+class buttonIdentifier(widgetIdentifier):
+ def getIdentifierSub(self):
+ ident = None
+ widget = self._widget
+
+ if hasattr(widget, "get_label"):
+ ident = widget.get_label()
+
+ return ident
+widgetIdentifier.identifiers[gtk.Button] = buttonIdentifier
+
+# class toolButtonIdentifier(widgetIdentifier):
+class toolButtonIdentifier(buttonIdentifier):
+ def getIdentifierSub(self):
+ ident = buttonIdentifier.getIdentifierSub(self)
+ widget = self._widget
+
+ # Get the identifier using the icon
+ if not self.validateIdentifier(ident):
+ ico = None
+ ico = widget.get_icon_widget()
+ if isinstance(ico, Icon):
+ ident = ico.props.icon_name
+
+ # Label did not give us a good ident, check the icon name
+ if not self.validateIdentifier(ident):
+ ident = widget.get_icon_name()
+
+ # Icon did not give us a good ident, try the label
+ if not self.validateIdentifier(ident):
+ label = widget.get_label_widget()
+ if hasattr(label,"get_text"):
+ ident = label.get_text()
+
+ return ident
+widgetIdentifier.identifiers[gtk.ToolButton] = toolButtonIdentifier
+
+class comboBoxIdentifier(widgetIdentifier):
+ def getIdentifierSub(self):
+ ident = None
+ widget = self._widget
+
+ if hasattr(widget, "get_title"):
+ ident = self._widget.get_title()
+
+ return ident
+widgetIdentifier.identifiers[gtk.ComboBox] = comboBoxIdentifier
+
+
+class entryIdentifier(widgetIdentifier):
+ def getIdentifierSub(self):
+ ident = None
+ widget = self._widget
+
+ if not self.validateIdentifier(ident):
+ if hasattr(widget, "get_text"):
+ ident = self._widget.get_text()
+
+ return ident
+widgetIdentifier.identifiers[gtk.Entry] = entryIdentifier
+
+class paletteIdentifier(widgetIdentifier):
+ def getIdentifierSub(self):
+ ident = None
+ widget = self._widget
+
+ if hasattr(widget, "_primary_text"):
+ ident = getattr(widget, "_primary_text")
+
+ elif not self.validateIdentifier(ident):
+ if hasattr(widget, "props.primary_text"):
+ ident = getattr(widget, "props.primary_text")
+
+ return ident
+widgetIdentifier.identifiers[Palette] = paletteIdentifier
+
+
+class toolComboBoxIdentifier(widgetIdentifier):
+ def getIdentifierSub(self):
+ ident = None
+ widget = self._widget
+
+ if hasattr(widget, "_label_text"):
+ ident = getattr(widget, "_label_text")
+ print ident
+
+ # if not self.validateIdentifier(ident):
+ # try:
+ # print "@@@"
+ # ident = widget.get_property("label-text")
+ # print ident
+ # except TypeError:
+ # raise
+
+ # <DEPRECATED>
+ # if not self.validateIdentifier(ident):
+ # if hasattr(widget, "_label_text"):
+ # ident = getattr(widget, "_label_text")
+ #
+ # elif not self.validateIdentifier(ident):
+ # if hasattr(widget, "label"):
+ # label = widget.label
+ # ident = label.get_text()
+ # </DEPRECATED>
+
+ return ident
+widgetIdentifier.identifiers[ToolComboBox] = toolComboBoxIdentifier \ No newline at end of file
diff --git a/Experior.Activity/widgetIdentifier.pyc b/Experior.Activity/widgetIdentifier.pyc
new file mode 100644
index 0000000..99312df
--- /dev/null
+++ b/Experior.Activity/widgetIdentifier.pyc
Binary files differ