diff options
author | Vincent Vinet <vince.vinet@gmail.com> | 2009-12-07 20:50:52 (GMT) |
---|---|---|
committer | Vincent Vinet <vince.vinet@gmail.com> | 2009-12-07 20:52:25 (GMT) |
commit | 034e36d4983da0c2d44c56d4efd9af922b2cab4e (patch) | |
tree | 8fc4726e09ac60cbfd64b0ee068f451144cecf3b | |
parent | 7e65bdb14c2b3a9e04762755a19fcdc9922291fc (diff) |
pass the overlayer as a keyword argument for do, enter_editmode and subscribe, remove object store references
-rw-r--r-- | addons/bubblemessage.py | 28 | ||||
-rw-r--r-- | addons/bubblemessagewimg.py | 31 | ||||
-rw-r--r-- | addons/clickaction.py | 4 | ||||
-rw-r--r-- | addons/disablewidget.py | 19 | ||||
-rw-r--r-- | addons/gtkwidgettypefilter.py | 9 | ||||
-rw-r--r-- | addons/messagebuttonnext.py | 16 | ||||
-rw-r--r-- | addons/readfile.py | 5 | ||||
-rw-r--r-- | addons/typetextaction.py | 4 | ||||
-rw-r--r-- | addons/widgetidentifyaction.py | 11 | ||||
-rw-r--r-- | tests/actiontests.py | 24 | ||||
-rw-r--r-- | tests/probetests.py | 4 | ||||
-rw-r--r-- | tutorius/TProbe.py | 106 | ||||
-rw-r--r-- | tutorius/actions.py | 9 | ||||
-rw-r--r-- | tutorius/creator.py | 1 |
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 |