Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tutorius/TProbe.py
diff options
context:
space:
mode:
Diffstat (limited to 'tutorius/TProbe.py')
-rw-r--r--tutorius/TProbe.py245
1 files changed, 231 insertions, 14 deletions
diff --git a/tutorius/TProbe.py b/tutorius/TProbe.py
index 5508d49..be0270a 100644
--- a/tutorius/TProbe.py
+++ b/tutorius/TProbe.py
@@ -14,6 +14,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+import time
import logging
LOGGER = logging.getLogger("sugar.tutorius.TProbe")
import os
@@ -26,7 +27,10 @@ import cPickle as pickle
from functools import partial
+import gtk
from jarabe.model.shell import get_model
+from jarabe.model import bundleregistry
+from sugar.activity import activityfactory
from sugar.bundle.activitybundle import ActivityBundle
from . import addon
@@ -156,11 +160,13 @@ class TProbe(dbus.service.Object):
if not is_editing:
action.do(activity=self._activity, probe=self, overlayer=self._overlayer)
else:
+ action.set_notification_cb(partial(self.update_action, address))
+
# force mandatory props
addon_name = addon.get_name_from_type(type(action))
meta = addon.get_addon_meta(addon_name)
for propname in meta['mandatory_props']:
- if getattr(action, propname) != None:
+ if getattr(action, propname, False):
continue
prop = getattr(type(action), propname)
prop.widget_class.run_dialog(self._activity,
@@ -169,7 +175,6 @@ class TProbe(dbus.service.Object):
updated_props[propname] = getattr(action, propname)
action.enter_editmode(overlayer=self._overlayer)
- action.set_notification_cb(partial(self.update_action, address))
pickled_value = pickle.dumps((address, updated_props))
return pickled_value
@@ -498,6 +503,107 @@ class DesktopProbe(TProbe):
return "desktop://"+window+"/"+(".".join(name))
+ # ------------------ 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
+
+ @param base the parent widget
+ @param path fqdn-style target object name
+
+ @return widget found
+ """
+ return find_widget(base, path, ignore_errors)
+
+ def retrieve_path(self, widget):
+ """
+ Retrieve the path to access a specific widget.
+ Symmetric with find_widget.
+
+ @param widget the widget to find a path for
+
+ @return path to the widget
+ """
+ return raddr_lookup(widget)
+
+class FrameProbe(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:
+
+ frame://<panel>/<path>
+ where panel: top | bottom | left | right
+ path: number[.number]*
+
+ @param base the parent widget
+ @param path fqdn-style target object name
+
+ @return widget found
+ """
+ protocol, p = path.split("://")
+ assert protocol == "frame"
+
+ window, object_id = p.split("/")
+ if window == "top":
+ return find_widget(base._top_panel, object_id, ignore_errors)
+ elif window == "bottom":
+ return find_widget(base._bottom_panel, object_id, ignore_errors)
+ elif window == "left":
+ return find_widget(base._left_panel, object_id, ignore_errors)
+ elif window == "right":
+ 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):
+ """
+ Retrieve the path to access a specific widget.
+ Symmetric with find_widget.
+
+ format for the path for the frame should be:
+
+ frame://<panel>/<path>
+ where panel: top | bottom | left | right
+ 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.append(str(parent.get_children().index(child)))
+ child = parent
+ parent = child.parent
+
+ name.append("0") # root object itself
+ name.reverse()
+
+ 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 "frame://"+window+"/"+(".".join(name))
+
class ProbeProxy:
"""
ProbeProxy is a Proxy class for connecting to a remote TProbe.
@@ -673,15 +779,24 @@ class ProbeProxy:
else:
LOGGER.debug("ProbeProxy :: unsubsribe address %s inconsistency : not registered", address)
- def create_event(self, addon_name):
+ def create_event(self, addon_name, event_created_cb):
"""
Create an event on the app side and request the user to fill the
properties before returning it.
@param addon_name: the add-on name of the event
+ @param event_created_cb The notification to trigger once the event has
+ been instantiated
@returns: an eventfilter instance
"""
- return pickle.loads(str(self._probe.create_event(addon_name)))
+ self._probe.create_event(addon_name,
+ reply_handler=save_args(self._event_created_cb, event_created_cb),
+ error_handler=ignore)
+
+ def _event_created_cb(self, event_created_cb, event):
+ LOGGER.debug("ProbeProxy :: _event_created_cb, calling upper layer")
+ event = pickle.loads(str(event))
+ event_created_cb(event)
def subscribe(self, event, notification_cb, event_subscribed_cb, error_cb):
@@ -751,20 +866,33 @@ class ProbeManager(object):
self._probes = {}
self._current_activity = None
+ self.list_pending_actions = []
+ self.list_action_installed_cb = []
+ self.list_error_cb = []
+
+ self.list_pending_transitions = []
+ self.list_notification_cb = []
+ self.list_event_subscribed_cb = []
+ self.list_error_cb = []
+
+ self.is_activity_launching = False
+
ProbeManager._LOGGER.debug("__init__()")
def setCurrentActivity(self, activity_id):
- if not activity_id in self._probes:
- raise RuntimeError("Activity not attached, id : %s"%activity_id)
+ # HACK : Disabling check for now, since it prevents usage of probes
+ # in activities that have yet to register their probes... We might
+ # set the current activity before having to execute anything inside it
+ # e.g. A new source is crawling in and we need to start the activity
+ #
+ # This should be removed once the Home Window probes are installed.
+
+ #if not activity_id in self._probes:
+ # raise RuntimeError("Activity not attached, id : %s"%activity_id)
+ LOGGER.debug("ProbeManager :: New activity set as current = %s", str(activity_id))
self._current_activity = activity_id
def getCurrentActivity(self):
- # TODO : Insert the correct call to remember the current activity,
- # taking the views and frame into account
- current_act = get_model().get_active_activity()
- current_act_bundle = ActivityBundle(current_act.get_bundle_path())
- current_act_id = current_act_bundle.get_bundle_id()
- self._current_activity = current_act_id
return self._current_activity
currentActivity = property(fget=getCurrentActivity, fset=setCurrentActivity)
@@ -775,6 +903,43 @@ class ProbeManager(object):
else:
return None
+ def prelaunch_activity(self, activity, action_event, is_event=False):
+ if activity == "org.sugar.desktop.mesh":
+ get_model()._set_zoom_level(get_model().ZOOM_MESH)
+ return False
+ elif activity == "org.sugar.desktop.group":
+ get_model()._set_zoom_level(get_model().ZOOM_GROUP)
+ return False
+ elif activity == "org.sugar.desktop.home":
+ get_model()._set_zoom_level(get_model().ZOOM_HOME)
+ return False
+
+ if activity == get_model().get_active_activity().get_type():
+ return False
+
+ model = get_model()
+ for active_activity in model:
+ if active_activity is not None and active_activity.get_type() == activity:
+ active_activity.get_window().activate(gtk.get_current_event_time())
+ return False
+
+ bundle = bundleregistry.get_registry().get_bundle(activity)
+ if not bundle:
+ print 'WARNING : Cannot find bundle'
+ else:
+ path = bundle.get_path()
+ activity_bundle = ActivityBundle(path)
+ if self.is_activity_launching == False:
+ activityfactory.create(activity_bundle)
+ self.is_activity_launching = True
+
+ if is_event:
+ self.list_pending_transitions.append(action_event)
+ else:
+ self.list_pending_actions.append(action_event)
+ return True
+ return False
+
def install(self, action, action_installed_cb, error_cb, is_editing=False, editing_cb=None):
"""
Install an action on the current activity
@@ -792,6 +957,13 @@ class ProbeManager(object):
activity = self.currentActivity
if activity:
+ wait_install = self.prelaunch_activity(activity, action)
+
+ if wait_install:
+ self.list_action_installed_cb.append(action_installed_cb)
+ self.list_error_cb.append(error_cb)
+ return
+
return self._first_proxy(activity).install(
action=action,
is_editing=is_editing,
@@ -840,16 +1012,17 @@ class ProbeManager(object):
else:
raise RuntimeWarning("No activity attached")
- def create_event(self, addon_name):
+ def create_event(self, addon_name, event_created_cb):
"""
Create an event on the app side and request the user to fill the
properties before returning it.
@param addon_name: the add-on name of the event
+ @param event_created_cb The notification to send once the event was created
@returns: an eventfilter instance
"""
if self.currentActivity:
- return self._first_proxy(self.currentActivity).create_event(addon_name)
+ return self._first_proxy(self.currentActivity).create_event(addon_name, event_created_cb)
else:
raise RuntimeWarning("No activity attached")
@@ -867,6 +1040,14 @@ class ProbeManager(object):
activity = self.get_source_activity(event)
if activity:
+ wait_install = self.prelaunch_activity(activity, event, True)
+
+ if wait_install:
+ self.list_notification_cb.append(notification_cb)
+ self.list_event_subscribed_cb.append(event_subscribed_cb)
+ self.list_error_cb.append(error_cb)
+ return
+
return self._first_proxy(activity).subscribe(event, notification_cb,\
event_subscribed_cb, error_cb)
else:
@@ -906,11 +1087,47 @@ class ProbeManager(object):
process_name = str(process_name)
unique_id = str(unique_id)
ProbeManager._LOGGER.debug("register_probe(%s,%s)", process_name, unique_id)
+
if process_name not in self._probes:
self._probes[process_name] = [(unique_id,self._ProxyClass(process_name, unique_id))]
else:
self._probes[process_name].append((unique_id,self._ProxyClass(process_name, unique_id)))
+ # Register the probe that was just installed as the current activity
+ # (this will be true by default since we probably were waiting for it
+ # to open up)
+ self.currentActivity = process_name
+ cnt_action = 0
+ for pending_action in self.list_pending_actions:
+ self._first_proxy(self.currentActivity).install(
+ action=pending_action,
+ is_editing=False,
+ action_installed_cb=self.list_action_installed_cb[cnt_action],
+ error_cb=self.list_error_cb[cnt_action],
+ editing_cb=False
+ )
+ cnt_action = cnt_action + 1
+
+ cnt_transition = 0
+ for pending_transition in self.list_pending_transitions:
+ self._first_proxy(self.currentActivity).subscribe(
+ pending_transition,
+ self.list_notification_cb[cnt_transition],
+ self.list_event_subscribed_cb[cnt_transition],
+ self.list_error_cb[cnt_transition]
+ )
+ cnt_transition = cnt_transition + 1
+
+ self.list_pending_actions = []
+ self.list_action_installed_cb = []
+ self.list_error_cb = []
+
+ self.list_pending_transitions = []
+ self.list_notification_cb = []
+ self.list_event_subscribed_cb = []
+ self.list_error_cb = []
+
+ self.is_activity_launching = False
def unregister_probe(self, unique_id):
""" Remove a probe from the known probes.