Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--addons/bubblemessage.py28
-rw-r--r--addons/bubblemessagewimg.py31
-rw-r--r--addons/clickaction.py4
-rw-r--r--addons/disablewidget.py19
-rw-r--r--addons/gtkwidgettypefilter.py9
-rw-r--r--addons/messagebuttonnext.py16
-rw-r--r--addons/readfile.py5
-rw-r--r--addons/typetextaction.py4
-rw-r--r--addons/widgetidentifyaction.py11
-rw-r--r--tests/actiontests.py24
-rw-r--r--tests/probetests.py4
-rw-r--r--tutorius/TProbe.py106
-rw-r--r--tutorius/actions.py9
-rw-r--r--tutorius/creator.py1
14 files changed, 171 insertions, 100 deletions
diff --git a/addons/bubblemessage.py b/addons/bubblemessage.py
index 4e37274..1b495d4 100644
--- a/addons/bubblemessage.py
+++ b/addons/bubblemessage.py
@@ -15,8 +15,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from ..actions import Action, DragWrapper
from ..properties import TStringProperty, TArrayProperty
-from .. import overlayer
-from ..services import ObjectStore
+from ..overlayer import TextBubble
class BubbleMessage(Action):
message = TStringProperty("Message")
@@ -42,21 +41,22 @@ class BubbleMessage(Action):
self._bubble = None
self._speaker = None
- def do(self, activity=None, **kwargs):
+ def do(self, overlayer=None, **kwargs):
"""
- Show the dialog
+ Show the dialog
+ @param overlayer Overlayer to draw on
"""
- if activity is None:
- raise TypeError("Missing argument activity")
+ if overlayer is None:
+ raise TypeError("Missing argument overlayer")
# get overlayer
- self.overlay = activity._overlayer
+ self.overlay = overlayer
if not self._bubble:
x, y = self.position
# TODO: tails are relative to tailpos. They should be relative to
# the speaking widget. Same of the bubble position.
- self._bubble = overlayer.TextBubble(text=self.message,
+ self._bubble = TextBubble(text=self.message,
tailpos=self.tail_pos)
self._bubble.show()
self.overlay.put(self._bubble, x, y)
@@ -71,16 +71,20 @@ class BubbleMessage(Action):
self._bubble.destroy()
self._bubble = None
- def enter_editmode(self, *args):
+ def enter_editmode(self, overlayer=None, *args, **kwargs):
"""
Enters edit mode. The action should display itself in some way,
without affecting the currently running application.
+ @param overlayer Overlayer to draw on
"""
- if not self.overlay:
- self.overlay = ObjectStore().activity._overlayer
+ if not overlayer:
+ raise TypeError("Missing argument overlayer")
+
+ self.overlay = overlayer
+
assert not self._drag, "bubble action set to editmode twice"
x, y = self.position
- self._bubble = overlayer.TextBubble(text=self.message,
+ self._bubble = TextBubble(text=self.message,
tailpos=self.tail_pos)
self.overlay.put(self._bubble, x, y)
self._bubble.show()
diff --git a/addons/bubblemessagewimg.py b/addons/bubblemessagewimg.py
index 9fe9512..974dd19 100644
--- a/addons/bubblemessagewimg.py
+++ b/addons/bubblemessagewimg.py
@@ -13,10 +13,9 @@
# 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
-from sugar.tutorius.actions import Action, DragWrapper
-from sugar.tutorius.properties import TStringProperty, TResourceProperty, TArrayProperty
-from sugar.tutorius import overlayer
-from sugar.tutorius.services import ObjectStore
+from ..actions import Action, DragWrapper
+from ..properties import TStringProperty, TResourceProperty, TArrayProperty
+from ..overlayer import TextBubbleWImg
class BubbleMessageWImg(Action):
message = TStringProperty("Message")
@@ -43,24 +42,25 @@ class BubbleMessageWImg(Action):
self._bubble = None
self._speaker = None
- def do(self, **kwargs):
+ def do(self, overlayer=None, **kwargs):
"""
Show the dialog
+ @param overlayer Overlayer to draw on
"""
- # get or inject overlayer
- self.overlay = ObjectStore().activity._overlayer
+ if overlayer is None:
+ raise TypeError("Missing overlayer")
+
+ self.overlay = overlayer
# FIXME: subwindows, are left to overlap this. This behaviour is
# undesirable. subwindows (i.e. child of top level windows) should be
# handled either by rendering over them, or by finding different way to
# draw the overlay.
- if not self.overlay:
- self.overlay = ObjectStore().activity._overlayer
if not self._bubble:
x, y = self.position
# TODO: tails are relative to tailpos. They should be relative to
# the speaking widget. Same of the bubble position.
- self._bubble = overlayer.TextBubbleWImg(text=self.message,
+ self._bubble = TextBubbleWImg(text=self.message,
tailpos=self.tail_pos,imagepath=self.imgpath.default)
self._bubble.show()
self.overlay.put(self._bubble, x, y)
@@ -75,16 +75,19 @@ class BubbleMessageWImg(Action):
self._bubble.destroy()
self._bubble = None
- def enter_editmode(self, *args):
+ def enter_editmode(self, overlayer=None, *args, **kwargs):
"""
Enters edit mode. The action should display itself in some way,
without affecting the currently running application.
+ @param overlay Overlayer to draw on
"""
- if not self.overlay:
- self.overlay = ObjectStore().activity._overlayer
+ if overlayer is None:
+ raise TypeError("Missing overlayer")
+
+ self.overlay = overlayer
assert not self._drag, "bubble action set to editmode twice"
x, y = self.position
- self._bubble = overlayer.TextBubbleWImg(text=self.message,
+ self._bubble = TextBubbleWImg(text=self.message,
tailpos=self.tail_pos,imagepath=self.imgpath)
self.overlay.put(self._bubble, x, y)
self._bubble.show()
diff --git a/addons/clickaction.py b/addons/clickaction.py
index eae713e..50726c6 100644
--- a/addons/clickaction.py
+++ b/addons/clickaction.py
@@ -30,7 +30,9 @@ class ClickAction(Action):
"""
click the widget
"""
- realWidget = gtkutils.find_widget(ObjectStore().activity, self.widget)
+ if not "activity" in kwargs:
+ raise TypeError("Missing activity")
+ realWidget = gtkutils.find_widget(kwargs["activity"], self.widget)
if hasattr(realWidget, "clicked"):
realWidget.clicked()
diff --git a/addons/disablewidget.py b/addons/disablewidget.py
index 15e07f2..3d392e9 100644
--- a/addons/disablewidget.py
+++ b/addons/disablewidget.py
@@ -16,7 +16,6 @@
from ..actions import *
from .. import gtkutils
-from ..services import ObjectStore
class DisableWidgetAction(Action):
target = TStringProperty("0")
@@ -31,15 +30,15 @@ class DisableWidgetAction(Action):
def do(self, **kwargs):
"""Action do"""
- os = ObjectStore()
- if os.activity:
- self._widget = gtkutils.find_widget(os.activity, self.target)
- if self._widget:
- # If we have an object whose sensitivity we can query, we will
- # keep it to reset it in the undo() method
- if hasattr(self._widget, 'get_sensitive') and callable(self._widget.get_sensitive):
- self._previous_sensitivity = self._widget.get_sensitive()
- self._widget.set_sensitive(False)
+ if not "activity" in kwargs:
+ raise TypeError("Missing activity")
+ self._widget = gtkutils.find_widget(kwargs["activity"], self.target)
+ if self._widget:
+ # If we have an object whose sensitivity we can query, we will
+ # keep it to reset it in the undo() method
+ if hasattr(self._widget, 'get_sensitive') and callable(self._widget.get_sensitive):
+ self._previous_sensitivity = self._widget.get_sensitive()
+ self._widget.set_sensitive(False)
def undo(self):
"""Action undo"""
diff --git a/addons/gtkwidgettypefilter.py b/addons/gtkwidgettypefilter.py
index 7b2e15e..01e6ad3 100644
--- a/addons/gtkwidgettypefilter.py
+++ b/addons/gtkwidgettypefilter.py
@@ -16,7 +16,6 @@
from ..filters import *
from ..properties import TStringProperty, TSequenceProperty
-from ..services import ObjectStore
from ..gtkutils import find_widget
import logging
@@ -49,12 +48,12 @@ class GtkWidgetTypeFilter(EventFilter):
"""install handlers
@param callback default EventFilter callback arg
"""
+ if not "activity" in kwargs:
+ raise TypeError("Missing activity argument")
+
super(GtkWidgetTypeFilter, self).install_handlers(callback, **kwargs)
logger.debug("~~~GtkWidgetTypeFilter install")
- activity = ObjectStore().activity
- if activity is None:
- logger.error("No activity")
- raise RuntimeWarning("no activity in the objectstore")
+ activity = kwargs["activity"]
self._widget = find_widget(activity, self.object_id)
if self._widget:
diff --git a/addons/messagebuttonnext.py b/addons/messagebuttonnext.py
index 058ef41..40e55c2 100644
--- a/addons/messagebuttonnext.py
+++ b/addons/messagebuttonnext.py
@@ -16,9 +16,8 @@
import gtk, gtk.gdk
-from sugar.tutorius.filters import EventFilter
-from sugar.tutorius.properties import TStringProperty, TArrayProperty
-from sugar.tutorius import overlayer
+from ..filters import EventFilter
+from ..properties import TStringProperty, TArrayProperty
from sugar import profile
@@ -57,17 +56,12 @@ class MessageButtonNext(EventFilter):
"""install_handlers creates the message button next and shows it"""
super(MessageButtonNext,self).install_handlers(callback, **kwargs)
- if not "activity" in kwargs:
- raise TypeError("activity argument is Mandatory")
+ if not "overlayer" in kwargs:
+ raise TypeError("overlayer argument is Mandatory")
- # get activity instance
- self.activity = kwargs["activity"]
-
# get or inject overlayer
- self.overlay = self.activity._overlayer
+ self.overlay = kwargs["overlayer"]
- if not self.overlay:
- self.overlay = self.activity._overlayer
btntext = "NEXT"
diff --git a/addons/readfile.py b/addons/readfile.py
index 81385ba..494483c 100644
--- a/addons/readfile.py
+++ b/addons/readfile.py
@@ -18,7 +18,6 @@ import os
from ..actions import Action
from ..properties import TFileProperty
-from ..services import ObjectStore
class ReadFile(Action):
"""
@@ -32,8 +31,10 @@ class ReadFile(Action):
"""
Perform the action, call read_file on the activity
"""
+ if not "activity" in kwargs:
+ raise TypeError("Missing activity")
if os.path.isfile(str(self.filename)):
- ObjectStore().activity.read_file(self.filename)
+ kwargs["activity"].read_file(self.filename)
def undo(self):
"""
diff --git a/addons/typetextaction.py b/addons/typetextaction.py
index 8a09ff9..e4a5ecc 100644
--- a/addons/typetextaction.py
+++ b/addons/typetextaction.py
@@ -32,7 +32,9 @@ class TypeTextAction(Action):
"""
Type the text
"""
- widget = gtkutils.find_widget(ObjectStore().activity, self.widget)
+ if not "activity" in kwargs:
+ raise TypeError("Missing activity")
+ widget = gtkutils.find_widget(kwargs["activity"], self.widget)
if hasattr(widget, "insert_text"):
widget.insert_text(self.text, -1)
diff --git a/addons/widgetidentifyaction.py b/addons/widgetidentifyaction.py
index b59c94a..55f9209 100644
--- a/addons/widgetidentifyaction.py
+++ b/addons/widgetidentifyaction.py
@@ -25,12 +25,13 @@ class WidgetIdentifyAction(Action):
self._dialog = None
def do(self, **kwargs):
- os = ObjectStore()
- if os.activity:
- self.activity = os.activity
+ if not "activity" in kwargs:
+ raise TypeError("Missing activity")
- self._dialog = WidgetIdentifier(self.activity)
- self._dialog.show()
+ self.activity = kwargs["activity"]
+
+ self._dialog = WidgetIdentifier(self.activity)
+ self._dialog.show()
def undo(self):
diff --git a/tests/actiontests.py b/tests/actiontests.py
index 80a10f8..932c2bb 100644
--- a/tests/actiontests.py
+++ b/tests/actiontests.py
@@ -27,7 +27,6 @@ import gtk
from sugar.tutorius import addon
from sugar.tutorius.addons.triggereventfilter import *
from sugar.tutorius.actions import *
-from sugar.tutorius.services import ObjectStore
test_props = {"prop_a":8, "prop_b":3, "prop_c":"Hi"}
@@ -190,14 +189,13 @@ class ChainActionTest(unittest.TestCase):
class DisableWidgetActionTests(unittest.TestCase):
def test_disable(self):
btn = gtk.Button()
- ObjectStore().activity = btn
btn.set_sensitive(True)
assert btn.props.sensitive is True, "Callback should have been called"
act = addon.create('DisableWidgetAction', target="0")
assert btn.props.sensitive is True, "Callback should have been called again"
- act.do()
+ act.do(activity=btn)
assert btn.props.sensitive is False, "Callback should not have been called again"
act.undo()
assert btn.props.sensitive is True, "Callback should have been called again"
@@ -280,22 +278,21 @@ class TypeTextActionTests(unittest.TestCase):
activity = FakeParentWidget()
widget = FakeTextEntry()
activity.add_child(widget)
- ObjectStore().activity = activity
test_text = "This is text"
action = addon.create('TypeTextAction', widgetUAM="0.0", text=test_text)
- assert widget == ObjectStore().activity.get_children()[0],\
+ assert widget == activity.get_children()[0],\
"The clickable widget isn't reachable from the object store \
the test cannot pass"
- action.do()
+ action.do(activity=activity)
assert widget.last_entered_line == test_text, "insert_text() should have been called by do()"
- action.do()
+ action.do(activity=activity)
assert widget.last_entered_line == test_text, "insert_text() should have been called by do()"
assert len(widget.text_lines) == 2, "insert_text() should have been called twice"
@@ -304,14 +301,13 @@ class TypeTextActionTests(unittest.TestCase):
activity = FakeParentWidget()
widget = FakeTextEntry()
activity.add_child(widget)
- ObjectStore().activity = activity
test_text = "This is text"
action = addon.create('TypeTextAction', widgetUAM="0.0", text=test_text)
- assert widget == ObjectStore().activity.get_children()[0],\
+ assert widget == activity.get_children()[0],\
"The clickable widget isn't reachable from the object store \
the test cannot pass"
@@ -328,19 +324,18 @@ class ClickActionTests(unittest.TestCase):
activity = FakeParentWidget()
widget = ClickableWidget()
activity.add_child(widget)
- ObjectStore().activity = activity
action = addon.create('ClickAction', widget="0.0")
- assert widget == ObjectStore().activity.get_children()[0],\
+ assert widget == activity.get_children()[0],\
"The clickable widget isn't reachable from the object store \
the test cannot pass"
- action.do()
+ action.do(activity=activity)
assert widget.click_count == 1, "clicked() should have been called by do()"
- action.do()
+ action.do(activity=activity)
assert widget.click_count == 2, "clicked() should have been called by do()"
@@ -348,11 +343,10 @@ class ClickActionTests(unittest.TestCase):
activity = FakeParentWidget()
widget = ClickableWidget()
activity.add_child(widget)
- ObjectStore().activity = activity
action = addon.create('ClickAction', widget="0.0")
- assert widget == ObjectStore().activity.get_children()[0],\
+ assert widget == activity.get_children()[0],\
"The clickable widget isn't reachable from the object store \
the test cannot pass"
diff --git a/tests/probetests.py b/tests/probetests.py
index 481eae3..9785e81 100644
--- a/tests/probetests.py
+++ b/tests/probetests.py
@@ -234,13 +234,13 @@ class ProbeTest(unittest.TestCase):
assert message_box is None, "Message box should still be empty"
#install 1
- address = self.probe.install(pickle.dumps(action), False)
+ address, addprops = pickle.loads(self.probe.install(pickle.dumps(action), False))
assert type(address) == str, "install should return a string"
assert message_box == (5, "woot"), "message box should have (i, s)"
#install 2
action.i, action.s = (10, "ahhah!")
- address2 = self.probe.install(pickle.dumps(action), False)
+ address2, addprops = pickle.loads(self.probe.install(pickle.dumps(action), False))
assert message_box == (10, "ahhah!"), "message box should have changed"
assert address != address2, "action addresses should be different"
diff --git a/tutorius/TProbe.py b/tutorius/TProbe.py
index e3189fe..5508d49 100644
--- a/tutorius/TProbe.py
+++ b/tutorius/TProbe.py
@@ -17,6 +17,7 @@
import logging
LOGGER = logging.getLogger("sugar.tutorius.TProbe")
import os
+import gtk
import gobject
@@ -29,8 +30,6 @@ from jarabe.model.shell import get_model
from sugar.bundle.activitybundle import ActivityBundle
from . import addon
-from . import properties
-from .services import ObjectStore
from .dbustools import save_args, ignore, logError
from .gtkutils import find_widget, raddr_lookup
@@ -62,28 +61,26 @@ class TProbe(dbus.service.Object):
a DBUS Interface.
"""
- def __init__(self, activity, activity_name, unique_id, service_proxy=None):
+ def __init__(self, widget, activity_name, unique_id, overlayer=None, service_proxy=None):
"""
Create and register a TProbe for an activity.
- @param activity activity reference, must be a gtk container
+ @param widget top widget reference, must be a gtk container
@param activity_name generic name for the activity
@param unique_id specific name for this instance
+ @param overlayer overlayer to draw actions on
@param service_proxy A Service proxy object to do the registering
"""
- # Moving the ObjectStore assignment here, in the meantime
- # the reference to the activity shouldn't be share as a
- # global variable but passed by the Probe to the objects
- # that requires it
- self._activity = activity
+ self._activity = widget
+
+ #Legacy way to access the overlayer, do it here instead of everywhere
+ self._overlayer = overlayer or getattr(self._activity, "_overlayer", None)
if service_proxy == None:
from .service import ServiceProxy
self._service_proxy = service_proxy or ServiceProxy()
- ObjectStore().activity = activity
-
self._activity_name = activity_name
self._unique_id = unique_id
@@ -157,7 +154,7 @@ class TProbe(dbus.service.Object):
action._props.update(loaded_action._props)
if not is_editing:
- action.do(activity=self._activity, probe=self)
+ action.do(activity=self._activity, probe=self, overlayer=self._overlayer)
else:
# force mandatory props
addon_name = addon.get_name_from_type(type(action))
@@ -171,7 +168,7 @@ class TProbe(dbus.service.Object):
propname)
updated_props[propname] = getattr(action, propname)
- action.enter_editmode()
+ action.enter_editmode(overlayer=self._overlayer)
action.set_notification_cb(partial(self.update_action, address))
pickled_value = pickle.dumps((address, updated_props))
@@ -194,10 +191,10 @@ class TProbe(dbus.service.Object):
action._props.update(props)
if not is_editing:
action.undo()
- action.do()
+ action.do(activity=self._activity, overlayer=self._overlayer)
else:
action.exit_editmode()
- action.enter_editmode()
+ action.enter_editmode(overlayer=self._overlayer)
@dbus.service.method("org.tutorius.ProbeInterface",
in_signature='sb', out_signature='')
@@ -250,7 +247,7 @@ class TProbe(dbus.service.Object):
def callback(*args):
self.notify(eventfilter)
- eventfilter.install_handlers(callback, activity=self._activity, probe=self)
+ eventfilter.install_handlers(callback, activity=self._activity, probe=self, overlayer=self._overlayer)
name = self._generate_event_reference(eventfilter)
self._subscribedEvents[name] = eventfilter
@@ -384,8 +381,6 @@ class FrameProbe(TProbe):
return find_widget(base._right_panel, object_id, ignore_errors)
else:
raise RuntimeWarning("Invalid frame panel: '%s'"%window)
-
- return find_widget(base, path, ignore_errors)
def retrieve_path(self, widget):
"""
@@ -427,6 +422,81 @@ class FrameProbe(TProbe):
return "frame://"+window+"/"+(".".join(name))
+class DesktopProbe(TProbe):
+ """
+ Identical to the base probe except that helper functions are redefined
+ to handle the four windows that are part of the Frame.
+ """
+ # ------------------ Helper functions specific to a component --------------
+ def find_widget(self, base, path, ignore_errors=True):
+ """
+ Finds a widget from a base object. Symmetric with retrieve_path
+
+ format for the path for the frame should be:
+
+ desktop://<view>/<path>
+ where view: home | group | mesh
+ path: number[.number]*
+
+ @param base the parent widget
+ @param path fqdn-style target object name
+
+ @return widget found
+ """
+ protocol, p = path.split("://")
+ assert protocol == "desktop"
+
+ window, object_id = p.split("/")
+ if window == "home":
+ return find_widget(base._top_panel, object_id, ignore_errors)
+ elif window == "group":
+ return find_widget(base._bottom_panel, object_id, ignore_errors)
+ elif window == "mesh":
+ return find_widget(base._left_panel, object_id, ignore_errors)
+ else:
+ raise RuntimeWarning("Invalid frame panel: '%s'"%window)
+
+ return find_widget(base, path, ignore_errors)
+
+ def retrieve_path(self, widget):
+ """
+ Retrieve the path to access a specific widget.
+ Symmetric with find_widget.
+
+ format for the path for the frame should be:
+
+ desktop://<view>/<path>
+ where view: home | group | mesh
+ path: number[.number]*
+
+ @param widget the widget to find a path for
+
+ @return path to the widget
+ """
+ name = []
+ child = widget
+ parent = widget.parent
+ while parent:
+ name.insert(0,str(parent.get_children().index(child)))
+ child = parent
+ parent = child.parent
+
+ name.insert(0,"0") # root object itself
+
+ window = ""
+ if parent._position == gtk.POS_TOP:
+ window = "top"
+ elif parent._position == gtk.POS_BOTTOM:
+ window = "bottom"
+ elif parent._position == gtk.POS_LEFT:
+ window = "left"
+ elif parent._position == gtk.POS_RIGHT:
+ window = "right"
+ else:
+ raise RuntimeWarning("Invalid root panel in frame: %s"%str(parent))
+
+ return "desktop://"+window+"/"+(".".join(name))
+
class ProbeProxy:
"""
diff --git a/tutorius/actions.py b/tutorius/actions.py
index 40d9b03..fe64c95 100644
--- a/tutorius/actions.py
+++ b/tutorius/actions.py
@@ -23,7 +23,6 @@ from gettext import gettext as _
from sugar.graphics import icon
from . import addon
-from .services import ObjectStore
from .properties import *
from .constants import *
@@ -211,12 +210,16 @@ class Action(TPropContainer):
# Empty the diff dict as we just synchronized with the creator
self._diff_dict.clear()
- def enter_editmode(self, **kwargs):
+ def enter_editmode(self, overlayer=None, **kwargs):
"""
Enters edit mode. The action should display itself in some way,
without affecting the currently running application. The default is
a small box with the action icon.
+ @param overlayer Overlayer to draw on
"""
+ if overlayer is None:
+ raise TypeError("No overlayer supplied")
+
meta = addon.get_addon_meta(type(self).__name__)
actionicon = icon.Icon(icon_name=meta['icon'],
@@ -232,7 +235,7 @@ class Action(TPropContainer):
self.position = 0, 0
x, y = self.position
- ObjectStore().activity._overlayer.put(self.__edit_img, x, y)
+ overlayer.put(self.__edit_img, x, y)
self.__edit_img.show_all()
self._drag = DragWrapper(self.__edit_img, self.position, update_action_cb=self.update_property, draggable=True)
diff --git a/tutorius/creator.py b/tutorius/creator.py
index 8964b7f..2de21ac 100644
--- a/tutorius/creator.py
+++ b/tutorius/creator.py
@@ -33,7 +33,6 @@ from sugar.graphics import icon, style
import jarabe.frame
from . import overlayer, gtkutils, vault, addon
-from .services import ObjectStore
from .tutorial import Tutorial
from . import viewer
from .propwidgets import TextInputDialog