Skip to content

Toc

TOC class for “text:table-of-content” tag and TabStopStyle, TocEntryTemplate, IndexBody, IndexTitle, IndexTitleTemplate related classes.

Classes:

Name Description
IndexBody

Represents the “text:index-body” element, which contains the content of an index.

IndexTitle

Represents the title of an index, “text:index-title”.

IndexTitleTemplate

Represents a template style for an index title, “text:index-title-template”.

TOC

A table of content, “text:table-of-content”.

TabStopStyle

Style for a tab-stop in a TOC entry, represented by “style:tab-stop”.

TocEntryTemplate

Template for a TOC entry, “text:table-of-content-entry-template”.

Functions:

Name Description
default_toc_level_style

Generate an automatic default style for the given TOC level.

IndexBody

Bases: ListMixin, TocMixin, SectionMixin

Represents the “text:index-body” element, which contains the content of an index.

This element is used for all types of indexes within an ODF document and holds the generated index content.

Source code in odfdo/toc.py
583
584
585
586
587
588
589
590
591
class IndexBody(ListMixin, TocMixin, SectionMixin):
    """Represents the "text:index-body" element, which contains the content of an index.

    This element is used for all types of indexes within an ODF document and
    holds the generated index content.
    """

    _tag: str = "text:index-body"
    _properties: tuple[PropDef | PropDefBool, ...] = ()

_properties class-attribute instance-attribute

_properties: tuple[PropDef | PropDefBool, ...] = ()

_tag class-attribute instance-attribute

_tag: str = 'text:index-body'

IndexTitle

Bases: ListMixin, TocMixin, SectionMixin

Represents the title of an index, “text:index-title”.

This element contains the title for an index, and its properties define how the title is displayed and protected.

Attributes:

Name Type Description
name str

The name of the index title.

style str

The style name applied to the index title.

xml_id str

A unique XML identifier.

protected bool

Indicates if the index title is protected.

protection_key str

The protection key if the title is protected.

protection_key_digest_algorithm str

The algorithm used for the protection key.

Methods:

Name Description
__init__

Create an IndexTitle element.

set_title_text

Set the actual text content of the index title.

Source code in odfdo/toc.py
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
class IndexTitle(ListMixin, TocMixin, SectionMixin):
    """Represents the title of an index, "text:index-title".

    This element contains the title for an index, and its properties define
    how the title is displayed and protected.

    Attributes:
        name (str): The name of the index title.
        style (str): The style name applied to the index title.
        xml_id (str): A unique XML identifier.
        protected (bool): Indicates if the index title is protected.
        protection_key (str): The protection key if the title is protected.
        protection_key_digest_algorithm (str): The algorithm used for the protection key.
    """

    _tag = "text:index-title"
    _properties: tuple[PropDef | PropDefBool, ...] = (
        PropDef("name", "text:name"),
        PropDef("style", "text:style-name"),
        PropDef("xml_id", "xml:id"),
        PropDef("protected", "text:protected"),
        PropDef("protection_key", "text:protection-key"),
        PropDef(
            "protection_key_digest_algorithm", "text:protection-key-digest-algorithm"
        ),
    )

    def __init__(
        self,
        name: str | None = None,
        style: str | None = None,
        title_text: str | None = None,
        title_text_style: str | None = None,
        xml_id: str | None = None,
        **kwargs: Any,
    ) -> None:
        """Create an IndexTitle element.

        Args:
            name: The name of the index title.
            style: The style name for the index title.
            title_text: The actual text content of the title.
            title_text_style: The style name for the title text.
            xml_id: A unique XML identifier for the title.
            **kwargs: Arbitrary keyword arguments for the Element base class.
        """
        super().__init__(**kwargs)
        if self._do_init:
            if name:
                self.name = name
            if style:
                self.style = style
            if xml_id:
                self.xml_id = xml_id
            if title_text:
                self.set_title_text(title_text, title_text_style)

    def set_title_text(
        self,
        title_text: str,
        title_text_style: str | None = None,
    ) -> None:
        """Set the actual text content of the index title.

        Args:
            title_text: The text content to set for the title.
            title_text_style: The style name for the title text.
        """
        current = self.get_element("text:p")
        if current:
            current.delete()
        title = Element.from_tag("text:p")
        title.append_plain_text(title_text)  # type: ignore[attr-defined]
        title.style = title_text_style  # type: ignore[attr-defined]
        self.append(title)

_properties class-attribute instance-attribute

_properties: tuple[PropDef | PropDefBool, ...] = (
    PropDef("name", "text:name"),
    PropDef("style", "text:style-name"),
    PropDef("xml_id", "xml:id"),
    PropDef("protected", "text:protected"),
    PropDef("protection_key", "text:protection-key"),
    PropDef(
        "protection_key_digest_algorithm",
        "text:protection-key-digest-algorithm",
    ),
)

_tag class-attribute instance-attribute

_tag = 'text:index-title'

name instance-attribute

name = name

style instance-attribute

style = style

xml_id instance-attribute

xml_id = xml_id

__init__

__init__(
    name: str | None = None,
    style: str | None = None,
    title_text: str | None = None,
    title_text_style: str | None = None,
    xml_id: str | None = None,
    **kwargs: Any,
) -> None

Create an IndexTitle element.

Parameters:

Name Type Description Default
name str | None

The name of the index title.

None
style str | None

The style name for the index title.

None
title_text str | None

The actual text content of the title.

None
title_text_style str | None

The style name for the title text.

None
xml_id str | None

A unique XML identifier for the title.

None
**kwargs Any

Arbitrary keyword arguments for the Element base class.

{}
Source code in odfdo/toc.py
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
def __init__(
    self,
    name: str | None = None,
    style: str | None = None,
    title_text: str | None = None,
    title_text_style: str | None = None,
    xml_id: str | None = None,
    **kwargs: Any,
) -> None:
    """Create an IndexTitle element.

    Args:
        name: The name of the index title.
        style: The style name for the index title.
        title_text: The actual text content of the title.
        title_text_style: The style name for the title text.
        xml_id: A unique XML identifier for the title.
        **kwargs: Arbitrary keyword arguments for the Element base class.
    """
    super().__init__(**kwargs)
    if self._do_init:
        if name:
            self.name = name
        if style:
            self.style = style
        if xml_id:
            self.xml_id = xml_id
        if title_text:
            self.set_title_text(title_text, title_text_style)

set_title_text

set_title_text(
    title_text: str, title_text_style: str | None = None
) -> None

Set the actual text content of the index title.

Parameters:

Name Type Description Default
title_text str

The text content to set for the title.

required
title_text_style str | None

The style name for the title text.

None
Source code in odfdo/toc.py
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
def set_title_text(
    self,
    title_text: str,
    title_text_style: str | None = None,
) -> None:
    """Set the actual text content of the index title.

    Args:
        title_text: The text content to set for the title.
        title_text_style: The style name for the title text.
    """
    current = self.get_element("text:p")
    if current:
        current.delete()
    title = Element.from_tag("text:p")
    title.append_plain_text(title_text)  # type: ignore[attr-defined]
    title.style = title_text_style  # type: ignore[attr-defined]
    self.append(title)

IndexTitleTemplate

Bases: Element

Represents a template style for an index title, “text:index-title-template”.

This element defines the styling for index titles within an ODF document.

Methods:

Name Description
__init__

Create an IndexTitleTemplate element.

Attributes:

Name Type Description
style
Source code in odfdo/toc.py
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
class IndexTitleTemplate(Element):
    """Represents a template style for an index title, "text:index-title-template".

    This element defines the styling for index titles within an ODF document.
    """

    _tag = "text:index-title-template"
    _properties: tuple[PropDef | PropDefBool, ...] = (
        PropDef("style", "text:style-name"),
    )

    def __init__(self, style: str | None = None, **kwargs: Any) -> None:
        """Create an IndexTitleTemplate element.

        Args:
            style: The style name for the template.
            **kwargs: Arbitrary keyword arguments for the Element base class.
        """
        super().__init__(**kwargs)
        if self._do_init and style:
            self.style = style

_properties class-attribute instance-attribute

_properties: tuple[PropDef | PropDefBool, ...] = (
    PropDef("style", "text:style-name"),
)

_tag class-attribute instance-attribute

_tag = 'text:index-title-template'

style instance-attribute

style = style

__init__

__init__(style: str | None = None, **kwargs: Any) -> None

Create an IndexTitleTemplate element.

Parameters:

Name Type Description Default
style str | None

The style name for the template.

None
**kwargs Any

Arbitrary keyword arguments for the Element base class.

{}
Source code in odfdo/toc.py
685
686
687
688
689
690
691
692
693
694
def __init__(self, style: str | None = None, **kwargs: Any) -> None:
    """Create an IndexTitleTemplate element.

    Args:
        style: The style name for the template.
        **kwargs: Arbitrary keyword arguments for the Element base class.
    """
    super().__init__(**kwargs)
    if self._do_init and style:
        self.style = style

TOC

Bases: MDToc, Element

A table of content, “text:table-of-content”.

The “text:table-of-content” element represents a table of contents for a document. The items that can be listed in a table of contents are:

  • Headings (as defined by the outline structure of the document), up to a selected level.

  • Table of contents index marks.

  • Paragraphs formatted with specified paragraph styles.

Attributes:

Name Type Description
name str

The name of the table of contents.

style str

The style name for the TOC.

xml_id str

The XML ID of the TOC.

protected bool

Whether the TOC is protected from manual changes.

protection_key str

The key for protection.

protection_key_digest_algorithm str

The algorithm for the protection key digest.

Methods:

Name Description
__init__

Initializes a TOC (Table of Contents) element.

__str__
create_toc_source

Create the ‘text:table-of-content-source’ element for a TOC.

fill

Fill the TOC with titles from the document.

get_formatted_text

Returns the formatted text content of the TOC.

get_title

Returns the title of the TOC.

set_toc_title

Sets the title of the TOC.

Source code in odfdo/toc.py
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
class TOC(MDToc, Element):
    """A table of content, "text:table-of-content".

    The "text:table-of-content" element represents a table of contents for a
    document. The items that can be listed in a table of contents are:

      - Headings (as defined by the outline structure of the document), up to
        a selected level.

      - Table of contents index marks.

      - Paragraphs formatted with specified paragraph styles.

    Attributes:
        name (str): The name of the table of contents.
        style (str, optional): The style name for the TOC.
        xml_id (str, optional): The XML ID of the TOC.
        protected (bool): Whether the TOC is protected from manual changes.
        protection_key (str, optional): The key for protection.
        protection_key_digest_algorithm (str, optional): The algorithm for
            the protection key digest.
    """

    _tag = "text:table-of-content"
    _properties = (
        PropDef("name", "text:name"),
        PropDef("style", "text:style-name"),
        PropDef("xml_id", "xml:id"),
        PropDef("protected", "text:protected"),
        PropDef("protection_key", "text:protection-key"),
        PropDef(
            "protection_key_digest_algorithm", "text:protection-key-digest-algorithm"
        ),
    )

    def __init__(
        self,
        title: str = "Table of Contents",
        name: str | None = None,
        protected: bool = True,
        outline_level: int = 0,
        style: str | None = None,
        title_style: str = "Contents_20_Heading",
        entry_style: str = "Contents_20_%d",
        **kwargs: Any,
    ) -> None:
        """Initializes a TOC (Table of Contents) element.

        Default parameters are what most people use: protected from manual
        modifications and not limited in title levels.

        The name is mandatory and derived automatically from the title if not
        given. Provide one in case of a conflict with other TOCs in the same
        document.

        Args:
            title: The title of the TOC (e.g., "Table of Contents").
            name: The name of the TOC element. If not
                provided, it's generated from the title.
            protected: If True, the TOC is protected from manual
                modifications.
            outline_level: The maximum outline level to include in the
                TOC. 0 means all levels.
            style: The style name for the TOC container.
            title_style: The style for the TOC's main title.
            entry_style: A format string for the style of each TOC
                entry (e.g., "Contents_20_%d").
        """
        super().__init__(**kwargs)
        if self._do_init:
            if style:
                self.style = style
            if protected:
                self.protected = protected
            if name is None:
                self.name = f"{title}1"
            # Create the source template
            toc_source = self.create_toc_source(
                title, outline_level, title_style, entry_style
            )
            self.append(toc_source)
            # Create the index body automatically with the index title
            if title:
                # This style is in the template document
                self.set_toc_title(title, text_style=title_style)

    @staticmethod
    def create_toc_source(
        title: str,
        outline_level: int,
        title_style: str,
        entry_style: str,
    ) -> Element:
        """Create the 'text:table-of-content-source' element for a TOC.

        This element defines the structure and appearance of the TOC.

        Args:
            title: The title of the TOC.
            outline_level: The maximum outline level to include.
            title_style: The style for the TOC's title.
            entry_style: The format string for entry styles.

        Returns:
            Element: The newly created 'text:table-of-content-source'
                element.
        """
        toc_source = Element.from_tag("text:table-of-content-source")
        toc_source.set_attribute("text:outline-level", str(outline_level))
        if title:
            title_template = IndexTitleTemplate()
            if title_style:
                # This style is in the template document
                title_template.style = title_style
            title_template.text = title
            toc_source.append(title_template)
        for level in range(1, 11):
            template = TocEntryTemplate(outline_level=level)
            if entry_style:
                template.style = entry_style % level
            toc_source.append(template)
        return toc_source

    def __str__(self) -> str:
        return self.get_formatted_text()

    def get_formatted_text(self, context: dict | None = None) -> str:
        """Returns the formatted text content of the TOC.

        Args:
            context: A context dictionary for formatting.
                If 'rst_mode' is True, it returns a reStructuredText
                'contents' directive.

        Returns:
            str: The formatted text of the TOC.
        """
        index_body = cast(None | IndexBody, self.get_element(IndexBody._tag))

        if index_body is None:
            return ""
        if context is None:
            context = {}
        if context.get("rst_mode"):
            return "\n.. contents::\n\n"

        result = []
        for element in index_body.children:
            if element.tag == "text:index-title":
                for child_element in element.children:
                    result.append(child_element.get_formatted_text(context).strip())
            else:
                result.append(element.get_formatted_text(context).strip())
        return "\n".join(x for x in result if x)

    @property
    def outline_level(self) -> int | None:
        """The outline level of the TOC.

        This property controls the maximum heading level that will be included
        in the table of contents. A value of 0 means all levels are included.
        """
        source = self.get_element("text:table-of-content-source")
        if source is None:
            return None
        return source.get_attribute_integer("text:outline-level")

    @outline_level.setter
    def outline_level(self, level: int) -> None:
        source = self.get_element("text:table-of-content-source")
        if source is None:
            source = Element.from_tag("text:table-of-content-source")
            self.insert(source, FIRST_CHILD)
        source.set_attribute("text:outline-level", str(level))

    @property
    def body(self) -> IndexBody | None:
        """The body of the TOC ('text:index-body').

        This property provides access to the 'text:index-body' element, which
        contains the actual entries of the table of contents.
        """
        return cast(None | IndexBody, self.get_element(IndexBody._tag))

    @body.setter
    def body(self, body: Element | None = None) -> Element | None:
        old_body = self.body
        if old_body is not None:
            self.delete(old_body)
        if body is None:
            body = Element.from_tag("text:index-body")
        self.append(body)
        return body

    def get_title(self) -> str:
        """Returns the title of the TOC.

        Returns:
            str: The title of the TOC.
        """
        index_body = self.body
        if index_body is None:
            return ""
        index_title = cast(
            None | IndexTitle, index_body.get_element(IndexTitle._tag)
        )
        if index_title is None:
            return ""
        return index_title.text_content

    def set_toc_title(
        self,
        title: str,
        style: str | None = None,
        text_style: str | None = None,
    ) -> None:
        """Sets the title of the TOC.

        Args:
            title: The new title for the TOC.
            style: The style for the index title element.
            text_style: The style for the title's paragraph.
        """
        index_body = self.body
        if index_body is None:
            self.body = None  # this ceates a new index_body
            index_body = cast(IndexBody, self.body)
        index_title = cast(
            None | IndexTitle, index_body.get_element(IndexTitle._tag)
        )
        if index_title:
            style = style or index_title.style
            if not text_style:
                index_title_paragraph = index_title.get_element("text:p")
                if index_title_paragraph:
                    text_style = index_title_paragraph.style  # type: ignore[attr-defined]
            name = index_title.name
            index_title.delete()
        else:
            name = f"{self.name}_Head"
        index_title = IndexTitle(
            name=name, style=style, title_text=title, text_style=text_style
        )
        index_body.append(index_title)

    @staticmethod
    def _header_numbering(level_indexes: dict[int, int], level: int) -> str:
        """Return the header hierarchical number (like "1.2.3.").

        Args:
            level_indexes: A dictionary to track numbering
                at each level.
            level: The current header level.

        Returns:
            str: The hierarchical number string.
        """
        numbers: list[int] = []
        # before header level
        for idx in range(1, level):
            numbers.append(level_indexes.setdefault(idx, 1))
        # header level
        index = level_indexes.get(level, 0) + 1
        level_indexes[level] = index
        numbers.append(index)
        # after header level
        idx = level + 1
        while idx in level_indexes:
            del level_indexes[idx]
            idx += 1
        return ".".join(str(x) for x in numbers) + "."

    def fill(
        self,
        document: Document | None = None,
        use_default_styles: bool = True,
    ) -> None:
        """Fill the TOC with titles from the document.

        This method populates the table of contents by scanning the document
        for headers. It is not contextual and will include all titles from
        the document, regardless of their position relative to the TOC.

        If the TOC is not yet part of a document, you must provide one as an
        argument.

        For a well-formatted TOC, it's recommended to leave
        `use_default_styles` as True.

        Args:
            document: The document to scan for titles.
                If not provided, the TOC must already be attached to a
                document.
            use_default_styles: If True, applies default styles to the
                TOC entries.
        """
        # Find the body
        if document is not None:
            body: Element | None = document.body
        else:
            body = self.document_body
        if body is None:
            raise ValueError("The TOC must be related to a document somehow")

        # Save the title
        index_body = self.body
        if index_body is None:
            title = None
        else:
            title = cast(
                None | IndexTitle, index_body.get_element(IndexTitle._tag)
            )

        # Clean the old index-body
        self.body = None  # this ceates a new index_body
        index_body = cast(IndexBody, self.body)

        # Restore the title
        if title and str(title):
            index_body.insert(title, position=0)

        # Insert default TOC style
        if use_default_styles:
            automatic_styles = body.get_element("//office:automatic-styles")
            if isinstance(automatic_styles, Element):  # pragma: nocover
                for level in range(1, 11):
                    if (
                        automatic_styles.get_style(
                            "paragraph", _toc_entry_style_name(level)
                        )
                        is None
                    ):
                        level_style = default_toc_level_style(level)
                        automatic_styles.append(level_style)

        # Auto-fill the index
        outline_level = self.outline_level or 10
        level_indexes: dict[int, int] = {}
        for header in body.headers:
            level = header.get_attribute_integer("text:outline-level") or 0
            if level > outline_level:
                continue
            number_str = self._header_numbering(level_indexes, level)
            # Make the title with "1.2.3. Title" format
            paragraph = Element.from_tag("text:p")
            paragraph.append_plain_text(f"{number_str} {header}")  # type: ignore[attr-defined]
            if use_default_styles:
                paragraph.style = _toc_entry_style_name(level)  # type: ignore[attr-defined]
            index_body.append(paragraph)

_properties class-attribute instance-attribute

_properties = (
    PropDef("name", "text:name"),
    PropDef("style", "text:style-name"),
    PropDef("xml_id", "xml:id"),
    PropDef("protected", "text:protected"),
    PropDef("protection_key", "text:protection-key"),
    PropDef(
        "protection_key_digest_algorithm",
        "text:protection-key-digest-algorithm",
    ),
)

_tag class-attribute instance-attribute

_tag = 'text:table-of-content'

body property writable

body: IndexBody | None

The body of the TOC (‘text:index-body’).

This property provides access to the ‘text:index-body’ element, which contains the actual entries of the table of contents.

name instance-attribute

name = f'{title}1'

outline_level property writable

outline_level: int | None

The outline level of the TOC.

This property controls the maximum heading level that will be included in the table of contents. A value of 0 means all levels are included.

protected instance-attribute

protected = protected

style instance-attribute

style = style

__init__

__init__(
    title: str = "Table of Contents",
    name: str | None = None,
    protected: bool = True,
    outline_level: int = 0,
    style: str | None = None,
    title_style: str = "Contents_20_Heading",
    entry_style: str = "Contents_20_%d",
    **kwargs: Any,
) -> None

Initializes a TOC (Table of Contents) element.

Default parameters are what most people use: protected from manual modifications and not limited in title levels.

The name is mandatory and derived automatically from the title if not given. Provide one in case of a conflict with other TOCs in the same document.

Parameters:

Name Type Description Default
title str

The title of the TOC (e.g., “Table of Contents”).

'Table of Contents'
name str | None

The name of the TOC element. If not provided, it’s generated from the title.

None
protected bool

If True, the TOC is protected from manual modifications.

True
outline_level int

The maximum outline level to include in the TOC. 0 means all levels.

0
style str | None

The style name for the TOC container.

None
title_style str

The style for the TOC’s main title.

'Contents_20_Heading'
entry_style str

A format string for the style of each TOC entry (e.g., “Contents_20_%d”).

'Contents_20_%d'
Source code in odfdo/toc.py
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
def __init__(
    self,
    title: str = "Table of Contents",
    name: str | None = None,
    protected: bool = True,
    outline_level: int = 0,
    style: str | None = None,
    title_style: str = "Contents_20_Heading",
    entry_style: str = "Contents_20_%d",
    **kwargs: Any,
) -> None:
    """Initializes a TOC (Table of Contents) element.

    Default parameters are what most people use: protected from manual
    modifications and not limited in title levels.

    The name is mandatory and derived automatically from the title if not
    given. Provide one in case of a conflict with other TOCs in the same
    document.

    Args:
        title: The title of the TOC (e.g., "Table of Contents").
        name: The name of the TOC element. If not
            provided, it's generated from the title.
        protected: If True, the TOC is protected from manual
            modifications.
        outline_level: The maximum outline level to include in the
            TOC. 0 means all levels.
        style: The style name for the TOC container.
        title_style: The style for the TOC's main title.
        entry_style: A format string for the style of each TOC
            entry (e.g., "Contents_20_%d").
    """
    super().__init__(**kwargs)
    if self._do_init:
        if style:
            self.style = style
        if protected:
            self.protected = protected
        if name is None:
            self.name = f"{title}1"
        # Create the source template
        toc_source = self.create_toc_source(
            title, outline_level, title_style, entry_style
        )
        self.append(toc_source)
        # Create the index body automatically with the index title
        if title:
            # This style is in the template document
            self.set_toc_title(title, text_style=title_style)

__str__

__str__() -> str
Source code in odfdo/toc.py
289
290
def __str__(self) -> str:
    return self.get_formatted_text()

_header_numbering staticmethod

_header_numbering(
    level_indexes: dict[int, int], level: int
) -> str

Return the header hierarchical number (like “1.2.3.”).

Parameters:

Name Type Description Default
level_indexes dict[int, int]

A dictionary to track numbering at each level.

required
level int

The current header level.

required

Returns:

Name Type Description
str str

The hierarchical number string.

Source code in odfdo/toc.py
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
@staticmethod
def _header_numbering(level_indexes: dict[int, int], level: int) -> str:
    """Return the header hierarchical number (like "1.2.3.").

    Args:
        level_indexes: A dictionary to track numbering
            at each level.
        level: The current header level.

    Returns:
        str: The hierarchical number string.
    """
    numbers: list[int] = []
    # before header level
    for idx in range(1, level):
        numbers.append(level_indexes.setdefault(idx, 1))
    # header level
    index = level_indexes.get(level, 0) + 1
    level_indexes[level] = index
    numbers.append(index)
    # after header level
    idx = level + 1
    while idx in level_indexes:
        del level_indexes[idx]
        idx += 1
    return ".".join(str(x) for x in numbers) + "."

create_toc_source staticmethod

create_toc_source(
    title: str,
    outline_level: int,
    title_style: str,
    entry_style: str,
) -> Element

Create the ‘text:table-of-content-source’ element for a TOC.

This element defines the structure and appearance of the TOC.

Parameters:

Name Type Description Default
title str

The title of the TOC.

required
outline_level int

The maximum outline level to include.

required
title_style str

The style for the TOC’s title.

required
entry_style str

The format string for entry styles.

required

Returns:

Name Type Description
Element Element

The newly created ‘text:table-of-content-source’ element.

Source code in odfdo/toc.py
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
@staticmethod
def create_toc_source(
    title: str,
    outline_level: int,
    title_style: str,
    entry_style: str,
) -> Element:
    """Create the 'text:table-of-content-source' element for a TOC.

    This element defines the structure and appearance of the TOC.

    Args:
        title: The title of the TOC.
        outline_level: The maximum outline level to include.
        title_style: The style for the TOC's title.
        entry_style: The format string for entry styles.

    Returns:
        Element: The newly created 'text:table-of-content-source'
            element.
    """
    toc_source = Element.from_tag("text:table-of-content-source")
    toc_source.set_attribute("text:outline-level", str(outline_level))
    if title:
        title_template = IndexTitleTemplate()
        if title_style:
            # This style is in the template document
            title_template.style = title_style
        title_template.text = title
        toc_source.append(title_template)
    for level in range(1, 11):
        template = TocEntryTemplate(outline_level=level)
        if entry_style:
            template.style = entry_style % level
        toc_source.append(template)
    return toc_source

fill

fill(
    document: Document | None = None,
    use_default_styles: bool = True,
) -> None

Fill the TOC with titles from the document.

This method populates the table of contents by scanning the document for headers. It is not contextual and will include all titles from the document, regardless of their position relative to the TOC.

If the TOC is not yet part of a document, you must provide one as an argument.

For a well-formatted TOC, it’s recommended to leave use_default_styles as True.

Parameters:

Name Type Description Default
document Document | None

The document to scan for titles. If not provided, the TOC must already be attached to a document.

None
use_default_styles bool

If True, applies default styles to the TOC entries.

True
Source code in odfdo/toc.py
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
def fill(
    self,
    document: Document | None = None,
    use_default_styles: bool = True,
) -> None:
    """Fill the TOC with titles from the document.

    This method populates the table of contents by scanning the document
    for headers. It is not contextual and will include all titles from
    the document, regardless of their position relative to the TOC.

    If the TOC is not yet part of a document, you must provide one as an
    argument.

    For a well-formatted TOC, it's recommended to leave
    `use_default_styles` as True.

    Args:
        document: The document to scan for titles.
            If not provided, the TOC must already be attached to a
            document.
        use_default_styles: If True, applies default styles to the
            TOC entries.
    """
    # Find the body
    if document is not None:
        body: Element | None = document.body
    else:
        body = self.document_body
    if body is None:
        raise ValueError("The TOC must be related to a document somehow")

    # Save the title
    index_body = self.body
    if index_body is None:
        title = None
    else:
        title = cast(
            None | IndexTitle, index_body.get_element(IndexTitle._tag)
        )

    # Clean the old index-body
    self.body = None  # this ceates a new index_body
    index_body = cast(IndexBody, self.body)

    # Restore the title
    if title and str(title):
        index_body.insert(title, position=0)

    # Insert default TOC style
    if use_default_styles:
        automatic_styles = body.get_element("//office:automatic-styles")
        if isinstance(automatic_styles, Element):  # pragma: nocover
            for level in range(1, 11):
                if (
                    automatic_styles.get_style(
                        "paragraph", _toc_entry_style_name(level)
                    )
                    is None
                ):
                    level_style = default_toc_level_style(level)
                    automatic_styles.append(level_style)

    # Auto-fill the index
    outline_level = self.outline_level or 10
    level_indexes: dict[int, int] = {}
    for header in body.headers:
        level = header.get_attribute_integer("text:outline-level") or 0
        if level > outline_level:
            continue
        number_str = self._header_numbering(level_indexes, level)
        # Make the title with "1.2.3. Title" format
        paragraph = Element.from_tag("text:p")
        paragraph.append_plain_text(f"{number_str} {header}")  # type: ignore[attr-defined]
        if use_default_styles:
            paragraph.style = _toc_entry_style_name(level)  # type: ignore[attr-defined]
        index_body.append(paragraph)

get_formatted_text

get_formatted_text(context: dict | None = None) -> str

Returns the formatted text content of the TOC.

Parameters:

Name Type Description Default
context dict | None

A context dictionary for formatting. If ‘rst_mode’ is True, it returns a reStructuredText ‘contents’ directive.

None

Returns:

Name Type Description
str str

The formatted text of the TOC.

Source code in odfdo/toc.py
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
def get_formatted_text(self, context: dict | None = None) -> str:
    """Returns the formatted text content of the TOC.

    Args:
        context: A context dictionary for formatting.
            If 'rst_mode' is True, it returns a reStructuredText
            'contents' directive.

    Returns:
        str: The formatted text of the TOC.
    """
    index_body = cast(None | IndexBody, self.get_element(IndexBody._tag))

    if index_body is None:
        return ""
    if context is None:
        context = {}
    if context.get("rst_mode"):
        return "\n.. contents::\n\n"

    result = []
    for element in index_body.children:
        if element.tag == "text:index-title":
            for child_element in element.children:
                result.append(child_element.get_formatted_text(context).strip())
        else:
            result.append(element.get_formatted_text(context).strip())
    return "\n".join(x for x in result if x)

get_title

get_title() -> str

Returns the title of the TOC.

Returns:

Name Type Description
str str

The title of the TOC.

Source code in odfdo/toc.py
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
def get_title(self) -> str:
    """Returns the title of the TOC.

    Returns:
        str: The title of the TOC.
    """
    index_body = self.body
    if index_body is None:
        return ""
    index_title = cast(
        None | IndexTitle, index_body.get_element(IndexTitle._tag)
    )
    if index_title is None:
        return ""
    return index_title.text_content

set_toc_title

set_toc_title(
    title: str,
    style: str | None = None,
    text_style: str | None = None,
) -> None

Sets the title of the TOC.

Parameters:

Name Type Description Default
title str

The new title for the TOC.

required
style str | None

The style for the index title element.

None
text_style str | None

The style for the title’s paragraph.

None
Source code in odfdo/toc.py
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
def set_toc_title(
    self,
    title: str,
    style: str | None = None,
    text_style: str | None = None,
) -> None:
    """Sets the title of the TOC.

    Args:
        title: The new title for the TOC.
        style: The style for the index title element.
        text_style: The style for the title's paragraph.
    """
    index_body = self.body
    if index_body is None:
        self.body = None  # this ceates a new index_body
        index_body = cast(IndexBody, self.body)
    index_title = cast(
        None | IndexTitle, index_body.get_element(IndexTitle._tag)
    )
    if index_title:
        style = style or index_title.style
        if not text_style:
            index_title_paragraph = index_title.get_element("text:p")
            if index_title_paragraph:
                text_style = index_title_paragraph.style  # type: ignore[attr-defined]
        name = index_title.name
        index_title.delete()
    else:
        name = f"{self.name}_Head"
    index_title = IndexTitle(
        name=name, style=style, title_text=title, text_style=text_style
    )
    index_body.append(index_title)

TabStopStyle

Bases: Element

Style for a tab-stop in a TOC entry, represented by “style:tab-stop”.

This class defines the visual properties of tab stops, such as their position, alignment, and leader style.

Attributes:

Name Type Description
style_char str

The character used for the tab stop.

leader_color str

The color of the leader line.

leader_style str

The style of the leader line (e.g., ‘dotted’, ‘solid’).

leader_text str

The text to use as a leader.

leader_text_style str

The style of the leader text.

leader_type str

The type of leader (e.g., ‘none’, ‘solid’).

leader_width str

The width of the leader line.

style_position str

The position of the tab stop (e.g., ‘1.25cm’).

style_type str

The alignment type of the tab stop (e.g., ‘left’, ‘right’).

Methods:

Name Description
__init__

Initializes a TabStopStyle element.

Source code in odfdo/toc.py
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
class TabStopStyle(Element):
    """Style for a tab-stop in a TOC entry, represented by "style:tab-stop".

    This class defines the visual properties of tab stops, such as their
    position, alignment, and leader style.

    Attributes:
        style_char (str, optional): The character used for the tab stop.
        leader_color (str, optional): The color of the leader line.
        leader_style (str, optional): The style of the leader line (e.g.,
            'dotted', 'solid').
        leader_text (str, optional): The text to use as a leader.
        leader_text_style (str, optional): The style of the leader text.
        leader_type (str, optional): The type of leader (e.g., 'none',
            'solid').
        leader_width (str, optional): The width of the leader line.
        style_position (str, optional): The position of the tab stop (e.g.,
            '1.25cm').
        style_type (str, optional): The alignment type of the tab stop
            (e.g., 'left', 'right').
    """

    _tag = "style:tab-stop"
    _properties = (
        PropDef("style_char", "style:char"),
        PropDef("leader_color", "style:leader-color"),
        PropDef("leader_style", "style:leader-style"),
        PropDef("leader_text", "style:leader-text"),
        PropDef("leader_text_style", "style:leader-text-style"),
        PropDef("leader_type", "style:leader-type"),
        PropDef("leader_width", "style:leader-width"),
        PropDef("style_position", "style:position"),
        PropDef("style_type", "style:type"),
    )

    def __init__(
        self,
        style_char: str | None = None,
        leader_color: str | None = None,
        leader_style: str | None = None,
        leader_text: str | None = None,
        leader_text_style: str | None = None,
        leader_type: str | None = None,
        leader_width: str | None = None,
        style_position: str | None = None,
        style_type: str | None = None,
        **kwargs: Any,
    ):
        """Initializes a TabStopStyle element.

        Args:
            style_char: The character for the tab stop.
            leader_color: Color of the leader line.
            leader_style: Style of the leader line.
            leader_text: Text to use as a leader.
            leader_text_style: Style of the leader text.
            leader_type: Type of leader.
            leader_width: Width of the leader line.
            style_position: Position of the tab stop.
            style_type: Alignment type of the tab stop.
        """
        super().__init__(**kwargs)
        if self._do_init:
            if style_char:
                self.style_char = style_char
            if leader_color:
                self.leader_color = leader_color
            if leader_style:
                self.leader_style = leader_style
            if leader_text:
                self.leader_text = leader_text
            if leader_text_style:
                self.leader_text_style = leader_text_style
            if leader_type:
                self.leader_type = leader_type
            if leader_width:
                self.leader_width = leader_width
            if style_position:
                self.style_position = style_position
            if style_type:
                self.style_type = style_type
        else:
            pass  # pragma: nocover

_properties class-attribute instance-attribute

_properties = (
    PropDef("style_char", "style:char"),
    PropDef("leader_color", "style:leader-color"),
    PropDef("leader_style", "style:leader-style"),
    PropDef("leader_text", "style:leader-text"),
    PropDef("leader_text_style", "style:leader-text-style"),
    PropDef("leader_type", "style:leader-type"),
    PropDef("leader_width", "style:leader-width"),
    PropDef("style_position", "style:position"),
    PropDef("style_type", "style:type"),
)

_tag class-attribute instance-attribute

_tag = 'style:tab-stop'

leader_color instance-attribute

leader_color = leader_color

leader_style instance-attribute

leader_style = leader_style

leader_text instance-attribute

leader_text = leader_text

leader_text_style instance-attribute

leader_text_style = leader_text_style

leader_type instance-attribute

leader_type = leader_type

leader_width instance-attribute

leader_width = leader_width

style_char instance-attribute

style_char = style_char

style_position instance-attribute

style_position = style_position

style_type instance-attribute

style_type = style_type

__init__

__init__(
    style_char: str | None = None,
    leader_color: str | None = None,
    leader_style: str | None = None,
    leader_text: str | None = None,
    leader_text_style: str | None = None,
    leader_type: str | None = None,
    leader_width: str | None = None,
    style_position: str | None = None,
    style_type: str | None = None,
    **kwargs: Any,
)

Initializes a TabStopStyle element.

Parameters:

Name Type Description Default
style_char str | None

The character for the tab stop.

None
leader_color str | None

Color of the leader line.

None
leader_style str | None

Style of the leader line.

None
leader_text str | None

Text to use as a leader.

None
leader_text_style str | None

Style of the leader text.

None
leader_type str | None

Type of leader.

None
leader_width str | None

Width of the leader line.

None
style_position str | None

Position of the tab stop.

None
style_type str | None

Alignment type of the tab stop.

None
Source code in odfdo/toc.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def __init__(
    self,
    style_char: str | None = None,
    leader_color: str | None = None,
    leader_style: str | None = None,
    leader_text: str | None = None,
    leader_text_style: str | None = None,
    leader_type: str | None = None,
    leader_width: str | None = None,
    style_position: str | None = None,
    style_type: str | None = None,
    **kwargs: Any,
):
    """Initializes a TabStopStyle element.

    Args:
        style_char: The character for the tab stop.
        leader_color: Color of the leader line.
        leader_style: Style of the leader line.
        leader_text: Text to use as a leader.
        leader_text_style: Style of the leader text.
        leader_type: Type of leader.
        leader_width: Width of the leader line.
        style_position: Position of the tab stop.
        style_type: Alignment type of the tab stop.
    """
    super().__init__(**kwargs)
    if self._do_init:
        if style_char:
            self.style_char = style_char
        if leader_color:
            self.leader_color = leader_color
        if leader_style:
            self.leader_style = leader_style
        if leader_text:
            self.leader_text = leader_text
        if leader_text_style:
            self.leader_text_style = leader_text_style
        if leader_type:
            self.leader_type = leader_type
        if leader_width:
            self.leader_width = leader_width
        if style_position:
            self.style_position = style_position
        if style_type:
            self.style_type = style_type
    else:
        pass  # pragma: nocover

TocEntryTemplate

Bases: Element

Template for a TOC entry, “text:table-of-content-entry-template”.

This element defines the structure for each entry in the table of contents, specifying what information is displayed (e.g., chapter number, text, page number) and how it is styled.

Attributes:

Name Type Description
style str

The style name for the entry.

Methods:

Name Description
__init__

Initializes a TocEntryTemplate element.

complete_defaults

Populates the template with default entry elements.

Source code in odfdo/toc.py
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
class TocEntryTemplate(Element):
    """Template for a TOC entry, "text:table-of-content-entry-template".

    This element defines the structure for each entry in the table of
    contents, specifying what information is displayed (e.g., chapter number,
    text, page number) and how it is styled.

    Attributes:
        style (str, optional): The style name for the entry.
    """

    _tag = "text:table-of-content-entry-template"
    _properties = (PropDef("style", "text:style-name"),)

    def __init__(
        self,
        style: str | None = None,
        outline_level: int | None = None,
        **kwargs: Any,
    ) -> None:
        """Initializes a TocEntryTemplate element.

        Args:
            style: The style name for the TOC entry.
            outline_level: The outline level this template
                applies to.
        """
        super().__init__(**kwargs)
        if self._do_init:
            if style:
                self.style = style
            if outline_level:
                self.outline_level = outline_level

    @property
    def outline_level(self) -> int | None:
        """The outline level this template applies to."""
        return self.get_attribute_integer("text:outline-level")

    @outline_level.setter
    def outline_level(self, level: int) -> None:
        self.set_attribute("text:outline-level", str(level))

    def complete_defaults(self) -> None:
        """Populates the template with default entry elements.

        This method adds standard elements to the template, such as placeholders
        for chapter number, entry text, and page number, providing a default
        structure for a TOC entry.
        """
        self.append(Element.from_tag("text:index-entry-chapter"))
        self.append(Element.from_tag("text:index-entry-text"))
        self.append(Element.from_tag("text:index-entry-text"))
        ts = Element.from_tag("text:index-entry-text")
        ts.set_style_attribute("style:type", "right")
        ts.set_style_attribute("style:leader-char", ".")
        self.append(ts)
        self.append(Element.from_tag("text:index-entry-page-number"))

_properties class-attribute instance-attribute

_properties = (PropDef('style', 'text:style-name'),)

_tag class-attribute instance-attribute

_tag = 'text:table-of-content-entry-template'

outline_level property writable

outline_level: int | None

The outline level this template applies to.

style instance-attribute

style = style

__init__

__init__(
    style: str | None = None,
    outline_level: int | None = None,
    **kwargs: Any,
) -> None

Initializes a TocEntryTemplate element.

Parameters:

Name Type Description Default
style str | None

The style name for the TOC entry.

None
outline_level int | None

The outline level this template applies to.

None
Source code in odfdo/toc.py
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
def __init__(
    self,
    style: str | None = None,
    outline_level: int | None = None,
    **kwargs: Any,
) -> None:
    """Initializes a TocEntryTemplate element.

    Args:
        style: The style name for the TOC entry.
        outline_level: The outline level this template
            applies to.
    """
    super().__init__(**kwargs)
    if self._do_init:
        if style:
            self.style = style
        if outline_level:
            self.outline_level = outline_level

complete_defaults

complete_defaults() -> None

Populates the template with default entry elements.

This method adds standard elements to the template, such as placeholders for chapter number, entry text, and page number, providing a default structure for a TOC entry.

Source code in odfdo/toc.py
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
def complete_defaults(self) -> None:
    """Populates the template with default entry elements.

    This method adds standard elements to the template, such as placeholders
    for chapter number, entry text, and page number, providing a default
    structure for a TOC entry.
    """
    self.append(Element.from_tag("text:index-entry-chapter"))
    self.append(Element.from_tag("text:index-entry-text"))
    self.append(Element.from_tag("text:index-entry-text"))
    ts = Element.from_tag("text:index-entry-text")
    ts.set_style_attribute("style:type", "right")
    ts.set_style_attribute("style:leader-char", ".")
    self.append(ts)
    self.append(Element.from_tag("text:index-entry-page-number"))

_toc_entry_style_name

_toc_entry_style_name(level: int) -> str

Return the style name of an entry of the TOC.

Parameters:

Name Type Description Default
level int

The outline level of the TOC entry.

required

Returns:

Name Type Description
str str

The generated style name.

Source code in odfdo/toc.py
41
42
43
44
45
46
47
48
49
50
def _toc_entry_style_name(level: int) -> str:
    """Return the style name of an entry of the TOC.

    Args:
        level: The outline level of the TOC entry.

    Returns:
        str: The generated style name.
    """
    return f"odfto_toc_level_{level}"

default_toc_level_style

default_toc_level_style(level: int) -> Style

Generate an automatic default style for the given TOC level.

Parameters:

Name Type Description Default
level int

The outline level for which to create the style.

required

Returns:

Name Type Description
Style Style

The generated style for the TOC level.

Source code in odfdo/toc.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
def default_toc_level_style(level: int) -> Style:
    """Generate an automatic default style for the given TOC level.

    Args:
        level: The outline level for which to create the style.

    Returns:
        Style: The generated style for the TOC level.
    """
    tab_stop = TabStopStyle(style_type="right", leader_style="dotted", leader_text=".")
    position = 17.5 - (0.5 * level)
    tab_stop.style_position = f"{position}cm"
    tab_stops = Element.from_tag("style:tab-stops")
    tab_stops.append(tab_stop)
    properties = Element.from_tag("style:paragraph-properties")
    properties.append(tab_stops)
    toc_style_level = Style(
        family="paragraph",
        name=_toc_entry_style_name(level),
        parent_style=f"Contents_20_{level}",
    )
    toc_style_level.append(properties)
    return toc_style_level