Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Poirier <simpoir@gmail.com>2009-12-01 05:57:04 (GMT)
committer Simon Poirier <simpoir@gmail.com>2009-12-01 06:05:27 (GMT)
commit50ec9ae6ebc7ecc088b5e0a6b79688a717271955 (patch)
tree86f79a5530c135a279cfcf1deadbb199230ec197
parent6c7cab75774cf5591657c051397b665ec727aa0e (diff)
creator with probe integration. updating existing objects doesn't work yetHEADmaster
-rw-r--r--data/ui/creator.glade50
-rwxr-xr-xsetup.py14
-rwxr-xr-xsrc/extensions/tutoriusremote.py74
-rw-r--r--tutorius/TProbe.py117
-rw-r--r--tutorius/creator.py248
-rw-r--r--tutorius/viewer.py3
6 files changed, 341 insertions, 165 deletions
diff --git a/data/ui/creator.glade b/data/ui/creator.glade
index 1c9669d..aeba19c 100644
--- a/data/ui/creator.glade
+++ b/data/ui/creator.glade
@@ -1,16 +1,19 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Sun Nov 1 16:39:50 2009 -->
<glade-interface>
- <!-- interface-requires gtk+ 2.16 -->
- <!-- interface-naming-policy project-wide -->
<widget class="GtkWindow" id="mainwindow">
<property name="width_request">300</property>
<property name="height_request">500</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="title" translatable="yes">Toolbox</property>
<property name="resizable">False</property>
- <property name="window_position">center-on-parent</property>
+ <property name="decorated">False</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="default_width">200</property>
<property name="default_height">500</property>
<property name="destroy_with_parent">True</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_UTILITY</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="focus_on_map">False</property>
@@ -19,35 +22,37 @@
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
+ <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
<property name="spacing">5</property>
+ <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
<child>
<widget class="GtkHButtonBox" id="hbuttonbox1">
<property name="visible">True</property>
<property name="spacing">5</property>
- <property name="layout_style">start</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
<child>
<widget class="GtkButton" id="button2">
- <property name="label">gtk-save</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <property name="label">gtk-save</property>
<property name="use_stock">True</property>
+ <property name="response_id">0</property>
<signal name="clicked" handler="on_save_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button4">
- <property name="label">gtk-quit</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <property name="label">gtk-quit</property>
<property name="use_stock">True</property>
+ <property name="response_id">0</property>
<signal name="clicked" handler="on_quit_clicked"/>
</widget>
<packing>
@@ -60,24 +65,24 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
- <property name="shadow_type">in</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
<child>
<widget class="GtkViewport" id="viewport1">
<property name="visible">True</property>
- <property name="resize_mode">queue</property>
+ <property name="resize_mode">GTK_RESIZE_QUEUE</property>
<child>
<widget class="GtkVBox" id="vbox2">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
+ <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
+ <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
<child>
<widget class="GtkExpander" id="expander1">
<property name="visible">True</property>
@@ -90,7 +95,6 @@
<property name="columns">2</property>
<property name="row_spacing">0</property>
<property name="column_spacing">0</property>
- <property name="item_padding">0</property>
<signal name="item_activated" handler="on_action_activate"/>
</widget>
</child>
@@ -106,7 +110,6 @@
</widget>
<packing>
<property name="expand">False</property>
- <property name="position">0</property>
</packing>
</child>
<child>
@@ -121,7 +124,6 @@
<property name="columns">2</property>
<property name="row_spacing">0</property>
<property name="column_spacing">0</property>
- <property name="item_padding">0</property>
<signal name="item_activated" handler="on_event_activate"/>
</widget>
</child>
@@ -153,8 +155,9 @@
<child>
<widget class="GtkVBox" id="propbox">
<property name="visible">True</property>
- <property name="orientation">vertical</property>
+ <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
<property name="spacing">10</property>
+ <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
<child>
<placeholder/>
</child>
@@ -169,26 +172,27 @@
<widget class="GtkHButtonBox" id="hbuttonbox2">
<property name="visible">True</property>
<property name="spacing">5</property>
- <property name="layout_style">start</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
<child>
<widget class="GtkButton" id="button1">
- <property name="label">gtk-media-record</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <property name="label">gtk-media-record</property>
<property name="use_stock">True</property>
+ <property name="response_id">0</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button3">
- <property name="label">gtk-media-stop</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
+ <property name="label">gtk-media-stop</property>
<property name="use_stock">True</property>
+ <property name="response_id">0</property>
</widget>
<packing>
<property name="expand">False</property>
diff --git a/setup.py b/setup.py
index e33873c..49bae4c 100755
--- a/setup.py
+++ b/setup.py
@@ -74,7 +74,7 @@ class TestCommand(Command):
sources)
coverage.report(sources)
coverage.erase()
-
+
def _listsources(self, arg, dirname, fnames):
fnames = filter(lambda x:x.endswith('.py'), fnames)
for name in fnames:
@@ -83,7 +83,7 @@ class TestCommand(Command):
setup(name='Tutorius',
version='0.0',
description='Interactive tutor and Tutorial creator',
- maintainer='Simon Poirier',
+ maintainer='Simon Poirier',
maintainer_email='simpoir@gmail.com',
author='Tutorius team',
author_email='sugar-narratives@googlegroups.com',
@@ -97,13 +97,15 @@ setup(name='Tutorius',
'sugar.tutorius.apilib.httplib2',
],
package_dir={
- 'sugar.tutorius': 'tutorius',
- 'sugar.tutorius.addons': 'addons',
- },
+ 'sugar.tutorius': 'tutorius',
+ 'sugar.tutorius.addons': 'addons',
+ },
cmdclass = {'test': TestCommand},
data_files=[('share/icons/sugar/scalable/actions', glob.glob('data/icons/*.svg')),
+ ('share/icons/sugar/scalable/device', ['data/icons/tutortool.svg']),
('share/tutorius/ui', glob.glob('data/ui/*.glade')),
+ ('share/sugar/extensions/deviceicon', glob.glob('src/extensions/*')),
]
)
-# vim: set et sw=4 sts=4 ts=4:
+# vim: set et sw=4 sts=4 ts=4:
diff --git a/src/extensions/tutoriusremote.py b/src/extensions/tutoriusremote.py
new file mode 100755
index 0000000..9bb4bfb
--- /dev/null
+++ b/src/extensions/tutoriusremote.py
@@ -0,0 +1,74 @@
+# Copyright (C) 2009, Tutorius.org
+# Copyright (C) 2009, Simon Poirier <simpoir@gmail.com>
+#
+#
+# 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
+"""
+This modules regroups the UI elements that drives the tutorial and tutorial
+creator from the Sugar frame.
+"""
+
+import gtk
+from gettext import gettext as _
+import gconf
+import dbus
+
+from sugar.graphics.tray import TrayIcon
+from sugar.graphics.palette import Palette
+from sugar.graphics.xocolor import XoColor
+
+from jarabe.frame.frameinvoker import FrameWidgetInvoker
+
+from sugar.tutorius.creator import default_creator
+
+_ICON_NAME = 'tutortool'
+
+class TutoriusRemote(TrayIcon):
+
+ FRAME_POSITION_RELATIVE = 102
+
+ def __init__(self, creator):
+ self._creator = creator
+
+ client = gconf.client_get_default()
+ self._color = XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ super(TutoriusRemote, self).__init__(icon_name=_ICON_NAME,
+ xo_color=self._color)
+
+ self.set_palette_invoker(FrameWidgetInvoker(self))
+
+ self.palette = TPalette(_('Tutorius'))
+ self.palette.set_group_id('frame')
+
+
+class TPalette(Palette):
+ def __init__(self, primary_text):
+ super(TPalette, self).__init__(primary_text)
+
+ self._creator_item = gtk.MenuItem(_('Create a tutorial'))
+ self._creator_item.connect('activate', self._start_creator)
+ self._creator_item.show()
+ self.menu.append(self._creator_item)
+
+ self.set_content(None)
+
+ def _start_creator(self, widget):
+ default_creator().start_authoring(tutorial=None)
+
+
+
+def setup(tray):
+ tray.add_device(TutoriusRemote(default_creator()))
diff --git a/tutorius/TProbe.py b/tutorius/TProbe.py
index 4e458a0..5b5cf8d 100644
--- a/tutorius/TProbe.py
+++ b/tutorius/TProbe.py
@@ -20,14 +20,12 @@ import os
import gobject
-import dbus
import dbus.service
import cPickle as pickle
from . import addon
from .services import ObjectStore
-from .properties import TPropContainer
from .dbustools import save_args, ignore, logError
import copy
@@ -127,11 +125,12 @@ class TProbe(dbus.service.Object):
# ------------------ Action handling --------------------------------------
@dbus.service.method("org.tutorius.ProbeInterface",
- in_signature='s', out_signature='s')
- def install(self, pickled_action):
+ in_signature='sb', out_signature='s')
+ def install(self, pickled_action, is_editing):
"""
Install an action on the Activity
@param pickled_action string pickled action
+ @param is_editing whether this action comes from the editor
@return string address of installed action
"""
loaded_action = pickle.loads(str(pickled_action))
@@ -144,17 +143,21 @@ class TProbe(dbus.service.Object):
if action._props:
action._props.update(loaded_action._props)
- action.do(activity=self._activity)
-
+ if not is_editing:
+ action.do(activity=self._activity)
+ else:
+ action.enter_editmode()
+
return address
@dbus.service.method("org.tutorius.ProbeInterface",
- in_signature='ss', out_signature='')
- def update(self, address, action_props):
+ in_signature='ssb', out_signature='')
+ def update(self, address, action_props, is_editing):
"""
Update an already registered action
@param address string address returned by install()
@param action_props pickled action properties
+ @param is_editing whether this action comes from the editor
@return None
"""
action = self._installedActions[address]
@@ -162,26 +165,47 @@ class TProbe(dbus.service.Object):
if action._props:
props = pickle.loads(str(action_props))
action._props.update(props)
- action.undo()
- action.do()
+ if not is_editing:
+ action.undo()
+ action.do()
+ else:
+ action.exit_editmode()
+ action.enter_editmode()
@dbus.service.method("org.tutorius.ProbeInterface",
- in_signature='s', out_signature='')
- def uninstall(self, address):
+ in_signature='sb', out_signature='')
+ def uninstall(self, address, is_editing):
"""
Uninstall an action
@param address string address returned by install()
+ @param is_editing whether this action comes from the editor
@return None
"""
if self._installedActions.has_key(address):
action = self._installedActions[address]
- action.undo()
+ if not is_editing:
+ action.undo()
+ else:
+ action.exit_editmode()
self._installedActions.pop(address)
# ------------------ Event handling ---------------------------------------
@dbus.service.method("org.tutorius.ProbeInterface",
in_signature='s', out_signature='s')
+ def create_event(self, addon_name):
+ # avoid recursive imports
+ event = addon.create(addon_name)
+ addonname = type(event).__name__
+ meta = addon.get_addon_meta(addonname)
+ for propname in meta['mandatory_props']:
+ prop = getattr(type(event), propname)
+ prop.widget_class.run_dialog(self._activity, event, propname)
+
+ return pickle.dumps(event)
+
+ @dbus.service.method("org.tutorius.ProbeInterface",
+ in_signature='s', out_signature='s')
def subscribe(self, pickled_event):
"""
Subscribe to an Event
@@ -318,45 +342,47 @@ class ProbeProxy:
def __clear_action(self, address):
self._actions.pop(address, None)
- def install(self, action, action_installed_cb, error_cb):
+ def install(self, action, action_installed_cb, error_cb, is_editing=False):
"""
Install an action on the TProbe's activity
@param action Action to install
@param action_installed_cb The callback function to call once the action is installed
@param error_cb The callback function to call when an error happens
+ @param is_editing whether this action comes from the editor
@return None
"""
- self._probe.install(pickle.dumps(action),
- reply_handler=save_args(self.__update_action, action, action_installed_cb),
+ self._probe.install(pickle.dumps(action), is_editing,
+ reply_handler=save_args(self.__update_action, action, action_installed_cb),
error_handler=save_args(error_cb, action))
- def update(self, action_address, newaction):
+ def update(self, action_address, newaction, is_editing=False):
"""
Update an already installed action's properties and run it again
@param action_address The address of the action to update. This is
provided by the install callback method.
@param newaction Action to update it with
@param block Force a synchroneous dbus call if True
+ @param is_editing whether this action comes from the editor
@return None
"""
#TODO review how to make this work well
if not action_address in self._actions.keys():
raise RuntimeWarning("Action not installed")
#TODO Check error handling
- return self._probe.update(action_address, pickle.dumps(newaction._props),
+ return self._probe.update(action_address, pickle.dumps(newaction._props), is_editing,
reply_handler=ignore,
error_handler=logError)
- def uninstall(self, action_address):
+ def uninstall(self, action_address, is_editing):
"""
Uninstall an installed action
@param action_address The address of the action to uninstall. This address was given
on action installation
- @param block Force a synchroneous dbus call if True
+ @param is_editing whether this action comes from the editor
"""
if action_address in self._actions:
self._actions.pop(action_address, None)
- self._probe.uninstall(action_address, reply_handler=ignore, error_handler=logError)
+ self._probe.uninstall(action_address, is_editing, reply_handler=ignore, error_handler=logError)
def __update_event(self, event, callback, event_subscribed_cb, address):
LOGGER.debug("ProbeProxy :: Registered event %s with address %s", str(hash(event)), str(address))
@@ -407,7 +433,18 @@ class ProbeProxy:
else:
LOGGER.debug("ProbeProxy :: unsubsribe address %s inconsistency : not registered", address)
+ def create_event(self, addon_name):
+ """
+ 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
+ @returns: an eventfilter instance
+ """
+ return pickle.loads(str(self._probe.create_event(addon_name)))
+
def subscribe(self, event, notification_cb, event_subscribed_cb, error_cb):
+
"""
Register an event listener
@param event Event to listen for
@@ -464,6 +501,8 @@ class ProbeManager(object):
"""
_LOGGER = logging.getLogger("sugar.tutorius.ProbeManager")
+ default_instance = None
+
def __init__(self, proxy_class=ProbeProxy):
"""Constructor
@param proxy_class Class to use for creating Proxies to activities.
@@ -478,6 +517,8 @@ class ProbeManager(object):
ProbeManager._LOGGER.debug("__init__()")
+ ProbeManager.default_instance = self
+
def setCurrentActivity(self, activity_id):
if not activity_id in self._probes:
raise RuntimeError("Activity not attached")
@@ -488,41 +529,61 @@ class ProbeManager(object):
currentActivity = property(fget=getCurrentActivity, fset=setCurrentActivity)
- def install(self, action, action_installed_cb, error_cb):
+ def install(self, action, action_installed_cb, error_cb, is_editing=False):
"""
Install an action on the current activity
@param action Action to install
@param action_installed_cb The callback to call once the action is installed
@param error_cb The callback that will be called if there is an error during installation
@param block Force a synchroneous dbus call if True
+ @param is_editing whether this action comes from the editor
@return None
"""
if self.currentActivity:
- return self._first_proxy(self.currentActivity).install(action, action_installed_cb, error_cb)
+ return self._first_proxy(self.currentActivity).install(
+ action=action,
+ is_editing=is_editing,
+ action_installed_cb=action_installed_cb,
+ error_cb=error_cb)
else:
raise RuntimeWarning("No activity attached")
- def update(self, action_address, newaction):
+ def update(self, action_address, newaction, is_editing=False):
"""
Update an already installed action's properties and run it again
@param action_address Action to update
@param newaction Action to update it with
@param block Force a synchroneous dbus call if True
+ @param is_editing whether this action comes from the editor
@return None
"""
if self.currentActivity:
- return self._first_proxy(self.currentActivity).update(action_address, newaction)
+ return self._first_proxy(self.currentActivity).update(action_address, newaction, is_editing)
else:
raise RuntimeWarning("No activity attached")
- def uninstall(self, action_address):
+ def uninstall(self, action_address, is_editing=False):
"""
Uninstall an installed action
- @param action Action to uninstall
+ @param action_address Action to uninstall
@param block Force a synchroneous dbus call if True
+ @param is_editing whether this action comes from the editor
+ """
+ if self.currentActivity:
+ return self._first_proxy(self.currentActivity).uninstall(action_address, is_editing)
+ else:
+ raise RuntimeWarning("No activity attached")
+
+ def create_event(self, addon_name):
+ """
+ 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
+ @returns: an eventfilter instance
"""
if self.currentActivity:
- return self._first_proxy(self.currentActivity).uninstall(action_address)
+ return self._first_proxy(self.currentActivity).create_event(addon_name)
else:
raise RuntimeWarning("No activity attached")
diff --git a/tutorius/creator.py b/tutorius/creator.py
index fd9f1e8..54e2912 100644
--- a/tutorius/creator.py
+++ b/tutorius/creator.py
@@ -27,27 +27,71 @@ from gettext import gettext as T
import uuid
import os
-from sugar.graphics import icon
+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
+from . import TProbe
-class Creator(object):
+from functools import partial
+
+from dbus import SessionBus
+from dbus.service import method, Object, BusName
+
+BUS_PATH = "/org/tutorius/Creator"
+BUS_NAME = "org.tutorius.Creator"
+
+def default_creator():
+ """
+ The Creator class is a singleton. There can never be more than one creator
+ at a time. This method returns a new instance only if none
+ already exists. Else, the existing instance is returned.
+ """
+ Creator._instance = Creator._instance or Creator()
+ return Creator._instance
+
+def get_creator_proxy():
+ """
+ Returns a Creator dbus proxy for inter-process events.
"""
- Class acting as a bridge between the creator, serialization and core
- classes. This contains most of the UI part of the editor.
+ bus = dbus.SessionBus()
+ proxy = bus.get_object(BUS_NAME, BUS_PATH)
+ return proxy
+
+class Creator(Object):
"""
- def __init__(self, activity, tutorial=None):
+ Class acting as a controller for the tutorial edition.
+ """
+
+ _instance = None
+
+ def __init__(self):
+ bus_name = BusName(BUS_NAME, bus=SessionBus())
+ Object.__init__(self, bus_name, BUS_PATH)
+
+ self.tuto = None
+ self.is_authoring = False
+ Creator._instance = self
+ self._probe_mgr = TProbe.ProbeManager.default_instance
+ self._installed_actions = list()
+
+ def start_authoring(self, tutorial=None):
"""
- Instanciate a tutorial creator for the activity.
+ Start authoring a tutorial.
- @param activity to bind the creator to
- @param tutorial an existing tutorial to edit, or None to create one
+ @type tutorial: str or None
+ @param tutorial: the unique identifier to an existing tutorial to
+ modify, or None to create a new one.
"""
- self._activity = activity
+ if self.is_authoring:
+ raise Exception("Already authoring")
+
+ self.is_authoring = True
+
if not tutorial:
self._tutorial = Tutorial('Untitled')
self._state = self._tutorial.add_state()
@@ -68,21 +112,15 @@ class Creator(object):
self._action_panel = None
self._current_filter = None
- self._intro_mask = None
- self._intro_handle = None
- allocation = self._activity.get_allocation()
- self._width = allocation.width
- self._height = allocation.height
self._selected_widget = None
self._eventmenu = None
self.tuto = None
self._guid = None
self.metadata = None
- self._hlmask = overlayer.Rectangle(None, (1.0, 0.0, 0.0, 0.5))
- self._activity._overlayer.put(self._hlmask, 0, 0)
+ frame = jarabe.frame.get_view()
- self._propedit = ToolBox(self._activity)
+ self._propedit = ToolBox(None)
self._propedit.tree.signal_autoconnect({
'on_quit_clicked': self._cleanup_cb,
'on_save_clicked': self.save,
@@ -90,18 +128,39 @@ class Creator(object):
'on_event_activate': self._add_event_cb,
})
self._propedit.window.move(
- gtk.gdk.screen_width()-self._propedit.window.get_allocation().width,
- 100)
-
+ gtk.gdk.screen_width()-self._propedit.window.get_allocation().width\
+ -style.GRID_CELL_SIZE,
+ style.GRID_CELL_SIZE)
+ self._propedit.window.connect('enter-notify-event',
+ frame._enter_notify_cb)
+ self._propedit.window.connect('leave-notify-event',
+ frame._leave_notify_cb)
self._overview = viewer.Viewer(self._tutorial, self)
- self._overview.win.set_transient_for(self._activity)
+ self._overview.win.set_transient_for(frame._bottom_panel)
+ self._overview.win.connect('enter-notify-event',
+ frame._enter_notify_cb)
+ self._overview.win.connect('leave-notify-event',
+ frame._leave_notify_cb)
- self._overview.win.move(0, gtk.gdk.screen_height()- \
- self._overview.win.get_allocation().height)
+ self._overview.win.move(style.GRID_CELL_SIZE,
+ gtk.gdk.screen_height()-style.GRID_CELL_SIZE \
+ -self._overview.win.get_allocation().height)
self._transitions = dict()
+ # FIXME : remove when probemgr completed
+ #self._probe_mgr.attach('org.laptop.Calculate')
+ self._probe_mgr._current_activity = 'org.laptop.Calculate'
+
+ def _tool_enter_notify_cb(self, window, event):
+ frame = jarabe.frame.get_view()
+ frame._bottom_panel.hover = True
+
+ def _tool_leave_notify_cb(self, window, event):
+ frame = jarabe.frame.get_view()
+ frame._bottom_panel.hover = False
+
def _update_next_state(self, state, event, next_state):
self._transitions[event] = next_state
@@ -121,7 +180,8 @@ class Creator(object):
.get(action, None)
if not action_obj:
return False
- action_obj.exit_editmode()
+
+ self._probe_mgr.uninstall(action_obj.address)
self._tutorial.delete_action(action)
self._overview.win.queue_draw()
return True
@@ -168,80 +228,43 @@ class Creator(object):
or state_name == self._tutorial.END:
return
- for action in self._tutorial.get_action_dict(self._state).values():
- action.exit_editmode()
+ for action in self._installed_actions:
+ self._probe_mgr.uninstall(action.address,
+ is_editing=True)
+ self._installed_actions = []
self._state = state_name
state_actions = self._tutorial.get_action_dict(self._state).values()
+
for action in state_actions:
- action.enter_editmode()
- action._drag._eventbox.connect_after(
- "button-release-event", self._action_refresh_cb, action)
+ return_cb = partial(self._action_installed_cb, action)
+ self._probe_mgr.install(action,
+ action_installed_cb=return_cb,
+ error_cb=self._dbus_exception,
+ is_editing=True)
if state_actions:
+ # I'm really lazy right now and to keep things simple I simply
+ # always select the first action when
+ # we change state. we should really select the clicked block
+ # in the overview instead. FIXME
self._propedit.action = state_actions[0]
else:
self._propedit.action = None
self._overview.win.queue_draw()
-
- def _evfilt_cb(self, menuitem, event):
- """
- This will get called once the user has selected a menu item from the
- event filter popup menu. This should add the correct event filter
- to the FSM and increment states.
- """
- # undo actions so they don't persist through step editing
- for action in self._state.get_action_list():
- action.exit_editmode()
- self._hlmask.covered = None
- self._propedit.action = None
- self._activity.queue_draw()
-
- def _intro_cb(self, widget, evt):
- """
- Callback for capture of widget events, when in introspect mode.
- """
- if evt.type == gtk.gdk.BUTTON_PRESS:
- # widget has focus, let's hilight it
- win = gtk.gdk.display_get_default().get_window_at_pointer()
- click_wdg = win[0].get_user_data()
- if not click_wdg.is_ancestor(self._activity._overlayer):
- # as popups are not (yet) supported, it would break
- # badly if we were to play with a widget not in the
- # hierarchy.
- return
- for hole in self._intro_mask.pass_thru:
- self._intro_mask.mask(hole)
- self._intro_mask.unmask(click_wdg)
- self._selected_widget = gtkutils.raddr_lookup(click_wdg)
-
- if self._eventmenu:
- self._eventmenu.destroy()
- self._eventmenu = gtk.Menu()
- menuitem = gtk.MenuItem(label=type(click_wdg).__name__)
- menuitem.set_sensitive(False)
- self._eventmenu.append(menuitem)
- self._eventmenu.append(gtk.MenuItem())
-
- for item in gobject.signal_list_names(click_wdg):
- menuitem = gtk.MenuItem(label=item)
- menuitem.connect("activate", self._evfilt_cb, item)
- self._eventmenu.append(menuitem)
- self._eventmenu.show_all()
- self._eventmenu.popup(None, None, None, evt.button, evt.time)
- self._activity.queue_draw()
-
def _add_action_cb(self, widget, path):
"""Callback for the action creation toolbar tool"""
action_type = self._propedit.actions_list[path][ToolBox.ICON_NAME]
action = addon.create(action_type)
- action.enter_editmode()
+ return_cb = partial(self._action_installed_cb, action)
+ self._probe_mgr.install(action,
+ action_installed_cb=return_cb,
+ error_cb=self._dbus_exception,
+ is_editing=True)
self._tutorial.add_action(self._state, action)
- # FIXME: replace following with event catching
- action._drag._eventbox.connect_after(
- "button-release-event", self._action_refresh_cb, action)
+ self._propedit.action = action
self._overview.win.queue_draw()
def _add_event_cb(self, widget, path):
@@ -266,12 +289,7 @@ class Creator(object):
"""
event_type = self._propedit.events_list[path][ToolBox.ICON_NAME]
- event = addon.create(event_type)
- addonname = type(event).__name__
- meta = addon.get_addon_meta(addonname)
- for propname in meta['mandatory_props']:
- prop = getattr(type(event), propname)
- prop.widget_class.run_dialog(self._activity, event, propname)
+ event = self._probe_mgr.create_event(event_type)
event_filters = self._tutorial.get_transition_dict(self._state)
@@ -296,17 +314,21 @@ class Creator(object):
self.set_insertion_point(new_state)
+ def properties_changed(self, action, properties):
+ pass
+
def _action_refresh_cb(self, widget, evt, action):
"""
Callback for refreshing properties values and notifying the
property dialog of the new values.
"""
- action.exit_editmode()
- action.enter_editmode()
- self._activity.queue_draw()
- # TODO: replace following with event catching
- action._drag._eventbox.connect_after(
- "button-release-event", self._action_refresh_cb, action)
+ self._probe_mgr.uninstall(action.address,
+ is_editing=True)
+ return_cb = partial(self._action_installed_cb, action)
+ self._probe_mgr.install(action,
+ action_installed_cb=return_cb,
+ error_cb=self._dbus_exception,
+ is_editing=True)
self._propedit.action = action
self._overview.win.queue_draw()
@@ -319,11 +341,12 @@ class Creator(object):
"""
# undo actions so they don't persist through step editing
for action in self._tutorial.get_action_dict(self._state).values():
- action.exit_editmode()
+ self._probe_mgr.uninstall(action.address,
+ is_editing=True)
if kwargs.get('force', False):
dialog = gtk.MessageDialog(
- parent=self._activity,
+ parent=self._overview.win,
flags=gtk.DIALOG_MODAL,
type=gtk.MESSAGE_QUESTION,
buttons=gtk.BUTTONS_YES_NO,
@@ -335,14 +358,9 @@ class Creator(object):
self.save()
# remove UI remains
- self._hlmask.covered = None
- self._activity._overlayer.remove(self._hlmask)
- self._hlmask.destroy()
- self._hlmask = None
self._propedit.destroy()
self._overview.destroy()
- self._activity.queue_draw()
- del self._activity._creator
+ self.is_authoring = False
def save(self, widget=None):
"""
@@ -369,15 +387,27 @@ class Creator(object):
vault.Vault.saveTutorial(self._tutorial, self._metadata)
+ def launch(self, *args):
+ assert False, "REMOVE THIS CALL!!!"
+ launch = staticmethod(launch)
- def launch(*args, **kwargs):
+ def _action_installed_cb(self, action, address):
"""
- Launch and attach a creator to the currently running activity.
+ This is a callback intented to be use to receive actions addresses
+ after they are installed.
+ @param address: the address of the newly installed action
"""
- activity = ObjectStore().activity
- if not hasattr(activity, "_creator"):
- activity._creator = Creator(activity)
- launch = staticmethod(launch)
+ action.address = address
+ self._installed_actions.append(action)
+
+ def _dbus_exception(self, exception):
+ """
+ This is a callback intented to be use to receive exceptions on remote
+ DBUS calls.
+ @param exception: the exception thrown by the remote process
+ """
+ pass
+
class ToolBox(object):
"""
@@ -396,10 +426,13 @@ class ToolBox(object):
'ui', 'creator.glade')
self.tree = gtk.glade.XML(glade_file)
self.window = self.tree.get_widget('mainwindow')
+ self.window.modify_bg(gtk.STATE_NORMAL,
+ style.COLOR_TOOLBAR_GREY.get_gdk_color())
self._propbox = self.tree.get_widget('propbox')
self._propedits = []
self.window.set_transient_for(parent)
+ self.window.set_keep_above(True)
self._action = None
self.actions_list = gtk.ListStore(str, gtk.gdk.Pixbuf, str, str)
@@ -494,6 +527,7 @@ class ToolBox(object):
self.__parent._creator._action_refresh_cb(None, None, self._action)
+
# The purpose of this function is to reformat text, as current IconView
# implentation does not insert carriage returns on long lines.
# To preserve layout, this call reformat text to fit in small space under an
diff --git a/tutorius/viewer.py b/tutorius/viewer.py
index 56428e1..8041162 100644
--- a/tutorius/viewer.py
+++ b/tutorius/viewer.py
@@ -65,7 +65,8 @@ class Viewer(object):
self.drag_pos = None
self.selection = set()
- self.win = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ self.win = gtk.Window(gtk.WINDOW_POPUP)
+ self.win.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_UTILITY)
self.win.set_size_request(400, 200)
self.win.set_gravity(gtk.gdk.GRAVITY_SOUTH_WEST)
self.win.show()