student-teacher customization
[librarian.git] / librarian / pypdf.py
index 4cc4d1d..387f647 100644 (file)
@@ -10,12 +10,14 @@ with TeXML, then runs it by XeLaTeX.
 
 """
 from __future__ import with_statement
 
 """
 from __future__ import with_statement
+from copy import deepcopy
 import os
 import os.path
 import shutil
 from StringIO import StringIO
 from tempfile import mkdtemp, NamedTemporaryFile
 import re
 import os
 import os.path
 import shutil
 from StringIO import StringIO
 from tempfile import mkdtemp, NamedTemporaryFile
 import re
+import random
 from copy import deepcopy
 from subprocess import call, PIPE
 
 from copy import deepcopy
 from subprocess import call, PIPE
 
@@ -23,7 +25,7 @@ from Texml.processor import process
 from lxml import etree
 from lxml.etree import XMLSyntaxError, XSLTApplyError
 
 from lxml import etree
 from lxml.etree import XMLSyntaxError, XSLTApplyError
 
-from xmlutils import Xmill, tag, tagged, ifoption
+from xmlutils import Xmill, tag, tagged, ifoption, tag_open_close
 from librarian.dcparser import Person
 from librarian.parser import WLDocument
 from librarian import ParseError, DCNS, get_resource, IOFile, Format
 from librarian.dcparser import Person
 from librarian.parser import WLDocument
 from librarian import ParseError, DCNS, get_resource, IOFile, Format
@@ -49,15 +51,18 @@ def escape(really):
     return deco
 
 
     return deco
 
 
-def cmd(name, pass_text=False):
+def cmd(name, parms=None):
     def wrap(self, element):
     def wrap(self, element):
-        pre = u'<cmd name="%s">' % name
-
-        if pass_text:
-            pre += "<parm>%s</parm>" % element.text
-            return pre + '</cmd>'
-        else:
-            return pre, '</cmd>'
+        pre, post = tag_open_close('cmd', name=name)
+
+        if parms:
+            for parm in parms:
+                e = etree.Element("parm")
+                e.text = parm
+                pre += etree.tostring(e)
+        pre += "<parm>"
+        post = "</parm>" + post
+        return pre, post
     return wrap
 
 
     return wrap
 
 
@@ -74,7 +79,7 @@ class EduModule(Xmill):
 
         def swap_endlines(txt):
             if self.options['strofa']:
 
         def swap_endlines(txt):
             if self.options['strofa']:
-                txt = txt.replace("/\n", '<ctrl ch="\"/>')
+                txt = txt.replace("/\n", '<ctrl ch="\\"/>')
             return txt
         self.register_text_filter(functions.substitute_entities)
         self.register_text_filter(mark_alien_characters)
             return txt
         self.register_text_filter(functions.substitute_entities)
         self.register_text_filter(mark_alien_characters)
@@ -189,7 +194,7 @@ class EduModule(Xmill):
     handle_wyroznienie = \
     handle_texcommand
 
     handle_wyroznienie = \
     handle_texcommand
 
-    _handle_strofa = cmd("strofa", True)
+    _handle_strofa = cmd("strofa")
 
     def handle_strofa(self, element):
         self.options = {'strofa': True}
 
     def handle_strofa(self, element):
         self.options = {'strofa': True}
@@ -250,6 +255,8 @@ class EduModule(Xmill):
         return
 
     def handle_lista(self, element, attrs={}):
         return
 
     def handle_lista(self, element, attrs={}):
+        if not element.findall("punkt"):
+            return None
         ltype = element.attrib.get('typ', 'punkt')
         if ltype == 'slowniczek':
             surl = element.attrib.get('href', None)
         ltype = element.attrib.get('typ', 'punkt')
         if ltype == 'slowniczek':
             surl = element.attrib.get('href', None)
@@ -271,16 +278,19 @@ class EduModule(Xmill):
 
     def handle_cwiczenie(self, element):
         exercise_handlers = {
 
     def handle_cwiczenie(self, element):
         exercise_handlers = {
-            'wybor': Wybor}
-            # 'uporzadkuj': Uporzadkuj,
-            # 'luki': Luki,
-            # 'zastap': Zastap,
-            # 'przyporzadkuj': Przyporzadkuj,
-            # 'prawdafalsz': PrawdaFalsz
+            'wybor': Wybor,
+            'uporzadkuj': Uporzadkuj,
+            'luki': Luki,
+            'zastap': Zastap,
+            'przyporzadkuj': Przyporzadkuj,
+            'prawdafalsz': PrawdaFalsz
+        }
 
         typ = element.attrib['typ']
 
         typ = element.attrib['typ']
+        self.exercise_counter += 1
         if not typ in exercise_handlers:
             return '(no handler)'
         if not typ in exercise_handlers:
             return '(no handler)'
+        self.options = {'exercise_counter': self.exercise_counter}
         handler = exercise_handlers[typ](self.options)
         return handler.generate(element)
 
         handler = exercise_handlers[typ](self.options)
         return handler.generate(element)
 
@@ -322,7 +332,7 @@ class EduModule(Xmill):
                 #        else: frames_c = ""
                 #        return u"""<table class="%s">""" % frames_c, u"</table>"
         return u'''
                 #        else: frames_c = ""
                 #        return u"""<table class="%s">""" % frames_c, u"</table>"
         return u'''
-<cmd name="begin"><parm>tabular</parm><opt>%s</opt></cmd>
+<cmd name="begin"><parm>tabular</parm><parm>%s</parm></cmd>
     ''' % ('l' * max_col), \
     u'''<cmd name="end"><parm>tabular</parm></cmd>'''
 
     ''' % ('l' * max_col), \
     u'''<cmd name="end"><parm>tabular</parm></cmd>'''
 
@@ -333,10 +343,14 @@ class EduModule(Xmill):
     @escape(1)
     def handle_kol(self, element):
         if element.getnext() is not None:
     @escape(1)
     def handle_kol(self, element):
         if element.getnext() is not None:
-            return u"", u'<spec cat="align">'
+            return u"", u'<spec cat="align" />'
         return u"", u""
 
         return u"", u""
 
-    handle_link = cmd('em', True)
+    def handle_link(self, element):
+        if element.attrib.get('url'):
+            return cmd('href', parms=[element.attrib['url']])(self, element)
+        else:
+            return cmd('em')(self, element)
 
 
 class Exercise(EduModule):
 
 
 class Exercise(EduModule):
@@ -344,14 +358,22 @@ class Exercise(EduModule):
         self.question_counter = 0
         super(Exercise, self).__init__(*args, **kw)
 
         self.question_counter = 0
         super(Exercise, self).__init__(*args, **kw)
 
-    handle_rozw_kom = ifoption(teacher=True)(cmd('akap', True))
+    handle_rozw_kom = ifoption(teacher=True)(cmd('akap'))
 
     def handle_cwiczenie(self, element):
 
     def handle_cwiczenie(self, element):
-        self.options = {'exercise': element.attrib['typ']}
+        self.options = {
+            'exercise': element.attrib['typ'],
+            'sub_gen': True,
+        }
         self.question_counter = 0
         self.piece_counter = 0
 
         self.question_counter = 0
         self.piece_counter = 0
 
-        pre = u""
+        header = etree.Element("parm")
+        header_cmd = etree.Element("cmd", name="naglowekpodrozdzial")
+        header_cmd.append(header)
+        header.text = u"Zadanie %d." % self.options['exercise_counter']
+
+        pre = etree.tostring(header_cmd, encoding=unicode)
         post = u""
         # Add a single <pytanie> tag if it's not there
         if not element.xpath(".//pytanie"):
         post = u""
         # Add a single <pytanie> tag if it's not there
         if not element.xpath(".//pytanie"):
@@ -363,29 +385,37 @@ class Exercise(EduModule):
     def handle_pytanie(self, element):
         """This will handle <cwiczenie> element, when there is no <pytanie>
         """
     def handle_pytanie(self, element):
         """This will handle <cwiczenie> element, when there is no <pytanie>
         """
-        opts = {}
         self.question_counter += 1
         self.piece_counter = 0
         self.question_counter += 1
         self.piece_counter = 0
-        solution = element.attrib.get('rozw', None)
-        if solution:
-            opts['solution'] = solution
+        pre = post = u""
+        if self.options['teacher'] and element.attrib.get('rozw'):
+            post += u" [rozwiązanie: %s]" % element.attrib.get('rozw')
+        return pre, post
 
 
-        handles = element.attrib.get('uchwyty', None)
-        if handles:
-            opts['handles'] = handles
+    def handle_punkt(self, element):
+        pre, post = super(Exercise, self).handle_punkt(element)
+        if self.options['teacher'] and element.attrib.get('rozw'):
+            post += u" [rozwiązanie: %s]" % element.attrib.get('rozw')
+        return pre, post
 
 
-        minimum = element.attrib.get('min', None)
-        if minimum:
-            opts['minimum'] = minimum
+    def solution_header(self):
+        par = etree.Element("cmd", name="par")
+        parm = etree.Element("parm")
+        parm.text = u"Rozwiązanie:"
+        par.append(parm)
+        return etree.tostring(par)
 
 
-        if opts:
-            self.options = opts
-        return u"", u""
+    def explicit_solution(self):
+        if self.options['solution']:
+            par = etree.Element("cmd", name="par")
+            parm = etree.Element("parm")
+            parm.text = self.options['solution']
+            par.append(parm)
+            return self.solution_header() + etree.tostring(par)
 
 
 
 
-class Wybor(Exercise):
-    INSTRUCTION = None
 
 
+class Wybor(Exercise):
     def handle_cwiczenie(self, element):
         pre, post = super(Wybor, self).handle_cwiczenie(element)
         is_single_choice = True
     def handle_cwiczenie(self, element):
         pre, post = super(Wybor, self).handle_cwiczenie(element)
         is_single_choice = True
@@ -415,6 +445,89 @@ class Wybor(Exercise):
             return super(Wybor, self).handle_punkt(element)
 
 
             return super(Wybor, self).handle_punkt(element)
 
 
+class Uporzadkuj(Exercise):
+    def handle_pytanie(self, element):
+        order_items = element.xpath(".//punkt/@rozw")
+        return super(Uporzadkuj, self).handle_pytanie(element)
+
+
+class Przyporzadkuj(Exercise):
+    def handle_lista(self, lista):
+        header = etree.Element("parm")
+        header_cmd = etree.Element("cmd", name="par")
+        header_cmd.append(header)
+        if 'nazwa' in lista.attrib:
+            header.text = u"Kategorie:"
+        elif 'cel' in lista.attrib:
+            header.text = u"Elementy do przyporządkowania:"
+        else:
+            header.text = u"Lista:"
+        pre, post = super(Przyporzadkuj, self).handle_lista(lista)
+        pre = etree.tostring(header_cmd, encoding=unicode) + pre
+        return pre, post
+
+
+class Luki(Exercise):
+    def find_pieces(self, question):
+        return question.xpath(".//luka")
+
+    def solution(self, piece):
+        piece = deepcopy(piece)
+        piece.tail = None
+        sub = EduModule()
+        return sub.generate(piece)
+
+    def handle_pytanie(self, element):
+        qpre, qpost = super(Luki, self).handle_pytanie(element)
+
+        luki = self.find_pieces(element)
+        random.shuffle(luki)
+        self.words = u"<env name='itemize'>%s</env>" % (
+            "".join("<cmd name='item'/>%s" % self.solution(luka) for luka in luki)
+        )
+        return qpre, qpost
+
+    def handle_opis(self, element):
+        return '', self.words
+
+    def handle_luka(self, element):
+        luka = "_" * 10
+        if self.options['teacher']:
+            piece = deepcopy(element)
+            piece.tail = None
+            sub = EduModule()
+            text = sub.generate(piece)
+            luka += u" [rozwiązanie: %s]" % text
+        return luka
+
+
+class Zastap(Luki):
+    def find_pieces(self, question):
+        return question.xpath(".//zastap")
+
+    def solution(self, piece):
+        return piece.attrib['rozw']
+
+    def list_header(self):
+        return u"Elementy do wstawienia"
+
+    def handle_zastap(self, element):
+        piece = deepcopy(element)
+        piece.tail = None
+        sub = EduModule()
+        text = sub.generate(piece)
+        if self.options['teacher'] and element.attrib.get('rozw'):
+            text += u" [rozwiązanie: %s]" % element.attrib.get('rozw')
+        return text
+
+
+class PrawdaFalsz(Exercise):
+    def handle_punkt(self, element):
+        pre, post = super(PrawdaFalsz, self).handle_punkt(element)
+        if 'rozw' in element.attrib:
+            post += u" [Prawda/Fałsz]"
+        return pre, post
+
 
 
 def fix_lists(tree):
 
 
 def fix_lists(tree):
@@ -435,7 +548,7 @@ def fix_lists(tree):
 
 class EduModulePDFFormat(PDFFormat):
     def get_texml(self):
 
 class EduModulePDFFormat(PDFFormat):
     def get_texml(self):
-        edumod = EduModule()
+        edumod = EduModule({"teacher": self.customization.get('teacher')})
         texml = edumod.generate(fix_lists(self.wldoc.edoc.getroot())).encode('utf-8')
 
         open("/tmp/texml.xml", "w").write(texml)
         texml = edumod.generate(fix_lists(self.wldoc.edoc.getroot())).encode('utf-8')
 
         open("/tmp/texml.xml", "w").write(texml)