backport 3.5
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 02 Sep 2009 10:24:15 +0200
changeset 3085 b415bca9a9ed
parent 3083 3084bc9ccc64 (current diff)
parent 3084 096d680c9da2 (diff)
child 3086 94ed8f0f0d14
backport 3.5
server/session.py
web/views/basetemplates.py
web/views/editforms.py
web/views/treeview.py
web/xhtml2fo.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ext/xhtml2fo.py	Wed Sep 02 10:24:15 2009 +0200
@@ -0,0 +1,142 @@
+from cubicweb.utils import can_do_pdf_conversion
+assert can_do_pdf_conversion()
+
+from xml.etree.ElementTree import QName, fromstring
+from pysixt.standard.xhtml_xslfo.transformer import XHTML2FOTransformer
+from pysixt.utils.xslfo.standard import cm
+from pysixt.utils.xslfo import SimplePageMaster
+from pysixt.standard.xhtml_xslfo.default_styling import default_styles
+from pysixt.standard.xhtml_xslfo import XHTML_NS
+
+
+class ReportTransformer(XHTML2FOTransformer):
+    """
+    Class transforming an XHTML input tree into a FO document
+    displaying reports (one report for each <div class="contentmain">
+    element in the input tree.
+    """
+
+    def __init__(self, section,
+                 page_width=21.0, page_height=29.7,
+                 margin_top=1.0, margin_bottom=1.0,
+                 margin_left=1.0, margin_right=1.0,
+                 header_footer_height=0.75,
+                 standard_font_size=11.0, default_lang=u"fr" ):
+        """
+        Initializes a transformer turning an XHTML input tree
+        containing <div class="contentmain"> elements representing
+        main content sections into a FO output tree displaying the
+        reports.
+
+        page_width: float - width of the page (in cm)
+        page_height: float - height of the page (in cm)
+        margin_top: float - top margin of the page (in cm)
+        margin_bottom: float - bottom margin of the page (in cm)
+        margin_left: float - left margin of the page (in cm)
+        margin_right: float - right margin of the page (in cm)
+        header_footer_height: float - height of the header or the footer of the
+                              page that the page number (if any) will be
+                              inserted in.
+        standard_font_size: float - standard size of the font (in pt)
+        default_lang: u"" - default language (used for hyphenation)
+        """
+        self.section = section
+        self.page_width = page_width
+        self.page_height = page_height
+
+        self.page_tmargin = margin_top
+        self.page_bmargin = margin_bottom
+        self.page_lmargin = margin_left
+        self.page_rmargin = margin_right
+
+        self.hf_height = header_footer_height
+
+        self.font_size = standard_font_size
+        self.lang = default_lang
+
+        XHTML2FOTransformer.__init__(self)
+
+
+    def define_pagemasters(self):
+        """
+        Defines the page masters for the FO output document.
+        """
+        pm = SimplePageMaster(u"page-report")
+        pm.set_page_dims( self.page_width*cm, self.page_height*cm )
+        pm.set_page_margins({u'top'   : self.page_tmargin*cm,
+                             u'bottom': self.page_bmargin*cm,
+                             u'left'  : self.page_lmargin*cm,
+                             u'right' : self.page_rmargin*cm })
+        pm.add_peripheral_region(u"end",self.hf_height)
+        dims = {}
+        dims[u"bottom"] = self.hf_height + 0.25
+        pm.set_main_region_margins(dims)
+        return [pm]
+
+    def _visit_report(self, in_elt, _out_elt, params):
+        """
+        Specific visit function for the input <div> elements whose class is
+        "report". The _root_visit method of this class selects these input
+        elements and asks the process of these elements with this specific
+        visit function.
+        """
+
+        ps = self.create_pagesequence(u"page-report")
+        props = { u"force-page-count": u"no-force",
+                  u"initial-page-number": u"1",
+                  u"format": u"1", }
+        self._output_properties(ps,props)
+
+        sc = self.create_staticcontent(ps, u"end")
+        sc_bl = self.create_block(sc)
+        attrs = { u"hyphenate": u"false", }
+        attrs[u"font-size"] = u"%.1fpt" %(self.font_size*0.7)
+        attrs[u"language"] = self.lang
+        attrs[u"text-align"] = u"center"
+        self._output_properties(sc_bl,attrs)
+        sc_bl.text = u"Page" + u" " # ### Should be localised!
+        pn = self.create_pagenumber(sc_bl)
+        pn.tail = u"/"
+        lpn = self.create_pagenumbercitation( sc_bl,
+                                              u"last-block-of-report-%d" % params[u"context_pos"]
+                                              )
+
+
+        fl = self.create_flow(ps,u"body")
+        bl = self.create_block(fl)
+
+        # Sets on the highest block element the properties of the XHTML body
+        # element. These properties (at the least the inheritable ones) will
+        # be inherited by all the future FO elements.
+        bodies = list(self.in_tree.getiterator(QName(XHTML_NS,u"body")))
+        if len(bodies) > 0:
+            attrs = self._extract_properties([bodies[0]])
+        else:
+            attrs = default_styles[u"body"].copy()
+        attrs[u"font-size"] = u"%.1fpt" %self.font_size
+        attrs[u"language"] = self.lang
+        self._output_properties(bl,attrs)
+
+        # Processes the report content
+        self._copy_text(in_elt,bl)
+        self._process_nodes(in_elt.getchildren(),bl)
+
+        # Inserts an empty block at the end of the report in order to be able
+        # to compute the last page number of this report.
+        last_bl = self.create_block(bl)
+        props = { u"keep-with-previous": u"always", }
+        props[u"id"] = u"last-block-of-report-%d" % params[u"context_pos"]
+        self._output_properties(last_bl,props)
+
+
+    def _root_visit(self):
+        """
+        Visit function called when starting the process of the input tree.
+        """
+        content = [ d for d in self.in_tree.getiterator(QName(XHTML_NS,u"div"))
+                    if d.get(u"id") == self.section ]
+        # Asks the process of the report elements with a specific visit
+        # function
+        self._process_nodes(content, self.fo_root,
+                            with_function=self._visit_report)
+
--- a/server/session.py	Wed Sep 02 10:22:47 2009 +0200
+++ b/server/session.py	Wed Sep 02 10:24:15 2009 +0200
@@ -153,8 +153,11 @@
                 if row[0] == targeteid:
                     break
             else:
-                raise Exception('cache inconsistency for %s %s %s %s' %
-                                (eid, rtype, role, targeteid))
+                # this may occurs if the cache has been filed by a hook
+                # after the database update
+                self.debug('cache inconsistency for %s %s %s %s', eid, rtype,
+                           role, targeteid)
+                return
             del rset.rows[idx]
             if isinstance(rset.description, list): # else description not set
                 del rset.description[idx]
--- a/web/data/cubicweb.ajax.js	Wed Sep 02 10:22:47 2009 +0200
+++ b/web/data/cubicweb.ajax.js	Wed Sep 02 10:24:15 2009 +0200
@@ -63,7 +63,12 @@
 	roundedCorners(node);
     }
     loadDynamicFragments(node);
-    jQuery(CubicWeb).trigger('ajax-loaded');
+    // XXX simulates document.ready, but the former
+    // only runs once, this one potentially many times
+    // we probably need to unbind the fired events
+    // When this is done, jquery.treeview.js (for instance)
+    // can be unpatched.
+  jQuery(CubicWeb).trigger('ajax-loaded');
 }
 
 /* cubicweb loadxhtml plugin to make jquery handle xhtml response
@@ -390,9 +395,10 @@
 /* convenience function that returns a DOM node based on req's result. */
 function getDomFromResponse(response) {
     if (typeof(response) == 'string') {
-	return html2dom(response);
+	var doc = html2dom(response);
+    } else {
+        var doc = response.documentElement;
     }
-    var doc = response.documentElement;
     var children = doc.childNodes;
     if (!children.length) {
 	// no child (error cases) => return the whole document
--- a/web/data/cubicweb.widgets.js	Wed Sep 02 10:22:47 2009 +0200
+++ b/web/data/cubicweb.widgets.js	Wed Sep 02 10:24:15 2009 +0200
@@ -181,13 +181,6 @@
     }
 }
 
-Widgets.TreeView = defclass("TreeView", null, {
-    __init__: function(wdgnode) {
-	jQuery(wdgnode).treeview({toggle: toggleTree,
-				  prerendered: true});
-    }
-});
-
 
 /* widget based on SIMILE's timeline widget
  * http://code.google.com/p/simile-widgets/
--- a/web/data/jquery.treeview.js	Wed Sep 02 10:22:47 2009 +0200
+++ b/web/data/jquery.treeview.js	Wed Sep 02 10:24:15 2009 +0200
@@ -1,6 +1,6 @@
 /*
  * Treeview 1.4 - jQuery plugin to hide and show branches of a tree
- * 
+ *
  * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
  * http://docs.jquery.com/Plugins/Treeview
  *
@@ -11,5 +11,6 @@
  *   http://www.gnu.org/licenses/gpl.html
  *
  * Revision: $Id: jquery.treeview.js 4684 2008-02-07 19:08:06Z joern.zaefferer $
+ * updated by Aurelien Campeas, 2009-09-01, to handle top-level ajax loads
  *
- */;(function($){$.extend($.fn,{swapClass:function(c1,c2){var c1Elements=this.filter('.'+c1);this.filter('.'+c2).removeClass(c2).addClass(c1);c1Elements.removeClass(c1).addClass(c2);return this;},replaceClass:function(c1,c2){return this.filter('.'+c1).removeClass(c1).addClass(c2).end();},hoverClass:function(className){className=className||"hover";return this.hover(function(){$(this).addClass(className);},function(){$(this).removeClass(className);});},heightToggle:function(animated,callback){animated?this.animate({height:"toggle"},animated,callback):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();if(callback)callback.apply(this,arguments);});},heightHide:function(animated,callback){if(animated){this.animate({height:"hide"},animated,callback);}else{this.hide();if(callback)this.each(callback);}},prepareBranches:function(settings){if(!settings.prerendered){this.filter(":last-child:not(ul)").addClass(CLASSES.last);this.filter((settings.collapsed?"":"."+CLASSES.closed)+":not(."+CLASSES.open+")").find(">ul").hide();}return this.filter(":has(>ul)");},applyClasses:function(settings,toggler){this.filter(":has(>ul):not(:has(>a))").find(">span").click(function(event){toggler.apply($(this).next());}).add($("a",this)).hoverClass();if(!settings.prerendered){this.filter(":has(>ul:hidden)").addClass(CLASSES.expandable).replaceClass(CLASSES.last,CLASSES.lastExpandable);this.not(":has(>ul:hidden)").addClass(CLASSES.collapsable).replaceClass(CLASSES.last,CLASSES.lastCollapsable);this.prepend("<div class=\""+CLASSES.hitarea+"\"/>").find("div."+CLASSES.hitarea).each(function(){var classes="";$.each($(this).parent().attr("class").split(" "),function(){classes+=this+"-hitarea ";});$(this).addClass(classes);});}this.find("div."+CLASSES.hitarea).click(toggler);},treeview:function(settings){settings=$.extend({cookieId:"treeview"},settings);if(settings.add){return this.trigger("add",[settings.add]);}if(settings.toggle){var callback=settings.toggle;settings.toggle=function(){return callback.apply($(this).parent()[0],arguments);};}function treeController(tree,control){function handler(filter){return function(){toggler.apply($("div."+CLASSES.hitarea,tree).filter(function(){return filter?$(this).parent("."+filter).length:true;}));return false;};}$("a:eq(0)",control).click(handler(CLASSES.collapsable));$("a:eq(1)",control).click(handler(CLASSES.expandable));$("a:eq(2)",control).click(handler());}function toggler(){$(this).parent().find(">.hitarea").swapClass(CLASSES.collapsableHitarea,CLASSES.expandableHitarea).swapClass(CLASSES.lastCollapsableHitarea,CLASSES.lastExpandableHitarea).end().swapClass(CLASSES.collapsable,CLASSES.expandable).swapClass(CLASSES.lastCollapsable,CLASSES.lastExpandable).find(">ul").heightToggle(settings.animated,settings.toggle);if(settings.unique){$(this).parent().siblings().find(">.hitarea").replaceClass(CLASSES.collapsableHitarea,CLASSES.expandableHitarea).replaceClass(CLASSES.lastCollapsableHitarea,CLASSES.lastExpandableHitarea).end().replaceClass(CLASSES.collapsable,CLASSES.expandable).replaceClass(CLASSES.lastCollapsable,CLASSES.lastExpandable).find(">ul").heightHide(settings.animated,settings.toggle);}}function serialize(){function binary(arg){return arg?1:0;}var data=[];branches.each(function(i,e){data[i]=$(e).is(":has(>ul:visible)")?1:0;});$.cookie(settings.cookieId,data.join(""));}function deserialize(){var stored=$.cookie(settings.cookieId);if(stored){var data=stored.split("");branches.each(function(i,e){$(e).find(">ul")[parseInt(data[i])?"show":"hide"]();});}}this.addClass("treeview");var branches=this.find("li").prepareBranches(settings);switch(settings.persist){case"cookie":var toggleCallback=settings.toggle;settings.toggle=function(){serialize();if(toggleCallback){toggleCallback.apply(this,arguments);}};deserialize();break;case"location":var current=this.find("a").filter(function(){return this.href.toLowerCase()==location.href.toLowerCase();});if(current.length){current.addClass("selected").parents("ul, li").add(current.next()).show();}break;}branches.applyClasses(settings,toggler);if(settings.control){treeController(this,settings.control);$(settings.control).show();}return this.bind("add",function(event,branches){$(branches).prev().removeClass(CLASSES.last).removeClass(CLASSES.lastCollapsable).removeClass(CLASSES.lastExpandable).find(">.hitarea").removeClass(CLASSES.lastCollapsableHitarea).removeClass(CLASSES.lastExpandableHitarea);$(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings,toggler);});}});var CLASSES=$.fn.treeview.classes={open:"open",closed:"closed",expandable:"expandable",expandableHitarea:"expandable-hitarea",lastExpandableHitarea:"lastExpandable-hitarea",collapsable:"collapsable",collapsableHitarea:"collapsable-hitarea",lastCollapsableHitarea:"lastCollapsable-hitarea",lastCollapsable:"lastCollapsable",lastExpandable:"lastExpandable",last:"last",hitarea:"hitarea"};$.fn.Treeview=$.fn.treeview;})(jQuery);
\ No newline at end of file
+ */;(function($){$.extend($.fn,{swapClass:function(c1,c2){var c1Elements=this.filter('.'+c1);this.filter('.'+c2).removeClass(c2).addClass(c1);c1Elements.removeClass(c1).addClass(c2);return this;},replaceClass:function(c1,c2){return this.filter('.'+c1).removeClass(c1).addClass(c2).end();},hoverClass:function(className){className=className||"hover";return this.hover(function(){$(this).addClass(className);},function(){$(this).removeClass(className);});},heightToggle:function(animated,callback){animated?this.animate({height:"toggle"},animated,callback):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();if(callback)callback.apply(this,arguments);});},heightHide:function(animated,callback){if(animated){this.animate({height:"hide"},animated,callback);}else{this.hide();if(callback)this.each(callback);}},prepareBranches:function(settings){if(!settings.prerendered){this.filter(":last-child:not(ul)").addClass(CLASSES.last);this.filter((settings.collapsed?"":"."+CLASSES.closed)+":not(."+CLASSES.open+")").find(">ul").hide();}return this.filter(":has(>ul)");},applyClasses:function(settings,toggler){this.filter(":has(>ul):not(:has(>a))").find(">span").click(function(event){toggler.apply($(this).next());}).add($("a",this)).hoverClass();if(!settings.prerendered){this.filter(":has(>ul:hidden)").addClass(CLASSES.expandable).replaceClass(CLASSES.last,CLASSES.lastExpandable);this.not(":has(>ul:hidden)").addClass(CLASSES.collapsable).replaceClass(CLASSES.last,CLASSES.lastCollapsable);this.prepend("<div class=\""+CLASSES.hitarea+"\"/>").find("div."+CLASSES.hitarea).each(function(){var classes="";$.each($(this).parent().attr("class").split(" "),function(){classes+=this+"-hitarea ";});$(this).addClass(classes);});}this.find("div."+CLASSES.hitarea).click(toggler);},treeview:function(settings){if(this.attr('cubicweb:type')=='prepared-treeview'){return this;}this.attr('cubicweb:type','prepared-treeview');settings=$.extend({cookieId:"treeview"},settings);if(settings.add){return this.trigger("add",[settings.add]);}if(settings.toggle){var callback=settings.toggle;settings.toggle=function(){return callback.apply($(this).parent()[0],arguments);};}function treeController(tree,control){function handler(filter){return function(){toggler.apply($("div."+CLASSES.hitarea,tree).filter(function(){return filter?$(this).parent("."+filter).length:true;}));return false;};}$("a:eq(0)",control).click(handler(CLASSES.collapsable));$("a:eq(1)",control).click(handler(CLASSES.expandable));$("a:eq(2)",control).click(handler());}function toggler(){$(this).parent().find(">.hitarea").swapClass(CLASSES.collapsableHitarea,CLASSES.expandableHitarea).swapClass(CLASSES.lastCollapsableHitarea,CLASSES.lastExpandableHitarea).end().swapClass(CLASSES.collapsable,CLASSES.expandable).swapClass(CLASSES.lastCollapsable,CLASSES.lastExpandable).find(">ul").heightToggle(settings.animated,settings.toggle);if(settings.unique){$(this).parent().siblings().find(">.hitarea").replaceClass(CLASSES.collapsableHitarea,CLASSES.expandableHitarea).replaceClass(CLASSES.lastCollapsableHitarea,CLASSES.lastExpandableHitarea).end().replaceClass(CLASSES.collapsable,CLASSES.expandable).replaceClass(CLASSES.lastCollapsable,CLASSES.lastExpandable).find(">ul").heightHide(settings.animated,settings.toggle);}}function serialize(){function binary(arg){return arg?1:0;}var data=[];branches.each(function(i,e){data[i]=$(e).is(":has(>ul:visible)")?1:0;});$.cookie(settings.cookieId,data.join(""));}function deserialize(){var stored=$.cookie(settings.cookieId);if(stored){var data=stored.split("");branches.each(function(i,e){$(e).find(">ul")[parseInt(data[i])?"show":"hide"]();});}}this.addClass("treeview");var branches=this.find("li").prepareBranches(settings);switch(settings.persist){case"cookie":var toggleCallback=settings.toggle;settings.toggle=function(){serialize();if(toggleCallback){toggleCallback.apply(this,arguments);}};deserialize();break;case"location":var current=this.find("a").filter(function(){return this.href.toLowerCase()==location.href.toLowerCase();});if(current.length){current.addClass("selected").parents("ul, li").add(current.next()).show();}break;}branches.applyClasses(settings,toggler);if(settings.control){treeController(this,settings.control);$(settings.control).show();}return this.bind("add",function(event,branches){$(branches).prev().removeClass(CLASSES.last).removeClass(CLASSES.lastCollapsable).removeClass(CLASSES.lastExpandable).find(">.hitarea").removeClass(CLASSES.lastCollapsableHitarea).removeClass(CLASSES.lastExpandableHitarea);$(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings,toggler);});}});var CLASSES=$.fn.treeview.classes={open:"open",closed:"closed",expandable:"expandable",expandableHitarea:"expandable-hitarea",lastExpandableHitarea:"lastExpandable-hitarea",collapsable:"collapsable",collapsableHitarea:"collapsable-hitarea",lastCollapsableHitarea:"lastCollapsable-hitarea",lastCollapsable:"lastCollapsable",lastExpandable:"lastExpandable",last:"last",hitarea:"hitarea"};$.fn.Treeview=$.fn.treeview;})(jQuery);
\ No newline at end of file
--- a/web/test/unittest_pdf.py	Wed Sep 02 10:22:47 2009 +0200
+++ b/web/test/unittest_pdf.py	Wed Sep 02 10:24:15 2009 +0200
@@ -7,7 +7,7 @@
 
 from cubicweb.utils import can_do_pdf_conversion
 
-from cubicweb.web.xhtml2fo import ReportTransformer
+from cubicweb.ext.xhtml2fo import ReportTransformer
 
 DATADIR = osp.join(osp.dirname(__file__), 'data')
 
--- a/web/views/basetemplates.py	Wed Sep 02 10:22:47 2009 +0200
+++ b/web/views/basetemplates.py	Wed Sep 02 10:24:15 2009 +0200
@@ -270,7 +270,7 @@
     from subprocess import Popen as sub
     from StringIO import StringIO
     from tempfile import NamedTemporaryFile
-    from cubicweb.web.xhtml2fo import ReportTransformer
+    from cubicweb.ext.xhtml2fo import ReportTransformer
 
     class PdfMainTemplate(TheMainTemplate):
         id = 'pdf-main-template'
@@ -279,7 +279,8 @@
             """build the standard view, then when it's all done, convert xhtml to pdf
             """
             super(PdfMainTemplate, self).call(view)
-            pdf = self.to_pdf(self._stream)
+            section = self.req.form.pop('section', 'contentmain')
+            pdf = self.to_pdf(self._stream, section)
             self.req.set_content_type('application/pdf', filename='report.pdf')
             self.binary = True
             self.w = None
@@ -287,7 +288,7 @@
             # pylint needs help
             self.w(pdf)
 
-        def to_pdf(self, stream, section='contentmain'):
+        def to_pdf(self, stream, section):
             # XXX see ticket/345282
             stream = stream.getvalue().replace('&nbsp;', '&#160;').encode('utf-8')
             xmltree = ElementTree()
--- a/web/views/boxes.py	Wed Sep 02 10:22:47 2009 +0200
+++ b/web/views/boxes.py	Wed Sep 02 10:24:15 2009 +0200
@@ -140,10 +140,13 @@
             for tr in entity.possible_transitions():
                 url = entity.absolute_url(vid='statuschange', treid=tr.eid)
                 menu_items.append(self.mk_action(_(tr.name), url))
-            wfurl = self.build_url('cwetype/%s'%entity.e_schema, vid='workflow')
-            menu_items.append(self.mk_action(_('view workflow'), wfurl))
-            wfurl = entity.absolute_url(vid='wfhistory')
-            menu_items.append(self.mk_action(_('view history'), wfurl))
+            # don't propose to see wf if user can't pass any transition
+            if menu_items:
+                wfurl = self.build_url('cwetype/%s'%entity.e_schema, vid='workflow')
+                menu_items.append(self.mk_action(_('view workflow'), wfurl))
+            if entity.workflow_history:
+                wfurl = entity.absolute_url(vid='wfhistory')
+                menu_items.append(self.mk_action(_('view history'), wfurl))
             box.append(BoxMenu(menu_title, menu_items))
         return None
 
--- a/web/views/editforms.py	Wed Sep 02 10:22:47 2009 +0200
+++ b/web/views/editforms.py	Wed Sep 02 10:24:15 2009 +0200
@@ -20,7 +20,8 @@
 from cubicweb.utils import make_uid
 from cubicweb.view import EntityView
 from cubicweb.common import tags
-from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, eid_param, uicfg
+from cubicweb.web import INTERNAL_FIELD_VALUE, RequestError, stdmsgs, eid_param
+from cubicweb.web import uicfg
 from cubicweb.web.form import FormViewMixIn, FieldNotFound
 from cubicweb.web.formfields import guess_field
 from cubicweb.web.formwidgets import Button, SubmitButton, ResetButton
@@ -327,13 +328,13 @@
         """creation view for an entity"""
         etype = kwargs.pop('etype', self.req.form.get('etype'))
         try:
-            entity = self.vreg['etypes'].etype_class(etype)(self.req)
-        except:
-            self.w(self.req._('no such entity type %s') % etype)
-        else:
-            self.initialize_varmaker()
-            entity.eid = self.varmaker.next()
-            self.render_form(entity)
+            etype = self.vreg.case_insensitive_etypes[etype.lower()]
+        except KeyError:
+            raise RequestError(self.req._('no such entity type %s') % etype)
+        entity = self.vreg['etypes'].etype_class(etype)(self.req)
+        self.initialize_varmaker()
+        entity.eid = self.varmaker.next()
+        self.render_form(entity)
 
     def form_title(self, entity):
         """the form view title"""
--- a/web/views/treeview.py	Wed Sep 02 10:22:47 2009 +0200
+++ b/web/views/treeview.py	Wed Sep 02 10:24:15 2009 +0200
@@ -32,17 +32,22 @@
             if treeid is None:
                 self.warning('Tree state won\'t be properly restored after next reload')
                 treeid = make_uid('throw away uid')
-        self.w(u'<ul id="tree-%s" class="%s">' % (treeid, self.css_classes))
+        toplevel_thru_ajax = self.req.form.pop('treeview_top', False)
+        toplevel = toplevel_thru_ajax or (initial_load and not self.req.form.get('fname'))
+        ulid = ' '
+        if toplevel:
+            ulid = ' id="tree-%s"' % treeid
+        self.w(u'<ul%s class="%s">' % (ulid, self.css_classes))
         for rowidx in xrange(len(self.rset)):
             self.wview(self.itemvid, self.rset, row=rowidx, col=0,
                        vid=subvid, parentvid=self.id, treeid=treeid)
         self.w(u'</ul>')
-        if initial_load and not self.req.form.get('fname'):
+        if toplevel:
             self.req.add_css('jquery.treeview.css')
             self.req.add_js(('cubicweb.ajax.js', 'cubicweb.widgets.js', 'jquery.treeview.js'))
             self.req.html_headers.add_onload(u"""
-jQuery("#tree-%s").treeview({toggle: toggleTree, prerendered: true});""" % treeid)
-
+jQuery("#tree-%s").treeview({toggle: toggleTree, prerendered: true});""" % treeid,
+                                             jsoncall=toplevel_thru_ajax)
 
 class FileTreeView(TreeView):
     """specific version of the treeview to display file trees
@@ -91,14 +96,15 @@
     (each item should be expandable if it's not a tree leaf)
     """
     id = 'treeitemview'
-    __select__ = EntityView.__select__ & implements(ITree) # XXX
+    default_branch_state_is_open = False
+    __select__ = EntityView.__select__ & implements(ITree)
 
     def open_state(self, eeid, treeid):
         cookies = self.req.get_cookie()
         treestate = cookies.get(treecookiename(treeid))
         if treestate:
             return str(eeid) in treestate.value.split(';')
-        return False
+        return self.default_branch_state_is_open
 
     def cell_call(self, row, col, treeid, vid='oneline', parentvid='treeview'):
         w = self.w
--- a/web/xhtml2fo.py	Wed Sep 02 10:22:47 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-from cubicweb.utils import can_do_pdf_conversion
-assert can_do_pdf_conversion()
-
-from xml.etree.ElementTree import QName, fromstring
-from pysixt.standard.xhtml_xslfo.transformer import XHTML2FOTransformer
-from pysixt.utils.xslfo.standard import cm
-from pysixt.utils.xslfo import SimplePageMaster
-from pysixt.standard.xhtml_xslfo.default_styling import default_styles
-from pysixt.standard.xhtml_xslfo import XHTML_NS
-
-
-class ReportTransformer(XHTML2FOTransformer):
-    """
-    Class transforming an XHTML input tree into a FO document
-    displaying reports (one report for each <div class="contentmain">
-    element in the input tree.
-    """
-
-    def __init__(self, section,
-                 page_width=21.0, page_height=29.7,
-                 margin_top=1.0, margin_bottom=1.0,
-                 margin_left=1.0, margin_right=1.0,
-                 header_footer_height=0.75,
-                 standard_font_size=11.0, default_lang=u"fr" ):
-        """
-        Initializes a transformer turning an XHTML input tree
-        containing <div class="contentmain"> elements representing
-        main content sections into a FO output tree displaying the
-        reports.
-
-        page_width: float - width of the page (in cm)
-        page_height: float - height of the page (in cm)
-        margin_top: float - top margin of the page (in cm)
-        margin_bottom: float - bottom margin of the page (in cm)
-        margin_left: float - left margin of the page (in cm)
-        margin_right: float - right margin of the page (in cm)
-        header_footer_height: float - height of the header or the footer of the
-                              page that the page number (if any) will be
-                              inserted in.
-        standard_font_size: float - standard size of the font (in pt)
-        default_lang: u"" - default language (used for hyphenation)
-        """
-        self.section = section
-        self.page_width = page_width
-        self.page_height = page_height
-
-        self.page_tmargin = margin_top
-        self.page_bmargin = margin_bottom
-        self.page_lmargin = margin_left
-        self.page_rmargin = margin_right
-
-        self.hf_height = header_footer_height
-
-        self.font_size = standard_font_size
-        self.lang = default_lang
-
-        XHTML2FOTransformer.__init__(self)
-
-
-    def define_pagemasters(self):
-        """
-        Defines the page masters for the FO output document.
-        """
-        pm = SimplePageMaster(u"page-report")
-        pm.set_page_dims( self.page_width*cm, self.page_height*cm )
-        pm.set_page_margins({u'top'   : self.page_tmargin*cm,
-                             u'bottom': self.page_bmargin*cm,
-                             u'left'  : self.page_lmargin*cm,
-                             u'right' : self.page_rmargin*cm })
-        pm.add_peripheral_region(u"end",self.hf_height)
-        dims = {}
-        dims[u"bottom"] = self.hf_height + 0.25
-        pm.set_main_region_margins(dims)
-        return [pm]
-
-    def _visit_report(self, in_elt, _out_elt, params):
-        """
-        Specific visit function for the input <div> elements whose class is
-        "report". The _root_visit method of this class selects these input
-        elements and asks the process of these elements with this specific
-        visit function.
-        """
-
-        ps = self.create_pagesequence(u"page-report")
-        props = { u"force-page-count": u"no-force",
-                  u"initial-page-number": u"1",
-                  u"format": u"1", }
-        self._output_properties(ps,props)
-
-        sc = self.create_staticcontent(ps, u"end")
-        sc_bl = self.create_block(sc)
-        attrs = { u"hyphenate": u"false", }
-        attrs[u"font-size"] = u"%.1fpt" %(self.font_size*0.7)
-        attrs[u"language"] = self.lang
-        attrs[u"text-align"] = u"center"
-        self._output_properties(sc_bl,attrs)
-        sc_bl.text = u"Page" + u" " # ### Should be localised!
-        pn = self.create_pagenumber(sc_bl)
-        pn.tail = u"/"
-        lpn = self.create_pagenumbercitation( sc_bl,
-                                              u"last-block-of-report-%d" % params[u"context_pos"]
-                                              )
-
-
-        fl = self.create_flow(ps,u"body")
-        bl = self.create_block(fl)
-
-        # Sets on the highest block element the properties of the XHTML body
-        # element. These properties (at the least the inheritable ones) will
-        # be inherited by all the future FO elements.
-        bodies = list(self.in_tree.getiterator(QName(XHTML_NS,u"body")))
-        if len(bodies) > 0:
-            attrs = self._extract_properties([bodies[0]])
-        else:
-            attrs = default_styles[u"body"].copy()
-        attrs[u"font-size"] = u"%.1fpt" %self.font_size
-        attrs[u"language"] = self.lang
-        self._output_properties(bl,attrs)
-
-        # Processes the report content
-        self._copy_text(in_elt,bl)
-        self._process_nodes(in_elt.getchildren(),bl)
-
-        # Inserts an empty block at the end of the report in order to be able
-        # to compute the last page number of this report.
-        last_bl = self.create_block(bl)
-        props = { u"keep-with-previous": u"always", }
-        props[u"id"] = u"last-block-of-report-%d" % params[u"context_pos"]
-        self._output_properties(last_bl,props)
-
-
-    def _root_visit(self):
-        """
-        Visit function called when starting the process of the input tree.
-        """
-        content = [ d for d in self.in_tree.getiterator(QName(XHTML_NS,u"div"))
-                    if d.get(u"id") == self.section ]
-        # Asks the process of the report elements with a specific visit
-        # function
-        self._process_nodes(content, self.fo_root,
-                            with_function=self._visit_report)
-