Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/sugar/activity/activity.py43
-rw-r--r--src/sugar/tutorius/Makefile.am5
-rw-r--r--src/sugar/tutorius/services.py1
-rw-r--r--src/sugar/tutorius/tests/serializertests.py121
-rw-r--r--src/sugar/tutorius/tutoserialize.py143
5 files changed, 302 insertions, 11 deletions
diff --git a/src/sugar/activity/activity.py b/src/sugar/activity/activity.py
index 21e38f6..3e2d3d4 100644
--- a/src/sugar/activity/activity.py
+++ b/src/sugar/activity/activity.py
@@ -77,6 +77,7 @@ from sugar.datastore import datastore
from sugar.session import XSMPClient
from sugar import wm
from sugar.tutorius.services import ObjectStore
+from sugar.tutorius.tutoserialize import TutoSerializer
_ = lambda msg: gettext.dgettext('sugar-toolkit', msg)
@@ -126,11 +127,21 @@ class ActivityToolbar(gtk.Toolbar):
if hasattr(self._activity,"get_tutorials") and hasattr(self._activity.get_tutorials,"__call__"):
self.tutorials = ToolComboBox(label_text=_('Tutorials:'))
self.tutorials.combo.connect('changed', self.__tutorial_changed_cb)
- tutorials = self._activity.get_tutorials()
+ # Get tutorial list by file
+ logging.debug("************************************ before creating serialize")
+ serialize = TutoSerializer()
+ logging.debug("************************************ before calling load_tuto_list()")
+
+ #tutorials = self._activity.get_tutorials()
+ if getattr(self._activity,"_tutorials",None) is None:
+ tutorials = serialize.load_tuto_list()
+
self._current_tutorial = None
if tutorials:
for key, tutorial in tutorials.items():
- self.tutorials.combo.append_item(key, tutorial.name)
+ # self.tutorials.combo.append_item(key, _(tutorial.name))
+ self.tutorials.combo.append_item(key, _(tutorial))
+
self.insert(self.tutorials, -1)
self.tutorials.show()
@@ -196,16 +207,34 @@ class ActivityToolbar(gtk.Toolbar):
"""
Callback for tutorial combobox item change
"""
- model = combo.get_model()
- it = combo.get_active_iter()
- (key, ) = model.get(it, 0)
- tutorial = self._activity.get_tutorials().get(key,None)
- if not tutorial is None:
+ logging.debug("************ function __tutorial_changed_cb called")
+ serialize = TutoSerializer()
+
+ if self._current_tutorial:
+ self._current_tutorial.detach()
+
+ model = self.tutorials.combo.get_model()
+ it = self.tutorials.combo.get_active_iter()
+ (key,) = model.get(it, 0)
+
+ #Load and build chosen tutorial from Pickle file
+ logging.debug("****************** before tuto build")
+## tutorials = self._activity.get_tutorials()
+ tuto = serialize.build_tutorial(key)
+ self._activity._tutorials = tuto
+ logging.debug("****************** after tuto build")
+## tutorial = self._activity.get_tutorials().get(key,None)
+ tutorial = tuto.get(key, None)
+
+ if not getattr(self._activity,"_tutorials",None) is None:
if not self._current_tutorial is None:
self._current_tutorial.detach()
+
self._current_tutorial = tutorial
+ logging.debug(" *************** try to attach tuto")
self._current_tutorial.attach(self._activity)
+
def __keep_clicked_cb(self, button):
self._activity.copy()
diff --git a/src/sugar/tutorius/Makefile.am b/src/sugar/tutorius/Makefile.am
index 02f832b..a74b796 100644
--- a/src/sugar/tutorius/Makefile.am
+++ b/src/sugar/tutorius/Makefile.am
@@ -1,5 +1,3 @@
-SUBDIRS = uam
-
sugardir = $(pythondir)/sugar/tutorius
sugar_PYTHON = \
__init__.py \
@@ -12,5 +10,4 @@ sugar_PYTHON = \
overlayer.py \
editor.py \
linear_creator.py \
- constraints.py \
- properties.py
+ bundler.py
diff --git a/src/sugar/tutorius/services.py b/src/sugar/tutorius/services.py
index 467eca0..9ed2e50 100644
--- a/src/sugar/tutorius/services.py
+++ b/src/sugar/tutorius/services.py
@@ -66,3 +66,4 @@ class ObjectStore(object):
tutorial = property(fset=set_tutorial,fget=get_tutorial,doc="tutorial")
__doc__ = __ObjectStore.__doc__
+
diff --git a/src/sugar/tutorius/tests/serializertests.py b/src/sugar/tutorius/tests/serializertests.py
new file mode 100644
index 0000000..7a31602
--- /dev/null
+++ b/src/sugar/tutorius/tests/serializertests.py
@@ -0,0 +1,121 @@
+# Copyright (C) 2009, Tutorius.org
+# Copyright (C) 2009, Jean-Christophe Savard <savard.jean.christophe@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
+"""
+Serialization Tests
+
+This module contains all the tests that pertain to the usage of the Tutorius
+Serializer object. This means testing saving a tutorial dictionary to a .tml
+file, loading the list of tutorials for this activity and building chosen
+tutorial.
+"""
+
+import unittest
+
+import logging
+import linecache
+import os
+import cPickle as pickle
+
+from sugar.tutorius import gtkutils, overlayer
+from sugar.tutorius.core import Tutorial, State, FiniteStateMachine
+from sugar.tutorius.actions import DialogMessage, OnceWrapper, BubbleMessage
+from sugar.tutorius.filters import GtkWidgetEventFilter, TimerEvent
+from sugar.tutorius.tutoserialize import TutoSerializer
+
+
+# Helper classes to help testing
+
+
+
+
+class SerializerTest(unittest.TestCase):
+ """
+ This class has to test the Serializer methods as well as the expected
+ functionality.
+ """
+
+ def test_pickle_integrity(self):
+ """
+ Validates content is uncorrupted trough a pickle file save/load.
+ """
+
+ # Sample valid FSM dict
+ sampleDict = {
+ "INIT":State("INIT",
+ action_list=[
+ OnceWrapper(BubbleMessage(message="Welcome to the text editor tutorial!\n\n Click on the canvas and type a letter.", pos=[100,100], tailpos=[-10,-20])),
+ ],
+ event_filter_list=[
+ GtkWidgetEventFilter("TEXT","0.0.0.1.0.0.0","key-press-event"),
+ TimerEvent("LOST",15),
+ ],
+ ),
+ "LOST":State("LOST",
+ action_list=[BubbleMessage("Click in the canvas and type on your keyboard", [400, 400]),],
+ event_filter_list=[
+ GtkWidgetEventFilter("TEXT","0.0.0.1.0.0.0","key-press-event"),
+ TimerEvent("INIT",5),
+ ],
+ ),
+ "TEXT":State("TEXT",
+ action_list=[OnceWrapper(BubbleMessage(" You can type more letters if you want!\n\n" +
+ "To proceed to the next step, select your text.\n\n Click and drag over the text!", [200,150])),],
+ event_filter_list=[
+ GtkWidgetEventFilter("SELECTED","0.0.0.1.0.0","text-selected"),
+ ],
+ ),
+ }
+
+ testpath = "/tmp/testdata/"
+
+ # Create testdata/ folder if no exists
+ if not os.path.exists(testpath):
+ os.mkdir(testpath)
+
+ serialize = TutoSerializer()
+
+ # Make the class believe the test is in a activity path
+ os.environ["SUGAR_ACTIVITY_ROOT"] = testpath
+
+ fsm = FiniteStateMachine("Test", state_dict=sampleDict)
+
+ serialize.save_tutorial("Test", "Test", fsm, "serializeTest")
+
+ fileDict = serialize.load_tuto_list()
+
+ for filekey, tutorial in fileDict.items():
+ if filekey == "Test":
+ reformedTuto = serialize.build_tutorial(filekey)
+
+ reformedfsm = reformedTuto.get("Test").state_machine
+
+ #Tests
+ assert reformedfsm._states.get("INIT").name == fsm._states.get("INIT").name, \
+ 'FSM underlying dictionary differ from original to pickled/reformed one'
+ assert reformedfsm._states.get("LOST").name == fsm._states.get("LOST").name, \
+ 'FSM underlying dictionary differ from original to pickled/reformed one'
+ assert reformedfsm._states.get("TEXT").name == fsm._states.get("TEXT").name, \
+ 'FSM underlying dictionary differ from original to pickled/reformed one'
+
+
+ os.remove(testpath + "serializeTest.tml")
+ os.rmdir(testpath)
+ os.rmdir("/tmp")
+
+
+if __name__ == "__main__":
+ unittest.main() \ No newline at end of file
diff --git a/src/sugar/tutorius/tutoserialize.py b/src/sugar/tutorius/tutoserialize.py
new file mode 100644
index 0000000..ebd17c6
--- /dev/null
+++ b/src/sugar/tutorius/tutoserialize.py
@@ -0,0 +1,143 @@
+# Copyright (C) 2009, Tutorius.org
+# Copyright (C) 2009, Jean-Christophe Savard <savard.jean.christophe@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
+
+
+"""
+-Save and load FSM Dictionnary to file in $SUGAR_ACTIVITY_ROOT/data/
+"""
+
+import logging
+import linecache
+import os
+import cPickle as pickle
+
+from sugar.tutorius import gtkutils, overlayer
+from sugar.tutorius.core import Tutorial, State, FiniteStateMachine
+from sugar.tutorius.actions import DialogMessage, OnceWrapper, BubbleMessage
+from sugar.tutorius.filters import GtkWidgetEventFilter, TimerEvent
+
+class TutoSerializer:
+ """
+ Serializer is a class that provide serializing and file reading and
+ writing to disk services for the FSM Dictionary used in the tutorials.
+ """
+ def __init__(self):
+ """
+ TutoSerializer constructor (empty)
+ """
+ pass
+
+
+ def load_tuto_list(self):
+ """
+ Load the tutorial key/name list for this activity from .tml files.
+ Return the key/name dictionary
+ """
+ # TODO : Temp path; decide how .tml files will be distrribued in file
+ # architecture
+
+ path = os.getenv("SUGAR_ACTIVITY_ROOT") + "/data/"
+ logging.debug("*********** Path of /data/ folder of activity : " + path)
+
+ # Create /data/ folder if no exists
+ if not os.path.exists(path):
+ os.mkdir(path)
+ logging.debug("************* Creating data folder")
+
+ tutoKeyName = {}
+
+ # iterate for each .tml file in the activity /data folder
+ for file_name in os.listdir(path):
+
+ if file_name.endswith(".tml"):
+ logging.debug("************** .tml file found : " + file_name)
+
+ # TODO : Filter for just current activity files
+ # (design convention and/or filter xxxxx.yyyyyy key ? )
+
+ # Get the key line (always 1st line of .tml file)
+ key_line = linecache.getline(path + file_name, 1)
+ key_line = key_line.split("\n")[0]
+ # Get the name line (always 2nd line of .tml file)
+ name_line = linecache.getline(path + file_name, 2)
+ name_line = name_line.split("\n")[0]
+ # Create dictionary
+ tutoKeyName[key_line.split("--KEY::")[1]] = \
+ name_line.split("--NAME::")[1]
+
+
+## tutoKeyName = {}
+## tutoKeyName["Writus.CopyPasteStyle"] = "Copy-paste and style"
+
+ return tutoKeyName
+
+ def build_tutorial(self,key):
+ """
+ Load the chosen dictionnary from Pickle file on disk, then build and
+ return the corresponding tutorial.
+ TODO : Decode pickle to prevent broswer corruption
+ """
+ path = os.getenv("SUGAR_ACTIVITY_ROOT") + "/data/"
+ logging.debug("************ Path of /data/ folder of activity : " \
+ + path)
+ logging.debug("************ User key = " + key)
+
+ # iterate for each .tml file in the activity /data folder
+ for file_name in os.listdir(path):
+
+ if file_name.endswith(".tml"):
+
+ logging.debug("************ found .tml file : " + file_name)
+ key_line = linecache.getline(path + file_name, 1)
+ key_line = key_line.split("\n")[0]
+ fileKey = key_line.split("--KEY::")[1]
+ logging.debug("************ fileKey = " + fileKey)
+ if key == fileKey:
+ logging.debug("************ Key : " + key + \
+ " = fileKey : " + fileKey)
+ tml = file(path + file_name, "r")
+ str = tml.read()
+ pick = str.split("--PICKLE::")[1]
+
+ fsm = pickle.loads(pick)
+ tuto = {key:Tutorial(key,fsm)}
+
+ return tuto
+
+
+ def save_tutorial(self, key, name, fsm, filename):
+ """
+ Save the dictionnary given in parameter to a filename.tml file with a
+ key and a name.
+
+ TODO : TEST : In developpement, untested.
+ TODO : Encode pickle to prevent broswer corruption
+ """
+
+ path = os.getenv("SUGAR_ACTIVITY_ROOT") + "/data/"
+ # Create /data/ folder if no exists
+ if not os.path.exists(path):
+ os.mkdir(path)
+ logging.debug("************* Creating data folder")
+
+ # Save the dictionnary to .tml file
+ tutoSave = file(path + filename + ".tml", 'w')
+ str = "--KEY::" + key + "\n--NAME::" + name + "\n--PICKLE::" + \
+ pickle.dumps(fsm,0)
+ tutoSave.write(str)
+ tutoSave.close()
+ \ No newline at end of file