jdum / odfdo

python library for OpenDocument format (ODF)
Apache License 2.0
48 stars 11 forks source link

Column table styling #17

Open bastien34 opened 2 years ago

bastien34 commented 2 years ago

Hi, after few tries, I'm wondering if it's possible to apply a column style (basically a column width) in a table appended in a text document. I've seen the recipe for doing a such styling in a spreadsheet, unfortunately, this doesn't work in my text document.

col_style` = Style("table-column", width="3.6cm", bold=True)
 name = doc.insert_style(style=col_style, automatic=True)
 for column in table.get_columns():
            column.style = name
            table.set_column(column.x, column)

Is there a way to set the width of a column in a text document, then?

jdum commented 2 years ago

Hi, I think the bug is that the table does not allows changes on itself while in a "get_columns()" loop. (It would require some clone() calls).

So the solution:

col_style = Style("table-column", width="3.6cm")
# Note: the column can only be styled for their width, so "bold" will be ignored
# Actually, ODF table is quite a list of rows, column are only shortcuts to set their width inside the table.
name = doc.insert_style(style=col_style, automatic=True)
# table.width is the number of columns of the table... 
for position in range(table.width):   
    col = table.get_column(position)
    column.style = name
    table.set_column(position, col)

Hope that works...

bastien34 commented 2 years ago

Thanks for your quick answer !

Unfortunately it doesn't work. It has no effect of the created table. So I formatted a table and I copied the serialized column styles. I only have 2 columns. The very strange result is that it adds a third column of equal width.

I let here my attempt:

def col_A() -> Style:
    return Element.from_tag(
        '<style:style style:name="mission-table.A" style:family="table-column">'
        '<style:table-column-properties style:column-width="5.609cm" style:rel-column-width="3180*"/>'
        '</style:style>'
    )

And to apply style:

        col = table.get_column(0)
        col.style = 'mission-table.A'
        table.set_column(0, col)

I do the same for columns A and B and it adds a third empty column!

jdum commented 2 years ago

My snippet works here, so there is another pb elsewhere. In your last attempt dont forget to insert style in doc:

style = col_A()
document.insert_style(style=style, automatic=True) 

And then it works

jdum commented 2 years ago

Note: ODF columns don't contain cells, only style information.

bastien34 commented 2 years ago

I created a snippet that can be read easily. It's a minimalist creation of a table with the attempt of doing a table with defined sized columns. When I run it, I get a 3 columns table which is to me out of sense.

#!/usr/bin/env python

from odfdo import Table, Element
from odfdo import Document, Style

def col_A() -> Style:
    return Element.from_tag(
        '<style:style style:name="mission-table.A" style:family="table-column">'
        '<style:table-column-properties style:column-width="5.609cm" style:rel-column-width="3180*"/>'
        '</style:style>'
    )

def col_B() -> Style:
    return Element.from_tag(
        '<style:style style:name="mission-table.B" style:family="table-column">'
        '<style:table-column-properties style:column-width="11.389cm" style:rel-column-width="6457*"/>'
        '</style:style>'
    )

if __name__ == "__main__":

    document = Document("text")
    body = document.body

    data = [
        ('Mission', 'Nom de la mission'),
        ('Durée', 'mission length'),
        ('Info', 'descr'),
    ]

    col_a = document.insert_style(col_A())
    col_b = document.insert_style(col_B())

    table = Table('mission-table', width=2, height=3)
    table.set_values(data)
    document.body.append(table)

    col = table.get_column(0)
    col.style = col_a
    table.set_column(0, col)

    col = table.get_column(1)
    col.style = col_b
    table.set_column(1, col)

    document.save(target="/home/bastien/test_table.odt", pretty=True)

If you'd like to give it a try, you only need to change the path to save the doc.

bastien34 commented 2 years ago

Ok I found the solution ! The style must be defined before the data are set.


from odfdo import Table, Element
from odfdo import Document, Style

def col_A() -> Style:
    return Element.from_tag(
        '<style:style style:name="mission-table.A" style:family="table-column">'
        '<style:table-column-properties style:column-width="5.609cm" style:rel-column-width="3180*"/>'
        '</style:style>'
    )

def col_B() -> Style:
    return Element.from_tag(
        '<style:style style:name="mission-table.B" style:family="table-column">'
        '<style:table-column-properties style:column-width="11.389cm" style:rel-column-width="6457*"/>'
        '</style:style>'
    )

if __name__ == "__main__":

    path = '/home/bastien/test_table.odt'
    document = Document("text")
    body = document.body

    data = [
        ('Mission', 'Nom de la mission'),
        ('Durée', 'mission length'),
        ('Info', 'descr'),
    ]

    col_a = document.insert_style(col_A(), automatic=True)
    col_b = document.insert_style(col_B(), automatic=True)

    table = Table('new-mission-table')
    body.append(table)

    col = table.get_column(0)
    col.style = col_a
    table.set_column(0, col)

    col = table.get_column(1)
    col.style = col_b
    table.set_column(1, col)

    table.set_values(data)

    document.save(target="/home/bastien/test_table.odt", pretty=True)

Hope this could help !