Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/sugar/tutorius/bundler.py
diff options
context:
space:
mode:
authorSimon Poirier <simpoir@gmail.com>2009-07-02 05:27:27 (GMT)
committer Simon Poirier <simpoir@gmail.com>2009-07-02 05:27:27 (GMT)
commit9fafb49af210e956d43d6a00106558d1a00d13df (patch)
tree5732d7950fab9915705685e0612ef4186111ef4a /src/sugar/tutorius/bundler.py
parent651700dfb6f42c61b8791b75f78cc60f7234ec92 (diff)
* Modularized actions and event filters through add-on components
* Working serialization * Working editor with addons * began refactoring actions and events ** fixed some tests to work with addons ** filters and actions tests won't pass until refactoring is done
Diffstat (limited to 'src/sugar/tutorius/bundler.py')
-rw-r--r--src/sugar/tutorius/bundler.py189
1 files changed, 54 insertions, 135 deletions
diff --git a/src/sugar/tutorius/bundler.py b/src/sugar/tutorius/bundler.py
index 0eb6b64..8e7fc3d 100644
--- a/src/sugar/tutorius/bundler.py
+++ b/src/sugar/tutorius/bundler.py
@@ -25,7 +25,7 @@ import os
import uuid
import xml.dom.minidom
-from sugar.tutorius import gtkutils, overlayer, tutorial
+from sugar.tutorius import addon
from sugar.tutorius.core import Tutorial, State, FiniteStateMachine
from sugar.tutorius.filters import *
from sugar.tutorius.actions import *
@@ -45,6 +45,7 @@ INI_NAME_PROPERTY = "NAME"
INI_XML_FSM_PROPERTY = "FSM_FILENAME"
INI_FILENAME = "meta.ini"
TUTORIAL_FILENAME = "tutorial.xml"
+NODE_COMPONENT = "Component"
class TutorialStore(object):
@@ -147,54 +148,35 @@ class XMLSerializer(Serializer):
eventfiltersList = stateNode.appendChild(self._create_event_filters_node(state.get_event_filter_list(), doc))
return statesList
- def _create_action_node(self, action, doc):
+ def _create_component_node(self, comp, doc):
"""
- Takes a single action and transforms it into a xml node.
+ Takes a single component (action or eventfilter) and transforms it
+ into a xml node.
- @param action A single action
+ @param comp A single component
@param doc The XML document root (used to create nodes only
- @return A XML Node object with the Action tag name
+ @return A XML Node object with the component tag name
"""
- actionNode = doc.createElement("Action")
+ compNode = doc.createElement(NODE_COMPONENT)
# Write down just the name of the Action class as the Class
# property --
- actionNode.setAttribute("Class",type(action).__name__)
-
- if type(action) is DialogMessage:
- actionNode.setAttribute("Message", action.message.value)
- actionNode.setAttribute("PositionX", str(action.position.value[0]))
- actionNode.setAttribute("PositionY", str(action.position.value[1]))
- elif type(action) is BubbleMessage:
- actionNode.setAttribute("Message", action.message.value)
- actionNode.setAttribute("PositionX", str(action.position.value[0]))
- actionNode.setAttribute("PositionY", str(action.position.value[1]))
- actionNode.setAttribute("Tail_posX", str(action.tail_pos.value[0]))
- actionNode.setAttribute("Tail_posY", str(action.tail_pos.value[1]))
- # TO ADD : elif for each type of action
- elif type(action) is WidgetIdentifyAction:
- # Nothing else to save
- pass
- elif type(action) is ChainAction:
- # Recusively write the contained actions - in the correct order
- subActionsNode = self._create_action_list_node(action._actions, doc)
- actionNode.appendChild(subActionsNode)
- elif type(action) is DisableWidgetAction:
- # Remember the target
- actionNode.setAttribute("Target", action._target)
- elif type(action) is TypeTextAction:
- # Save the text and the widget
- actionNode.setAttribute("Widget", action._widget)
- actionNode.setAttribute("Text", action._text)
- elif type(action) is ClickAction:
- # Save the widget to click
- actionNode.setAttribute("Widget", action._widget)
- elif type(action) is OnceWrapper:
- # Encapsulate the action in a OnceWrapper
- subActionNode = self._create_action_node(action._action, doc)
- actionNode.appendChild(subActionNode)
-
- return actionNode
+ compNode.setAttribute("Class",type(comp).__name__)
+
+ # serialize all tutorius properties
+ for propname in comp.get_properties():
+ propval = getattr(comp, propname)
+ if getattr(type(comp), propname).type == "addonlist":
+ for subval in propval:
+ compNode.appendChild(self._create_component_node(subval, doc))
+ elif getattr(type(comp), propname).type == "addonlist":
+ compNode.appendChild(self._create_component_node(subval, doc))
+ else:
+ # repr instead of str, as we want to be able to eval() it into a
+ # valid object.
+ compNode.setAttribute(propname, repr(propval))
+
+ return compNode
def _create_action_list_node(self, action_list, doc):
"""
@@ -208,7 +190,7 @@ class XMLSerializer(Serializer):
actionsList = doc.createElement("Actions")
for action in action_list:
# Create the action node
- actionNode = self._create_action_node(action, doc)
+ actionNode = self._create_component_node(action, doc)
# Append it to the list
actionsList.appendChild(actionNode)
@@ -220,38 +202,17 @@ class XMLSerializer(Serializer):
"""
eventFiltersList = doc.createElement("EventFiltersList")
for event_f in event_filters:
- eventFilterNode = doc.createElement("EventFilter")
+ eventFilterNode = self._create_component_node(event_f, doc)
eventFiltersList.appendChild(eventFilterNode)
-
- # Write down just the name of the Action class as the Class
- # property --
- eventFilterNode.setAttribute("Class", type(event_f).__name__)
-
- # Write the name of the next state
- eventFilterNode.setAttribute("NextState", event_f.next_state)
-
- if type(event_f) is TimerEvent:
- eventFilterNode.setAttribute("Timeout_s", str(event_f._timeout))
-
- elif type(event_f) is GtkWidgetEventFilter:
- eventFilterNode.setAttribute("EventName", event_f._event_name)
- eventFilterNode.setAttribute("ObjectId", event_f._object_id)
-
- elif type(event_f) is GtkWidgetTypeFilter:
- eventFilterNode.setAttribute("ObjectId", event_f._object_id)
- if event_f._strokes is not None:
- eventFilterNode.setAttribute("Strokes", event_f._strokes)
- if event_f._text is not None:
- eventFilterNode.setAttribute("Text", event_f._text)
-
- return eventFiltersList
+
+ return eventFiltersList
def save_fsm(self, fsm, xml_filename, path):
"""
Save fsm to disk, in the xml file specified by "xml_filename", in the
"path" folder. If the specified file doesn't exist, it will be created.
"""
- doc = xml.dom.minidom.Document()
+ self.doc = doc = xml.dom.minidom.Document()
fsm_element = doc.createElement("FSM")
doc.appendChild(fsm_element)
fsm_element.setAttribute("Name", fsm.name)
@@ -335,84 +296,42 @@ class XMLSerializer(Serializer):
@param filters_elem An XML Element representing a list of event filters
"""
reformed_event_filters_list = []
- event_filter_element_list = filters_elem.getElementsByTagName("EventFilter")
+ event_filter_element_list = filters_elem.getElementsByTagName(NODE_COMPONENT)
new_event_filter = None
for event_filter in event_filter_element_list:
- # Load the name of the next state for this filter
- next_state = event_filter.getAttribute("NextState")
-
- if event_filter.getAttribute("Class") == str(TimerEvent):
- timeout = int(event_filter.getAttribute("Timeout_s"))
- new_event_filter = TimerEvent(next_state, timeout)
-
- elif event_filter.getAttribute("Class") == str(GtkWidgetEventFilter):
- # Get the event name and the object's ID
- event_name = event_filter.getAttribute("EventName")
- object_id = event_filter.getAttribute("ObjectId")
-
- new_event_filter = GtkWidgetEventFilter(next_state, object_id, event_name)
- elif event_filter.getAttribute("Class") == str(GtkWidgetTypeFilter):
- # Get the widget to write in and the text
- object_id = event_filter.getAttribute("ObjectId")
- if event_filter.hasAttribute("Text"):
- text = event_filter.getAttribute("Text")
- new_event_filter = GtkWidgetTypeFilter(next_state, object_id, text=text)
- elif event_filter.hasAttribute("Strokes"):
- strokes = event_filter.getAttribute("Strokes")
- new_event_filter = GtkWidgetTypeFilter(next_state, object_id, strokes=strokes)
+ new_event_filter = self._load_xml_component(event_filter)
if new_event_filter is not None:
reformed_event_filters_list.append(new_event_filter)
return reformed_event_filters_list
- def _load_xml_action(self, action):
+ def _load_xml_component(self, node):
"""
- Loads a single action from an Xml Action node.
+ Loads a single addon component instance from an Xml node.
- @param action The Action XML Node to transform
+ @param node The component XML Node to transform
object
- @return The Action object of the correct type according to the XML
+ @return The addon component object of the correct type according to the XML
description
"""
- # TO ADD: an elif for each type of action
- if action.getAttribute("Class") == 'DialogMessage':
- message = action.getAttribute("Message")
- positionX = int(action.getAttribute("PositionX"))
- positionY = int(action.getAttribute("PositionY"))
- position = [positionX, positionY]
- return DialogMessage(message,position)
- elif action.getAttribute("Class") == 'BubbleMessage':
- message = action.getAttribute("Message")
- positionX = int(action.getAttribute("PositionX"))
- positionY = int(action.getAttribute("PositionY"))
- position = [positionX, positionY]
- tail_posX = int(action.getAttribute("Tail_posX"))
- tail_posY = int(action.getAttribute("Tail_posY"))
- tail_pos = [tail_posX, tail_posY]
- return BubbleMessage(message,position,None,tail_pos)
- elif action.getAttribute("Class") == 'WidgetIdentifyAction':
- return WidgetIdentifyAction()
- elif action.getAttribute("Class") == 'ChainAction':
- # Load the subactions
- subActionsList = self._load_xml_actions(action.getElementsByTagName("Actions")[0])
- return ChainAction(subActionsList)
- elif action.getAttribute("Class") == 'DisableWidgetAction':
- # Get the target
- targetName = action.getAttribute("Target")
- return DisableWidgetAction(targetName)
- elif action.getAttribute("Class") == 'TypeTextAction':
- # Get the widget and the text to type
- widget = action.getAttribute("Widget")
- text = action.getAttribute("Text")
-
- return TypeTextAction(widget, text)
- elif action.getAttribute("Class") == 'ClickAction':
- # Load the widget to click
- widget = action.getAttribute("Widget")
-
- return ClickAction(widget)
+ new_action = addon.create(node.getAttribute("Class"))
+ if not new_action:
+ return None
+
+ for attrib in node.attributes.keys():
+ if attrib == "Class": continue
+ # security note: keep sandboxed
+ setattr(new_action, attrib, eval(node.getAttribute(attrib), {}, {}))
+
+ # recreate complex attributes
+ for sub in node.childNodes:
+ name = getattr(new_action, sub.nodeName)
+ if name == "addon":
+ setattr(new_action, sub.getAttribute("Name"), self._load_xml_action(sub))
+
+ return new_action
def _load_xml_actions(self, actions_elem):
"""
@@ -421,10 +340,10 @@ class XMLSerializer(Serializer):
@param actions_elem An XML Element representing a list of Actions
"""
reformed_actions_list = []
- actions_element_list = actions_elem.getElementsByTagName("Action")
+ actions_element_list = actions_elem.getElementsByTagName(NODE_COMPONENT)
for action in actions_element_list:
- new_action = self._load_xml_action(action)
+ new_action = self._load_xml_component(action)
reformed_actions_list.append(new_action)
@@ -451,7 +370,7 @@ class XMLSerializer(Serializer):
reformed_state_list.append(State(stateName, actions_list, event_filters_list))
return reformed_state_list
-
+
def _load_xml_fsm(self, fsm_elem):
"""
Takes in an XML element representing an FSM and returns the fully