From fb49b482f5bd478bada50cd1ab25a876806eff31 Mon Sep 17 00:00:00 2001 From: mike Date: Tue, 05 May 2009 05:30:41 +0000 Subject: [LP 352437] Core : Minor refactoring on XMLSerializer, added tests --- (limited to 'src/sugar/tutorius/bundler.py') diff --git a/src/sugar/tutorius/bundler.py b/src/sugar/tutorius/bundler.py index 34b3a12..f9a3911 100644 --- a/src/sugar/tutorius/bundler.py +++ b/src/sugar/tutorius/bundler.py @@ -27,9 +27,8 @@ import xml.dom.minidom from sugar.tutorius import gtkutils, overlayer from sugar.tutorius.core import Tutorial, State, FiniteStateMachine +from sugar.tutorius.filters import * from sugar.tutorius.actions import * -import sugar.tutorius.filters -#from sugar.tutorius.filters import EventFilter, TimerEvent, GtkWidgetEventFilter, GtkWidgetTypeFilter from ConfigParser import SafeConfigParser def _get_store_root(): @@ -132,47 +131,73 @@ 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): + """ + Takes a single action and transforms it into a xml node. + + @param action A single action + @param doc The XML document root (used to create nodes only + @return A XML Node object with the Action tag name + """ + actionNode = doc.createElement("Action") + + # Write down just the name of the Action class as the Class + # property -- + # Using .__class__ since type() doesn't have the same behavior + # with class derivating from object and class that don't + actionNode.setAttribute("Class", str(action.__class__)) + + 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 + def _create_action_list_node(self, action_list, doc): """ Create and return a xml Node from a Action list. + + @param action_list A list of actions + @param doc The XML document root (used to create new nodes only) + @return A XML Node object with the Actions tag name and a serie of + Action children """ actionsList = doc.createElement("Actions") for action in action_list: - actionNode = doc.createElement("Action") + # Create the action node + actionNode = self._create_action_node(action, doc) + # Append it to the list actionsList.appendChild(actionNode) - # Using .__class__ since type() doesn't have the same behavior - # with class derivating from object and class that don't - actionNode.setAttribute("Class", str(action.__class__)) - - if type(action) is DialogMessage: - actionNode.setAttribute("Message", action.message.value) - actionNode.setAttribute("PositionX", 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])) - # TODO : 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_actions_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) - + return actionsList def _create_event_filters_node(self, event_filters, doc): @@ -181,23 +206,26 @@ class XMLSerializer(Serializer): """ eventFiltersList = doc.createElement("EventFiltersList") for event_f in event_filters: - eventFilterNode = eventFiltersList.appendChild("EventFilter") + eventFilterNode = doc.createElement("EventFilter") + eventFiltersList.appendChild(eventFilterNode) - # Using .__class__ since type() doesn't have the same behavior + # Write down just the name of the Action class as the Class + # property -- + # using .__class__ since type() doesn't have the same behavior # with class derivating from object and class that don't eventFilterNode.setAttribute("Class", str(event_f.__class__)) # Write the name of the next state eventFilterNode.setAttribute("NextState", event_f.next_state) - if type(event_f) is sugar.tutorius.filters.TimerEvent: + if type(event_f) is TimerEvent: eventFilterNode.setAttribute("Timeout_s", str(event_f._timeout)) - elif type(event_f) is sugar.tutorius.filters.GtkWidgetEventFilter: + 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 sugar.tutorius.filters.GtkWidgetTypeFilter: + 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) @@ -295,26 +323,24 @@ class XMLSerializer(Serializer): @param filters_elem An XML Element representing a list of event filters """ reformed_event_filters_list = [] - # item(0) because there is always only one tag in the xml file - # so states_elem should always contain only one element - event_filter_element_list = filters_elem.item(0).getElementsByTagName("EventFilter") + event_filter_element_list = filters_elem.getElementsByTagName("EventFilter") 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(sugar.tutorius.filters.TimerEvent): + 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(sugar.tutorius.filters.GtkWidgetEventFilter): + 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(sugar.tutorius.filters.GtkWidgetTypeFilter): + 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"): @@ -325,10 +351,57 @@ class XMLSerializer(Serializer): new_event_filter = GtkWidgetTypeFilter(next_state, object_id, strokes=strokes) if new_event_filter is not None: - reformed_event_filter.append(new_event_filter) + reformed_event_filters_list.append(new_event_filter) return reformed_event_filters_list + def _load_xml_action(self, action): + """ + Loads a single action from an Xml Action node. + + @param action The Action XML Node to transform + object + @return The Action object of the correct type according to the XML + description + """ + # TO ADD: an elif for each type of action + if action.getAttribute("Class") == str(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") == str(BubbleMessage): + message = action.getAttribute("Message") + positionX = int(action.getAttribute("PositionX")) + positionY = int(action.getAttribute("PositionY")) + position = [positionX, positionY] + tail_posX = action.getAttribute("Tail_posX") + tail_posY = action.getAttribute("Tail_posY") + tail_pos = [tail_posX, tail_posY] + return BubbleMessage(message,position,None,tail_pos) + elif action.getAttribute("Class") == str(WidgetIdentifyAction): + return WidgetIdentifyAction() + elif action.getAttribute("Class") == str(ChainAction): + # Load the subactions + subActionsList = self._load_xml_actions(action.getElementsByTagName("Actions")[0]) + return ChainAction(subActionsList) + elif action.getAttribute("Class") == str(DisableWidgetAction): + # Get the target + targetName = action.getAttribute("Target") + return DisableWidgetAction(targetName) + elif action.getAttribute("Class") == str(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") == str(ClickAction): + # Load the widget to click + widget = action.getAttribute("Widget") + + return ClickAction(widget) + def _load_xml_actions(self, actions_elem): """ Transforms an Actions element into a list of instanciated Action. @@ -336,48 +409,12 @@ class XMLSerializer(Serializer): @param actions_elem An XML Element representing a list of Actions """ reformed_actions_list = [] - # item(0) because there is always only one tag in the xml file - # so states_elem should always contain only one element - actions_element_list = actions_elem.item(0).getElementsByTagName("Action") + actions_element_list = actions_elem.getElementsByTagName("Action") for action in actions_element_list: - # TODO : elif for each type of action - if action.getAttribute("Class") == str(DialogMessage): - message = action.getAttribute("Message") - positionX = int(action.getAttribute("PositionX")) - positionY = int(action.getAttribute("PositionY")) - position = [positionX, positionY] - reformed_actions_list.append(DialogMessage(message,position)) - elif action.getAttribute("Class") == str(BubbleMessage): - message = action.getAttribute("Message") - positionX = int(action.getAttribute("PositionX")) - positionY = int(action.getAttribute("PositionY")) - position = [positionX, positionY] - tail_posX = action.getAttribute("Tail_posX") - tail_posY = action.getAttribute("Tail_posY") - tail_pos = [tail_posX, tail_posY] - reformed_actions_list.append(BubbleMessage(message,position,None,tail_pos)) - elif action.getAttribute("Class") == str(WidgetIdentifyAction): - reformed_actions_list.append(WidgetIdentifyAction()) - elif action.getAttribute("Class") == str(ChainAction): - # Load the subactions - subActionsList = _load_xml_actions(action.getElementsByTagName("Actions")) - reformed_actions_list.append(ChainAction(subActionsList)) - elif action.getAttribute("Class") == str(DisableWidgetAction): - # Get the target - targetName = action.getAttribute("Target") - reformed_actions_list.append(DisableWidgetAction(targetName)) - elif action.getAttribute("Class") == str(TypeTextAction): - # Get the widget and the text to type - widget = action.getAttribute("Widget") - text = action.getAttribute("Text") - - reformed_actions_list.append(TypeTextAction(widget, text)) - elif action.getAttribute("Class") == str(ClickAction): - # Load the widget to click - widget = action.getAttribute("Widget") - - reformed_actions_list.append(ClickAction(widget)) + new_action = self._load_xml_action(action) + + reformed_actions_list.append(new_action) return reformed_actions_list @@ -395,8 +432,10 @@ class XMLSerializer(Serializer): for state in states_element_list: stateName = state.getAttribute("Name") - actions_list = self._load_xml_actions(state.getElementsByTagName("Actions")) - event_filters_list = self._load_xml_event_filters(state.getElementsByTagName("EventFiltersList")) + # Using item 0 in the list because there is always only one + # Actions and EventFilterList element per State node. + actions_list = self._load_xml_actions(state.getElementsByTagName("Actions")[0]) + event_filters_list = self._load_xml_event_filters(state.getElementsByTagName("EventFiltersList")[0]) reformed_state_list.append(State(stateName, actions_list, event_filters_list)) return reformed_state_list @@ -425,12 +464,12 @@ class XMLSerializer(Serializer): fsm.add_state(state) # Load the actions on this FSM - actions = self._load_xml_actions(fsm_elem.getElementsByTagName("FSMActions")) + actions = self._load_xml_actions(fsm_elem.getElementsByTagName("FSMActions")[0]) for action in actions: fsm.add_action(action) # Load the event filters - events = self._load_xml_event_filters(fsm_elem.getElementsByTagName("EventFiltersList")) + events = self._load_xml_event_filters(fsm_elem.getElementsByTagName("EventFiltersList")[0]) for event in events: fsm.add_event_filter(event) -- cgit v0.9.1