florath/rmtoo

View on GitHub
rmtoo/outputs/oopricing1.py

Summary

Maintainability
F
4 days
Test Coverage
#  -*- coding: utf-8 -*-
'''
 rmtoo
   Free and Open Source Requirements Management Tool

  OpenOffice Pricing output class for rmtoo

 (c) 2010-2012,2017 by flonatel GmbH & Co. KG

 For licensing details see COPYING
'''
from six import iteritems

from rmtoo.lib.digraph.TopologicalSort import topological_sort
from rmtoo.lib.StdOutputParams import StdOutputParams
from rmtoo.lib.ExecutorTopicContinuum import ExecutorTopicContinuum
from rmtoo.lib.logging import tracer
from rmtoo.lib.CreateMakeDependencies import CreateMakeDependencies

# imports from python-odf
from odf.opendocument import OpenDocumentSpreadsheet
import odf.table
import odf.text
import odf.style
import odf.office
import odf.form
import odf.draw
import odf.number
import odf.dc

DEPS_HEADER_LEN = 6


class oopricing1(StdOutputParams, ExecutorTopicContinuum,
                 CreateMakeDependencies):

    def __setup_coord_lookup(self):
        '''Because at some points a requirement will be rendered in a row
           and at some other points as a column, there is the need to
           access the used cell addresses from integers.
           This function creates a map to easily acces the column name by
           the column index: 0->A, 1->B, ..., 26->Z, 27->AA, ...
           Note: This currently limits the number of requirements which can
           be handled with this output module to about 700. If there is a
           need for more requirements, this can be easily extended.'''
        alpha = 'abcdefghijklmnopqrstuvwxyz'.upper()
        pairs = [''.join((x, y)) for x in alpha
                 for y in [''] + [z for z in alpha]]
        self.__sscoords = sorted(pairs, key=len)

    def __init__(self, oconfig):
        '''Create a oopricing output object.'''
        tracer.debug("Called.")
        StdOutputParams.__init__(self, oconfig)
        CreateMakeDependencies.__init__(self)
        self.doc_styles = {}
        self.__used_vcs_id = None
        self.__setup_coord_lookup()

    def topic_continuum_sort(self, vcs_commit_ids, topic_sets):
        '''Because oopricing1 can only one topic continuum,
           the latest (newest) is used.'''
        self.__used_vcs_id = vcs_commit_ids[-1]
        return [topic_sets[vcs_commit_ids[-1].get_commit()]]

    def __create_meta(self):
        '''Create the meta-information for the document.'''
        m = odf.meta.Generator(text="rmtoo")
        self.__calcdoc.meta.addElement(m)
        m = odf.dc.Title(text="Requirements Pricing")
        self.__calcdoc.meta.addElement(m)
        m = odf.meta.UserDefined(name="Version",
                                 text=self.__used_vcs_id)
        self.__calcdoc.meta.addElement(m)
        m = odf.meta.UserDefined(name="Generator", text="rmtoo")
        self.__calcdoc.meta.addElement(m)

    # Functions handling style

    def __create_styles_table_cell(self):
        # Bold
        s = odf.style.Style(name="tc-bold", family="table-cell")
        s.addElement(
            odf.style.TextProperties(fontweight="bold", fontsize="12pt"))
        self.__calcdoc.automaticstyles.addElement(s)
        self.doc_styles["tc-bold"] = s

        # Bold with blue background for header
        s = odf.style.Style(name="tc-bold-blue", family="table-cell")
        s.addElement(
            odf.style.TextProperties(fontweight="bold", fontsize="12pt"))
        s.addElement(
            odf.style.TableCellProperties(backgroundcolor="#99ccff"))
        self.__calcdoc.automaticstyles.addElement(s)
        self.doc_styles["tc-bold-blue"] = s

        # Shrink-to-fit
        s = odf.style.Style(name="tc-shrink-to-fit", family="table-cell")
        s.addElement(
            odf.style.TableCellProperties(shrinktofit="true"))
        s.addElement(odf.style.TableCellProperties(cellprotect="none",
                                                   printcontent="true"))
        self.__calcdoc.automaticstyles.addElement(s)
        self.doc_styles["tc-shrink-to-fit"] = s

    def __create_styles_table_column(self):
        '''The different column style differ only in the columnwidth.'''
        colstyles = {
            "col-comment": "10in",
            "col-days": "0.5in",
            "col-dayrate": "0.65in",
            "col-compliant": "0.75in",
            "col-material": "0.8in",
            "col-sum": "0.9in",
            "col-ids": "1.2in",
            "col-name": "2.25in",
            "col-supplier": "0.75in",
            }

        # The sorted() is done to get always the same XML document -
        # which is important for comparison in tests.
        for name, size in sorted(iteritems(colstyles)):
            s = odf.style.Style(name=name, family="table-column")
            s.addElement(
                odf.style.TableColumnProperties(columnwidth=size))
            self.__calcdoc.automaticstyles.addElement(s)
            self.doc_styles[name] = s

    def __create_styles_currency(self):
        '''Column Style for Euro: only full Euros.'''
        # The positive part
        s = odf.number.CurrencyStyle(name="cs-euro-positive",
                                     volatile="true")
        s.addElement(odf.number.Number(
                decimalplaces="0", grouping="true", minintegerdigits="1"))
        s.addElement(odf.number.Text(text=" "))
        s.addElement(odf.number.CurrencySymbol(
                text=u"€", country="DE", language="de"))
        self.__calcdoc.styles.addElement(s)
        # This is the negative part: there is the decision, which one
        # is used.
        s = odf.number.CurrencyStyle(name="cs-euro")
        s.addElement(odf.number.Text(text="-"))
        s.addElement(odf.number.Number(
                decimalplaces="0", grouping="true", minintegerdigits="1"))
        s.addElement(odf.number.Text(text=" "))
        s.addElement(odf.number.CurrencySymbol(
                text=u"€", country="DE", language="de"))
        s.addElement(odf.style.Map(
                applystylename="cs-euro-positive", condition="value()>=0"))
        self.__calcdoc.styles.addElement(s)

        # This is the one for the read-only modules
        s = odf.style.Style(name="col-euro", family="table-cell",
                            datastylename="cs-euro")
        self.__calcdoc.automaticstyles.addElement(s)
        self.doc_styles["col-euro"] = s

        # And the same for read-write.
        s = odf.style.Style(name="col-euro-rw", family="table-cell",
                            datastylename="cs-euro")
        s.addElement(odf.style.TableCellProperties(cellprotect="none",
                                                   printcontent="true"))
        self.__calcdoc.automaticstyles.addElement(s)
        self.doc_styles["col-euro-rw"] = s

    def __create_styles_int(self):
        '''Number as used for days count.'''
        s = odf.number.NumberStyle(name="ns-int")
        s.addElement(odf.number.Number(
                decimalplaces="0", minintegerdigits="1"))
        self.__calcdoc.automaticstyles.addElement(s)

        # The version for read-only.
        s = odf.style.Style(name="col-int", family="table-cell",
                            datastylename="ns-int")
        self.__calcdoc.automaticstyles.addElement(s)
        self.doc_styles["col-int"] = s

        # And the same for rw.
        s = odf.style.Style(name="col-int-rw", family="table-cell",
                            datastylename="ns-int")
        s.addElement(odf.style.TableCellProperties(cellprotect="none",
                                                   printcontent="true"))
        self.__calcdoc.automaticstyles.addElement(s)
        self.doc_styles["col-int-rw"] = s

    def __create_styles(self):
        '''There is the need to apply some styles.'''
        # There is the need for many different styles.
        self.__create_styles_table_cell()
        self.__create_styles_table_column()
        self.__create_styles_currency()
        self.__create_styles_int()

    def topic_set_pre(self, topics_set):
        '''Document setup and output.
           Because for this document a very specific sort order
           must be implemented, everything must be done here explicitly -
           the executor interface can only partially be used.'''
        self.__calcdoc = OpenDocumentSpreadsheet()
        self.__create_meta()
        self.__create_styles()

    def topic_set_post(self, topics_set):
        '''Document storage.'''
        self.__calcdoc.save(self._output_filename, True)

    # Sheet creation functions.

    def __create_costs_sheet(self, sreqs):
        sheet = odf.table.Table(name="Costs", protected="true")
        self.create_form(sheet, sreqs)
        self.create_costs_column_styles(sheet)
        self.create_costs_header(sheet, sreqs[0])
        self.create_costs_content(sheet, sreqs)
        self.__calcdoc.spreadsheet.addElement(sheet)

    def __create_deps_sheet(self, sreqs):
        sheet = odf.table.Table(name="Deps")  # , protected="true")
        self.create_reqs_ids_row(sheet, sreqs)
        # The second row is where all the results will be inserted.
        # Therefore put in each one a none.
        tr = odf.table.TableRow()
        for _ in sreqs:
            self.create_text_cell(tr, "none")
        sheet.addElement(tr)
        # The third row contains the indices of the requirement
        # which is chosen as the dependent one.
        tr = odf.table.TableRow()
        for req in sreqs:
            tc = odf.table.TableCell()
            if len(req.incoming) > 0:
                # By default, the chosen is the first one.
                p = odf.text.P(text=req.incoming[0].get_id())
                tc.addElement(p)
            tr.addElement(tc)
        sheet.addElement(tr)

        self.create_empty_row(sheet)
        # Output all the dependent requirements
        self.create_deps_dependent(sheet, sreqs)
        self.__calcdoc.spreadsheet.addElement(sheet)

    def __create_sums_sheet(self, sreqs):
        self.create_one_sums_sheet(self.__calcdoc, sreqs, "SumRate", "L")
        self.create_one_sums_sheet(self.__calcdoc, sreqs, "SumMat", "M")

    def __create_constants_sheet(self):
        sheet = odf.table.Table(name="Constants", protected="true")
        # This is the list where the requirement compliance gets it
        # values from.
        for r in ["none", "partial", "fully"]:
            tr = odf.table.TableRow()
            tc = odf.table.TableCell()
            p = odf.text.P(text=r)
            tc.addElement(p)
            tr.addElement(tc)
            sheet.addElement(tr)
        self.__calcdoc.spreadsheet.addElement(sheet)

    # This is added to get all the results in one point (sheet)
    # which makes it easier to handle the output.
    def __create_result_sheet(self, sreqs):
        sheet = odf.table.Table(name="Results", protected="true")
        i = 0
        for req in sreqs:
            tr = odf.table.TableRow()
            self.create_result_one_req(tr, req, i)
            sheet.addElement(tr)
            i += 1
        self.__calcdoc.spreadsheet.addElement(sheet)

    def requirement_set_pre(self, requirement_set):
        '''The output of all the content.'''

        # Because of a problem with the current OpenOffice versions,
        # there is the need to sometimes arrange requirements as rows
        # and sometimes as columns:
        # It is not possible to define the range of a list input as a
        # row: it must be a column.
        # The order dictionary holds the number - which can be
        # computed in a row or column.
        def create_reqs_index(srqes):
            sreqs_index = {}
            cnt = 0
            for req in sreqs:
                sreqs_index[req] = cnt
                cnt += 1
            return sreqs_index

        sreqs = topological_sort(requirement_set)

        # Create the row / column index of each requirement
        self.sreqs_index = create_reqs_index(sreqs)

        # Create and save the document
        self.__create_costs_sheet(sreqs)
        self.__create_deps_sheet(sreqs)
        self.__create_sums_sheet(sreqs)
        self.__create_constants_sheet()
        self.__create_result_sheet(sreqs)

    def cmad_topic_continuum_pre(self, _):
        '''Write out the one and only dependency to all the requirements.'''
        tracer.debug("Called.")
        CreateMakeDependencies.write_reqs_dep(self._cmad_file,
                                              self._output_filename)

    # ======================================================================
    # 2nd level functions
    #

    # helper functions

    # Create an empty row
    @staticmethod
    def create_empty_row(sheet):
        tr = odf.table.TableRow()
        sheet.addElement(tr)

    @staticmethod
    def create_empty_cell(row):
        tc = odf.table.TableCell()
        row.addElement(tc)

    @staticmethod
    def create_empty_currency_cell(row):
        tc = odf.table.TableCell(
            valuetype="currency", currency="EUR",
            stylename="col-euro-rw")
        tc.addElement(odf.text.P())
        row.addElement(tc)

    @staticmethod
    def create_empty_currency_cell_ro(row):
        tc = odf.table.TableCell(
            valuetype="currency", currency="EUR",
            stylename="col-euro")
        tc.addElement(odf.text.P())
        row.addElement(tc)

    @staticmethod
    def create_empty_int_cell(row):
        tc = odf.table.TableCell(
            valuetype="float", value="0",
            stylename="col-int-rw")
        tc.addElement(odf.text.P())
        row.addElement(tc)

    # Create the first row in the deps or sums sheet: all the ids
    @staticmethod
    def create_reqs_ids_row(sheet, sreqs):
        tr = odf.table.TableRow()
        for req in sreqs:
            tc = odf.table.TableCell()
            p = odf.text.P(text=req.name)
            tc.addElement(p)
            tr.addElement(tc)
        sheet.addElement(tr)

    # Creates a text cell with the given text. Optional a style can be
    # specified.
    @staticmethod
    def create_text_cell(table_row, text, style=None):
        if style is not None:
            tc = odf.table.TableCell(stylename=style)
        else:
            tc = odf.table.TableCell()

        if text is not None:
            p = odf.text.P(text=text)
            tc.addElement(p)
        table_row.addElement(tc)

    # Functions handling costs

    def create_costs_column_styles(self, sheet):
        # 1 Colum: Ids
        tc = odf.table.TableColumn(stylename=self.doc_styles["col-ids"])
        sheet.addElement(tc)
        # 2 Colum: Name
        tc = odf.table.TableColumn(stylename=self.doc_styles["col-name"])
        sheet.addElement(tc)
        # 3 Colum: Compliant
        tc = odf.table.TableColumn(stylename=self.doc_styles["col-compliant"])
        sheet.addElement(tc)
        # 4 Colum: Costs-dayrate
        tc = odf.table.TableColumn(
            stylename=self.doc_styles["col-dayrate"],
            defaultcellstylename=self.doc_styles["col-euro"])
        sheet.addElement(tc)
        # 5 Colum: Costs-days
        tc = odf.table.TableColumn(
            stylename=self.doc_styles["col-days"],
            defaultcellstylename=self.doc_styles["col-int"])
        sheet.addElement(tc)
        # 6 Colum: Costs-material
        tc = odf.table.TableColumn(
            stylename=self.doc_styles["col-material"],
            defaultcellstylename=self.doc_styles["col-euro"])
        sheet.addElement(tc)
        # 7 Colum: Costs-sum
        tc = odf.table.TableColumn(
            stylename=self.doc_styles["col-sum"],
            defaultcellstylename=self.doc_styles["col-euro"])
        sheet.addElement(tc)
        # 8 Colum: Dependent from
        tc = odf.table.TableColumn(stylename=self.doc_styles["col-ids"])
        sheet.addElement(tc)
        # 9-14 Sum columns
        for _ in ["dep-rate", "dep-mat", "dep-sum",
                  "ovl-rate", "ovl-mat", "ovl-sum"]:
            tc = odf.table.TableColumn(
                stylename=self.doc_styles["col-sum"],
                defaultcellstylename=self.doc_styles["col-euro"])
            sheet.addElement(tc)
        # 15 Supplier
        tc = odf.table.TableColumn(stylename=self.doc_styles["col-supplier"])
        sheet.addElement(tc)
        # 16 Comment
        tc = odf.table.TableColumn(stylename=self.doc_styles["col-comment"])
        sheet.addElement(tc)

    def create_costs_header(self, sheet, req):
        # First is empty
        self.create_empty_row(sheet)
        # Second holds only the Overall sum
        tr = odf.table.TableRow()
        self.create_text_cell(tr, req.get_id(),
                              self.doc_styles["tc-bold"])
        sheet.addElement(tr)
        # Followed by an additionally empty line
        self.create_empty_row(sheet)
        # Table header line 1
        tr = odf.table.TableRow()
        for h in ["Id", "Name", "Compliant", "Costs for requirement",
                  None, None, None, "Dependent from",
                  "Costs of dependent", None, None,
                  "Overall sum", None, None, "Supplier", "Comment"]:
            self.create_text_cell(tr, h, self.doc_styles["tc-bold-blue"])
        sheet.addElement(tr)
        # Table header line 2
        tr = odf.table.TableRow()
        for h in [None, None, None, "dayrate",
                  "#days", "material", "sum", None,
                  "rate", "material", "sum",
                  "rate", "material", "sum", None, None]:
            self.create_text_cell(tr, h, self.doc_styles["tc-bold-blue"])
        sheet.addElement(tr)

    def create_costs_content(self, sheet, sreqs):
        i = 0
        for req in sreqs:
            tr = odf.table.TableRow()
            self.create_costs_content_req(tr, req, i)
            sheet.addElement(tr)
            i += 1

    def create_costs_content_req(self, tr, req, i):
        choi = i + DEPS_HEADER_LEN
        # First cell is the id
        self.create_text_cell(tr, req.name)
        # Second cell is the name
        self.create_text_cell(tr, req.get_value("Name").get_content())
        # Third is the compliant
        tc = odf.table.TableCell()
        dc = odf.draw.Control(control="lbcompliant%s" % req.name,
                              zindex="0",
                              x="0.0in",
                              y="0.0in",
                              endcelladdress="Costs.C%d" % (choi + 1),
                              endx="0.75in",
                              endy="0.0in")
        tc.addElement(dc)
        tr.addElement(tc)
        # Three empty columns for costs
        self.create_empty_currency_cell(tr)
        self.create_empty_int_cell(tr)
        self.create_empty_currency_cell(tr)
        # Sum / factor of before ones
        tc = odf.table.TableCell(
            valuetype="currency", currency="EUR",
            formula="oooc:=[.D%d]*[.E%d]+[.F%d]" % (choi, choi, choi))
        tr.addElement(tc)
        # Dependent on Chooser
        tc = odf.table.TableCell()
        # Do not do this for first cell.
        if len(req.incoming) > 0:
            dc = odf.draw.Control(control="lbdependentfrom%s" % req.name,
                                  zindex="0",
                                  x="0.0in",
                                  y="0.0in",
                                  endcelladdress="Costs.H%d" % (choi + 1),
                                  endx="1.2in",
                                  endy="0.0in")
            tc.addElement(dc)
        tr.addElement(tc)

        # dependet rate and material
        # Do not do this for first cell.
        for sname in ["SumRate", "SumMat"]:
            if len(req.outgoing) > 0:
                tc = odf.table.TableCell(
                    valuetype="currency", currency="EUR",
                    formula="oooc:=SUM([%s.%s2:%s.%s%d])"
                    % (sname, self.__sscoords[i], sname, self.__sscoords[i],
                       (1 + len(req.outgoing))))
                tr.addElement(tc)
            else:
                self.create_empty_currency_cell_ro(tr)

        # sum of dependent
        tc = odf.table.TableCell(
            valuetype="currency", currency="EUR",
            formula="oooc:=[.I%d]+[.J%d]" % (choi, choi))
        tr.addElement(tc)

        # Overall rate
        tc = odf.table.TableCell(
            valuetype="currency", currency="EUR",
            formula="oooc:=[.D%d]*[.E%d]+[.I%d]" % (choi, choi, choi))
        tr.addElement(tc)
        # Overall material
        tc = odf.table.TableCell(
            valuetype="currency", currency="EUR",
            formula="oooc:=[.F%d]+[.J%d]" % (choi, choi))
        tr.addElement(tc)
        # Overall sum
        tc = odf.table.TableCell(
            valuetype="currency", currency="EUR",
            formula="oooc:=[.L%d]+[.M%d]" % (choi, choi))
        tr.addElement(tc)
        # Supplier
        tc = odf.table.TableCell(
            valuetype="string", stylename=self.doc_styles["tc-shrink-to-fit"])
        tr.addElement(tc)
        # Comment
        tc = odf.table.TableCell(
            valuetype="string", stylename=self.doc_styles["tc-shrink-to-fit"])
        tr.addElement(tc)

    # Functions handling deps

    def create_deps_dependent(self, sheet, sreqs):
        # The number of the following rows depend on the maximum
        # number of incoming requirements.
        # This flags if there is something found with the current
        # index.
        i = 0
        while True:
            tr = odf.table.TableRow()
            index_used = False
            for req in sreqs:
                if len(req.incoming) > i:
                    tc = odf.table.TableCell()
                    p = odf.text.P(text=req.incoming[i].name)
                    tc.addElement(p)
                    tr.addElement(tc)
                    index_used = True
                else:
                    tc = odf.table.TableCell()
                    tr.addElement(tc)
            sheet.addElement(tr)
            if not index_used:
                break
            i += 1

    # Functions handling sums

    # Create one sum sheet
    def create_one_sums_sheet(self, calcdoc, sreqs, name, colname):
        sheet = odf.table.Table(name=name, protected="true")
        self.create_reqs_ids_row(sheet, sreqs)

        i = 0
        while True:
            tr = odf.table.TableRow()
            index_used = False
            for req in sreqs:
                if len(req.outgoing) > i:
                    # This is somewhat complicated:
                    # If on the Costs sheet one direction is chosen,
                    # it is written to the deps sheet (row 3).
                    # If this row contains the name of the current
                    # requirment, it is chosen to be dependent and the
                    # overall costs of that requirement must go to the
                    # local list - which then is again summed over on
                    # the cost sheet.
                    tc = odf.table.TableCell(
                        valuetype="currency", currency="EUR",
                        formula='oooc:=IF([Deps.%s3]="%s";[Costs.%s%d];0)' %
                        (self.__sscoords[self.sreqs_index[req.outgoing[i]]],
                         req.name, colname,
                         self.sreqs_index[req.outgoing[i]] + DEPS_HEADER_LEN))
                    tr.addElement(tc)
                    index_used = True
                else:
                    tc = odf.table.TableCell()
                    tr.addElement(tc)
            sheet.addElement(tr)
            if not index_used:
                break
            i += 1

        calcdoc.spreadsheet.addElement(sheet)

    # Functions handling forms
    def create_form(self, calcdoc, sreqs):
        forms = odf.office.Forms(
            applydesignmode="false",
            automaticfocus="false")
        form = odf.form.Form(
            applyfilter="true",
            commandtype="table",
            controlimplementation="ooo:com.sun.star.form.component.Form",
            name="Standard",
            targetframe="",
            href="")

        # Listboxes for compliant
        i = 0
        for req in sreqs:
            lb = odf.form.Listbox(
                id="lbcompliant%s" % req.name,
                boundcolumn="1",
                dropdown="yes",
                controlimplementation="ooo:com.sun.star."
                "form.component.ListBox",
                linkedcell="Deps.%s2" % self.__sscoords[i],
                listlinkagetype="selection",
                name="ListBox Compliant %s" % req.name,
                size="3",
                sourcecellrange="Constants.A1:Constants.A3"
                )
            lbproperties = odf.form.Properties()
            lbprop = odf.form.Property(
                propertyname="DefaultControl",
                stringvalue="com.sun.star.form.control.ListBox",
                valuetype="string")
            lbproperties.addElement(lbprop)
            # Default selection
            lstprop = odf.form.ListProperty(
                propertyname="DefaultSelection",
                valuetype="float")
            defaultval = odf.form.ListValue(stringvalue='0')
            lstprop.addElement(defaultval)
            lbproperties.addElement(lstprop)

            lb.addElement(lbproperties)

            form.addElement(lb)
            i += 1

        # Listboxes for dependent from
        i = 0
        for req in sreqs:
            # When there is only one entry in the list, there is no
            # need to have a dropdown list.
            # Needed?
            # ddown = "yes"
            # if len(req.incoming) <= 1:
            #    ddown = "no"

            lb = odf.form.Listbox(
                id="lbdependentfrom%s" % req.name,
                boundcolumn="1",
                dropdown="yes",
                controlimplementation="ooo:com.sun.star."
                "form.component.ListBox",
                linkedcell="Deps.%s3" % self.__sscoords[i],
                listlinkagetype="selection",
                name="ListBox Dependet From %s" % req.name,
                size="3",
                sourcecellrange="Deps.%s5:Deps.%s%d" % (
                    self.__sscoords[i], self.__sscoords[i],
                    len(req.incoming) + 4)
                )
            lbproperties = odf.form.Properties()
            lbprop = odf.form.Property(
                propertyname="DefaultControl",
                stringvalue="com.sun.star.form.control.ListBox",
                valuetype="string")
            lbproperties.addElement(lbprop)
            # Default selection
            lstprop = odf.form.ListProperty(
                propertyname="DefaultSelection",
                valuetype="float")
            defaultval = odf.form.ListValue(stringvalue='0')
            lstprop.addElement(defaultval)
            lbproperties.addElement(lstprop)
            # Read only
            # When there is only one dependent requirement, it makes
            # no sense to have something which can be changed.
            # Therefore this should be readonly then.
            if len(req.incoming) <= 1:
                lstprop = odf.form.Property(
                    propertyname="ReadOnly",
                    valuetype="boolean",
                    booleanvalue="true")
                lbproperties.addElement(lstprop)

            lb.addElement(lbproperties)

            form.addElement(lb)
            i += 1

        forms.addElement(form)
        calcdoc.addElement(forms)

    # Functions handling result sheet
    def create_result_one_req(self, tr, req, i):
        # 1 Id
        self.create_text_cell(tr, req.name)
        # 2 Compliance
        tc = odf.table.TableCell(
            valuetype="string",
            formula="oooc:=[Deps.%s2]" % self.__sscoords[i])
        tr.addElement(tc)
        # Prices
        for r in ["D", "E", "F"]:
            tc = odf.table.TableCell(
                valuetype="string",
                formula="oooc:=[Costs.%s%d]" % (r, i + DEPS_HEADER_LEN))
            tr.addElement(tc)
        # Dependent from
        tc = odf.table.TableCell(
            valuetype="string",
            formula="oooc:=[Deps.%s3]" % self.__sscoords[i])
        tr.addElement(tc)
        # Supplier
        tc = odf.table.TableCell(
            valuetype="string",
            formula="oooc:=[Costs.O%d]" % (i + DEPS_HEADER_LEN))
        tr.addElement(tc)
        # Comment
        tc = odf.table.TableCell(
            valuetype="string",
            formula="oooc:=[Costs.P%d]" % (i + DEPS_HEADER_LEN))
        tr.addElement(tc)