Index: third_party/logilab/common/ureports/nodes.py |
diff --git a/third_party/logilab/common/ureports/nodes.py b/third_party/logilab/common/ureports/nodes.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d63b58284cd8b3d9dae38ff58ce7bdf9c2510409 |
--- /dev/null |
+++ b/third_party/logilab/common/ureports/nodes.py |
@@ -0,0 +1,201 @@ |
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
+# |
+# This file is part of logilab-common. |
+# |
+# logilab-common is free software: you can redistribute it and/or modify it under |
+# the terms of the GNU Lesser General Public License as published by the Free |
+# Software Foundation, either version 2.1 of the License, or (at your option) any |
+# later version. |
+# |
+# logilab-common 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 Lesser General Public License for more |
+# details. |
+# |
+# You should have received a copy of the GNU Lesser General Public License along |
+# with logilab-common. If not, see <http://www.gnu.org/licenses/>. |
+"""Micro reports objects. |
+ |
+A micro report is a tree of layout and content objects. |
+""" |
+__docformat__ = "restructuredtext en" |
+ |
+from logilab.common.tree import VNode |
+ |
+class BaseComponent(VNode): |
+ """base report component |
+ |
+ attributes |
+ * id : the component's optional id |
+ * klass : the component's optional klass |
+ """ |
+ def __init__(self, id=None, klass=None): |
+ VNode.__init__(self, id) |
+ self.klass = klass |
+ |
+class BaseLayout(BaseComponent): |
+ """base container node |
+ |
+ attributes |
+ * BaseComponent attributes |
+ * children : components in this table (i.e. the table's cells) |
+ """ |
+ def __init__(self, children=(), **kwargs): |
+ super(BaseLayout, self).__init__(**kwargs) |
+ for child in children: |
+ if isinstance(child, BaseComponent): |
+ self.append(child) |
+ else: |
+ self.add_text(child) |
+ |
+ def append(self, child): |
+ """overridden to detect problems easily""" |
+ assert child not in self.parents() |
+ VNode.append(self, child) |
+ |
+ def parents(self): |
+ """return the ancestor nodes""" |
+ assert self.parent is not self |
+ if self.parent is None: |
+ return [] |
+ return [self.parent] + self.parent.parents() |
+ |
+ def add_text(self, text): |
+ """shortcut to add text data""" |
+ self.children.append(Text(text)) |
+ |
+ |
+# non container nodes ######################################################### |
+ |
+class Text(BaseComponent): |
+ """a text portion |
+ |
+ attributes : |
+ * BaseComponent attributes |
+ * data : the text value as an encoded or unicode string |
+ """ |
+ def __init__(self, data, escaped=True, **kwargs): |
+ super(Text, self).__init__(**kwargs) |
+ #if isinstance(data, unicode): |
+ # data = data.encode('ascii') |
+ assert isinstance(data, (str, unicode)), data.__class__ |
+ self.escaped = escaped |
+ self.data = data |
+ |
+class VerbatimText(Text): |
+ """a verbatim text, display the raw data |
+ |
+ attributes : |
+ * BaseComponent attributes |
+ * data : the text value as an encoded or unicode string |
+ """ |
+ |
+class Link(BaseComponent): |
+ """a labelled link |
+ |
+ attributes : |
+ * BaseComponent attributes |
+ * url : the link's target (REQUIRED) |
+ * label : the link's label as a string (use the url by default) |
+ """ |
+ def __init__(self, url, label=None, **kwargs): |
+ super(Link, self).__init__(**kwargs) |
+ assert url |
+ self.url = url |
+ self.label = label or url |
+ |
+ |
+class Image(BaseComponent): |
+ """an embedded or a single image |
+ |
+ attributes : |
+ * BaseComponent attributes |
+ * filename : the image's filename (REQUIRED) |
+ * stream : the stream object containing the image data (REQUIRED) |
+ * title : the image's optional title |
+ """ |
+ def __init__(self, filename, stream, title=None, **kwargs): |
+ super(Image, self).__init__(**kwargs) |
+ assert filename |
+ assert stream |
+ self.filename = filename |
+ self.stream = stream |
+ self.title = title |
+ |
+ |
+# container nodes ############################################################# |
+ |
+class Section(BaseLayout): |
+ """a section |
+ |
+ attributes : |
+ * BaseLayout attributes |
+ |
+ a title may also be given to the constructor, it'll be added |
+ as a first element |
+ a description may also be given to the constructor, it'll be added |
+ as a first paragraph |
+ """ |
+ def __init__(self, title=None, description=None, **kwargs): |
+ super(Section, self).__init__(**kwargs) |
+ if description: |
+ self.insert(0, Paragraph([Text(description)])) |
+ if title: |
+ self.insert(0, Title(children=(title,))) |
+ |
+class Title(BaseLayout): |
+ """a title |
+ |
+ attributes : |
+ * BaseLayout attributes |
+ |
+ A title must not contains a section nor a paragraph! |
+ """ |
+ |
+class Span(BaseLayout): |
+ """a title |
+ |
+ attributes : |
+ * BaseLayout attributes |
+ |
+ A span should only contains Text and Link nodes (in-line elements) |
+ """ |
+ |
+class Paragraph(BaseLayout): |
+ """a simple text paragraph |
+ |
+ attributes : |
+ * BaseLayout attributes |
+ |
+ A paragraph must not contains a section ! |
+ """ |
+ |
+class Table(BaseLayout): |
+ """some tabular data |
+ |
+ attributes : |
+ * BaseLayout attributes |
+ * cols : the number of columns of the table (REQUIRED) |
+ * rheaders : the first row's elements are table's header |
+ * cheaders : the first col's elements are table's header |
+ * title : the table's optional title |
+ """ |
+ def __init__(self, cols, title=None, |
+ rheaders=0, cheaders=0, rrheaders=0, rcheaders=0, |
+ **kwargs): |
+ super(Table, self).__init__(**kwargs) |
+ assert isinstance(cols, int) |
+ self.cols = cols |
+ self.title = title |
+ self.rheaders = rheaders |
+ self.cheaders = cheaders |
+ self.rrheaders = rrheaders |
+ self.rcheaders = rcheaders |
+ |
+class List(BaseLayout): |
+ """some list data |
+ |
+ attributes : |
+ * BaseLayout attributes |
+ """ |