How do I create a `ott' template that includes "default" style definitions; by "default" styles, I mean ALL the "factory styles" that ship with a LibreOffice install

Goal

To get a copy of the styles.xml that contains ALL OF DEFAULT LO styles (= “factory styles”)

Attachments

Untitled 1.ott (7.9 KB)

Styles that are saved in Untitled 1.ott

I am attaching an “Untitled 1.ott” which was created by saving an Untitled 1.odt as an ott file. When I examine the styles in the resulting Untitled 1.ott, I see only these

  • Arial
  • Caption
  • Heading
  • Index
  • List
  • Lohit Devanagari
  • Lohit Devanagari1
  • Mpm1
  • Noto Sans CJK SC
  • Noto Serif CJK SC
  • Outline
  • Standard
  • Standard
  • Text_20_body
  • Times New Roman

(Above list is created by parsing the styles.xml embedded within Untitled 1.ott; the list included font face styles as well)

I was hoping to capture ALL THE FACTORY STYLES that LibreOffice ships in the ott file. I was specifically interested in seeing the XML definitions of ALL OF THE FACTORY STYLES.


Additional Note 1

I know that if a create some sample text in the ott file, and apply the default LO style on that text, the resulting styles.xml will have “capture” the style in the styles.xm

But this process is limiting and tedious for my purpose. What I want is a complete dump of all default styles—paragraph, character, list, frame, page, table template, table cell—in a styles.xml without having to “create sample text, apply style, grok the style” workflow.

FWIW, I am the author of the Emacs Org-mode Markup to OpenDocument Text exporter / converter.

So, I am asking this question as a developer who wants to ship the default LO styles as part of my own converter’s factory styles.

Additional Note 2

My converter dates back as far back as Year 2010; I remember creating my converter’s styles just a few months prior LO forked off-of OpenOffice. The list styles that I use are “legacy” list styles, and I want to upgrade the “List” styles to the “modern” ones.

Legacy list styles Vs Modern list styles

Legacy List Styles (in Lisp data format)

(text:list-style ((style:name . "OrgBulletedList"))
		 (text:list-level-style-bullet
		  ((text:level . "1")
		   (text:style-name . "Bullet_20_Symbols")
		   (style:num-suffix . ".")
		   (text:bullet-char . "•"))
		  (style:list-level-properties
		   ((text:space-before . "0.635cm")
		    (text:min-label-width . "0.635cm")))
		  (style:text-properties
		   ((fo:font-family . "StarSymbol")
		    (style:font-charset . "x-symbol"))))
		 (text:list-level-style-bullet
		  ((text:level . "2")
		   (text:style-name . "Bullet_20_Symbols")
		   (style:num-suffix . ".")
		   (text:bullet-char . "•"))
		  (style:list-level-properties
		   ((text:space-before . "1.27cm")
		    (text:min-label-width . "0.635cm")))
		  (style:text-properties
		   ((fo:font-family . "StarSymbol")
		    (style:font-charset . "x-symbol"))))
		 ...)

Modern “List” style in Lisp format

(text:list-style
 ((style:name . "List_20_1")
  (style:display-name . "List 1"))
 (text:list-level-style-bullet
  ((text:level . "1")
   (text:style-name . "Numbering_20_Symbols")
   (text:bullet-char . "•"))
  (style:list-level-properties
   ((text:list-level-position-and-space-mode . "label-alignment"))
   (style:list-level-label-alignment
    ((text:label-followed-by . "listtab")
     (text:list-tab-stop-position . "0.4cm")
     (fo:text-indent . "-0.4cm")
     (fo:margin-left . "0.4cm"))))
  (style:text-properties ((style:font-name . "OpenSymbol"))))
 (text:list-level-style-bullet
  ((text:level . "2")
   (text:style-name . "Numbering_20_Symbols")
   (text:bullet-char . "•"))
  (style:list-level-properties
   ((text:list-level-position-and-space-mode . "label-alignment"))
   (style:list-level-label-alignment
    ((text:label-followed-by . "listtab")
     (text:list-tab-stop-position . "0.801cm")
     (fo:text-indent . "-0.4cm")
     (fo:margin-left . "0.801cm"))))
  (style:text-properties
   ((style:font-name . "OpenSymbol"))))
 ...)

There is no built-in way of doing that. The export filter exports things conditionally, based on the default styles being modified and/or used. Likely the only way is to change the source code of LibreOffice.

I searched for List_20_1 in LibreOffice's codebase with https://github.com/search?q=org%3ALibreOffice%20List_20_1&type=code and the first hit seems like a good start (atleast to my untrained eye)

extras/source/templates/styles/Simple/styles.xml

If I download the styles.xml from the Simple styles how good an approximation it would be to the default factory style.

There are 35 hits for List_20_1 (the display name for List 1 style) on GitHub search

I am sure the default factory styles are a mish-mash of XML fragments with some fixups here and there. For example, different locales will have different default Standard paragraph styles based etc … For example, for en_IN locale the default paragraph style goes something like

(style:text-properties
 ((style:use-window-font-color . "true")
  (fo:font-size . "12pt")
  (fo:language . "en")
  (fo:country . "GB")
  (style:letter-kerning . "true")
  (style:font-size-asian . "12pt")
  (style:language-asian . "zh")
  (style:country-asian . "CN")
  (style:font-size-complex . "12pt")
  (style:language-complex . "hi")
  (style:country-complex . "IN")))


If the pancake is NOT readily available on a platter, can you help me with the ingredients and a recipe so that I can make the pancake myself.

I am sure I can mash up the different XML pieces together with Emacs. (I don’t want to checkout or build LibreOffice. My humble laptop wouldn’t give me such a privilege)

Even a slight hint on what the bulk of the XML definitions come from will do … if possible, some hint on which of the 35 different directory that I can focus on for assembling the fragments …

Thanks in advance.

What you see is a source for one of the bundled templates. It is not what is built in and used when you don’t use any template… I’d not rely on those XMLs being accurate in reflecting our defaults.

If some macro coder would generate a dummy document with all styles applied, would it contain the wanted styles.xml?

1 Like

I think so. But wouldn’t it be simple to create a document containing as many empty paragraphs as built-in styles? Then apply a style on every paragraph.
Unfortunately this doesn’t provide definitions for character styles which as as much important as paragraph styles. There as also page styles. The procedure would be to enter page breaks to switch to another page style.
A similar approach would insert frames onto which you apply a frame style.
To get list styles, create as many paragraphs as list style count. Manually apply a list style to a paragraph. I am not sure if empty paragraphs could do because I noticed some odd behaviour with them (read: I have not fully understood all the subtleties when you erase things in a list item).

When this “support document” is done, save it preciously for future use with new LO releases.

Start with a Default paragraph having all the char style names in their respective char style.
Then create paragraphs with their para style names. Finish the first paragraphs with page breaks until page styles are used up.
I have no idea how list stlyes actually work (I don’t really like working with Writer). However, there should be some way to create at least one XML entry for each one of them. Table styles are hard coded in macro code. Frame styles may be of lesser interest?

ODT File with all the Factory Styes

vanilla-styles.odt (39.1 KB)

PDF version of the above file

vanilla-styles.pdf (545.2 KB)

Recipe for creating the above ODT document

Sub CreateODTFileWithAllFactoryStyles
    Dim inDoc                    
    Dim interactive
    ' BasicLibraries.loadLibrary("XrayTool")
    ' LoadMriLibrary

    Dim oProps(0) as New com.sun.star.beans.PropertyValue
    oProps(0).Name = "Hidden"
    oProps(0).Value = False

    inDoc = StarDesktop.loadComponentFromURL( "private:factory/swriter", "_blank", 0, Array() )
    fileURL = ConvertToURL("/home/kjambunathan/vanilla-styles.odt")

    oText = inDoc.getText()
    oCursor = oText.createTextCursor()
    styleFamilies = inDoc.StyleFamilies
    styleFamilyNames = styleFamilies.getElementNames()
    ' For each StyleFamily
    For i = 0 To UBound(styleFamilyNames)
        styleFamilyName = styleFamilyNames(i)
        styleFamily = inDoc.StyleFamilies.getByName(styleFamilyNames(i))
        styleNames = styleFamily.getElementNames()

        oText.insertString(oCursor, "--- BEGIN STYLE FAMILY `" & styleFamilyName & "' ---", False)
        oText.insertString( oCursor, styleFamilyName, False )
        oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
        ' For each StyleName in StyleFamily
        For j = 0 To UBound(styleNames)
            styleName = styleNames(j)
            oCursor.CharWeight = com.sun.star.awt.FontWeight.NORMAL
            If styleFamilyName = "CharacterStyles" Then
                If j <> -1 Then
                    oCursor.CharStyleName = styleName
                    oText.insertString( oCursor, styleName, False )
                    oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                End If
            ElseIf styleFamilyName = "ParagraphStyles" Then
                oCursor.ParaStyleName = styleName
                oText.insertString( oCursor, styleName, False )
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
            ElseIf styleFamilyName = "NumberingStyles" Then
                bodyText = styleName
                oText.insertString( oCursor, bodyText, False )
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                nCount = 5
                For k = 0 To nCount
                    oCursor.NumberingLevel = k
                    oCursor.NumberingStyleName = styleName
                    bodyText = styleName & "[Level " & k & "]"
                    oText.insertString( oCursor, bodyText, False )
                    oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                Next k
                oCursor.NumberingLevel = 0
                oCursor.NumberingStyleName = ""
            ElseIf styleFamilyName = "CellStyles" Then
                If j <> -1 Then
                    xxx = inDoc.StyleFamilies.getByIndex(i).getByIndex(j)
                    If j = -1 Then
                        MsgBox "MRI-ing " & styleName
                        Mri xxx
                    End If
                    oTable = inDoc.createInstance( "com.sun.star.text.TextTable" )
                    oTable.initialize(1, 1) 'Single Cell
                    oTable.TableName = styleName
                    oInsertPoint = ThisComponent.Text.getEnd()
                    oInsertPoint.getText().insertTextContent(oInsertPoint , oTable, False)
                    oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                    oTableCell = oTable.getCellByPosition(0,0)
                    oTableCell.setString(styleName & " {" & styleFamilyName & "}")
                    ' TODO: Don't know how to associate oTableCell with the corresponding xxx
                    If j = -1 Then
                        MsgBox "MRI-ing Writer TabeCell"
                        Mri oTableCell
                    End If
                End If
            ElseIf styleFamilyName = "TableStyles" Then
                If j = -1 Then
                    MsgBox "Examining " & styleName
                    ' xray styleFamily.getByname(styleName)
                End If
                If j <> -1 Then
                    oCursor.ParaStyleName = "Caption"
                    oText.insertString( oCursor, styleName, False )
                    oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                    oTable = inDoc.createInstance( "com.sun.star.text.TextTable" )
                    oTable.initialize(6, 6) 'Two rows, three columns
                    oTable.TableName = styleName
                    ' Setting "TableTemplateName" doesn't give fancy tables
                    ' oTable.setPropertyValue("TableTemplateName", styleName)
                    oInsertPoint = ThisComponent.Text.getEnd()
                    oInsertPoint.getText().insertTextContent(oInsertPoint , oTable, False)
                    ' Invoking `autoformat' gives a fancy table, but
                    ' the Table Template definition doesn't land in
                    ' the `styles.xml'.
                    '  oTable.autoformat(styleName)
                    oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                    oTableCell = oTable.getCellByPosition(0,0)
                    oTableCell.setString(styleName & " {" & styleFamilyName & "}")
                End If
            ElseIf styleFamilyName = "FrameStyles" Then
                If j <> -1 Then
                    oFrame = ThisComponent.createInstance( "com.sun.star.text.TextFrame" )
                    oText.insertTextContent( oCursor, oFrame, false )
                    oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                    oFrame.Text.String = styleName & "[" & styleFamilyName & "]"
                    oFrame.FrameStyleName = styleName
                    oFrame.Name = styleName
                End If
            ElseIf styleFamilyName = "PageStyles" Then
                If j <> -1 Then
                    oText.insertString(oCursor, "" & styleName & "[" & styleFamilyName & "]", False)
                    oCursor.PageDescName = styleName
                    oCursor.breakType = com.sun.star.style.BreakType.PAGE_BEFORE
                    oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                End If
            Else
                ' MsgBox "You haven't handled " & styleName & "[" & styleFamilyName & "]"
                oCursor.ParaStyleName = "Standard"
                oText.insertString( oCursor, styleName & " {" & styleFamilyName & "}", False )
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
            End If
        Next j
        oText.insertString(oCursor, "--- END STYLE FAMILY `" & styleFamilyName & "' ---", False)
        oCursor.breakType = com.sun.star.style.BreakType.PAGE_AFTER
        oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
    Next i
    ApplyTableTemplates()
    If (inDoc.isModified() AND inDoc.hasLocation() AND (Not inDoc.isReadOnly())) Then
        inDoc.store()
    End If
    Dim xProps(0) as New com.sun.star.beans.PropertyValue
    xProps(0).Name = "Overwrite"
    xProps(0).Value = True
    inDoc.storeAsUrl(fileURL, xProps)
End Sub

Sub ApplyTableTemplate(templateName)
    dim document   as object
    dim dispatcher as object

    document   = ThisComponent.CurrentController.Frame
    dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

    dim args1(1) as new com.sun.star.beans.PropertyValue
    args1(0).Name = "Template"
    args1(0).Value = templateName
    args1(1).Name = "Family"
    args1(1).Value = 32
    dispatcher.executeDispatch(document, ".uno:StyleApply", "", 0, args1())
End Sub

Sub ApplyTableTemplates
    inDoc = ThisComponent
    oTables = inDoc.getTextTables()
    If oTables.hasElements() Then
        For i = 0 To oTables.getCount() - 1
            oTable = oTables.getByIndex(i)
            inDoc.getCurrentController().select(oTable)
            ApplyTableTemplate(oTable.Name)
        Next
    End If
End Sub


3 Likes

Why only 5 levels? I would very much assume that you don’t even need 5 - you could likely have a single paragraph of that numbering style, with level 1. Possibly I’m wrong - but then you would need all 10 of them?

Six levels actually. From 0 to 5.

1 Like

I am mostly interested in the XML definitions of the style … and my Emacs Org-mode to ODT converter typesets things slightly different than what you would get if you were to use LibreOffice by hand.

Thanks for catching this … I have to replace 5 with whatever is the count of NumberingRules.

I faced 3 numbers of issues with applying a cell style to text table cell (=writer table cell).

  1. Invoking autoformat works, but the following XML element doesn’t get dumped to styles.xml
(table:table-template
 ((table:first-row-end-column . "row")
  (table:first-row-start-column . "row")
  (table:last-row-end-column . "row")
  (table:last-row-start-column . "row") (table:name . "Box List Blue"))
 (table:first-row ((table:style-name . "Box_20_List_20_Blue.1")))
 (table:last-row ((table:style-name . "Box_20_List_20_Blue.2")))
 (table:first-column ((table:style-name . "Box_20_List_20_Blue.3")))
 (table:last-column ((table:style-name . "Box_20_List_20_Blue.4")))
 (table:body ((table:style-name . "Box_20_List_20_Blue.9")))
 (table:even-rows ((table:style-name . "Box_20_List_20_Blue.5")))
 (table:odd-rows ((table:style-name . "Box_20_List_20_Blue.6")))
 (table:even-columns ((table:style-name . "Box_20_List_20_Blue.7")))
 (table:odd-columns ((table:style-name . "Box_20_List_20_Blue.8")))
 (table:background ((table:style-name . "Box_20_List_20_Blue.10")))
 (loext:first-row-even-column
  ((table:style-name . "Box_20_List_20_Blue.15")))
 (loext:last-row-even-column
  ((table:style-name . "Box_20_List_20_Blue.16")))
 (loext:first-row-end-column
  ((table:style-name . "Box_20_List_20_Blue.12")))
 (loext:first-row-start-column
  ((table:style-name . "Box_20_List_20_Blue.11")))
 (loext:last-row-end-column
  ((table:style-name . "Box_20_List_20_Blue.14")))
 (loext:last-row-start-column
  ((table:style-name . "Box_20_List_20_Blue.13"))))
  1. Setting TableTemplateName property on the table cell, doesn’t prettify the table

  2. I have finally settled for autoformat of the table.

There are breadcrumbs for (1) and (2) in the Basic snippet I posted earlier.


I would have preferred to apply a cell style that comes from CellStyles to a writer cell. (The autoformat etc will not capture a cell style that is NOT part of a Table Template. In the vanilla styles, all the cell styles come from the table template definitions. So the ODT file I shared is complete for vanilla LO styles)

UNSOLVED MYSTERY: How does one apply a cell style to a writer table cell

I did run in to issues applying a Cell Style to a Text Table Cell (= WriterCell). This is because the writer table cell doesn’t have CellStyle property (only calc cells have CellStyle property).

CellProperties Service Reference (LibreOffice 7.4 SDK API Reference) and there are two references to CellStyle

cell-style

Here is a visual representation of where I am stuck … and I would appreciate any help. (FWIW, I have both xray and MRI installed, and have some passing familiarity with it)



Moderators please DO NOT close the thread … Even though I have marked the above response as a SOLUTION, I do have one more (half-baked) SOLUTION and additional questions / remarks.

I will update this thread tomorrow …

I’m quite surprised by the result. Which exact LO release did you dump? Have you customised the styles in your default template?

In Character styles, I am not aware of Endnote Symbol nor Footnote Symbol. Is standard Bullets renamed Bullet Symbols? In recent releases (don’t remember from which), Standard has been renamed No Character Style.

The list of paragraph styles is rather difficult to follow because it is not sorted alphabetically. But I have no Salutation (=Complmentary Close?)

Similarly, Standard is now Default Page Style.

Graphics frame style is hidden by some other frame. At first I thought it was missing.

List styles List n are now named Bullet z.
I didn’t know there were cell styles but since so called table “styles” are not traditional Writer styles (I consider them, perhaps erroneously, as a set of macro, it might be a by-product of the implementation.

LibreOffice - 24.2 … This is a daily build only a few months old

Version: 24.2.0.0.alpha0+ (X86_64) / LibreOffice Community
Build ID: 5fecd865303b3f0a2eeb0b9466d2bcf23cfce068
CPU threads: 4; OS: Linux 6.4; UI render: default; VCL: gtk3
Locale: de-AT (en_IN); UI: en-US
Calc: threaded

Have you customised the styles in your default template?

I ran the macro in Safe Mode. So, whatever is in the local config, shouldn’t have made its way through

… but since so called table “styles” are not traditional Writer styles (I consider them, perhaps erroneously, as a set of macro, it might be a by-product of the implementation.

The table templates–banding row/col style, first/last row/col cell styles–are very much part of v1.2 spec. It was there in ODF standard even some 8-10 years ago.

Here is a link to the rnc file which defines table template https://github.com/kjambunathan/org-mode-ox-odt/blob/6fb4a7feb264e27006da922780c037f2eb6d8649/etc/schema/odf1.2/OpenDocument-v1.2-os-schema.rnc#L1350

(The above rnc file is a verbatim copy of what OASIS distributes)

You can compare what is in the rnc file with the lisp-ified version of Box List Blue style which I shared earlier. (You can see some loext elements which are LibreOffice-only extensions to ODF markup)

LO 5.3: The “Table Autoformat” feature was extended from one-time formatting only to a full-featured table style. Import and export of ODF table styles.

LibreOffice Design Team: Style your tables (Historic Notes)

The basic mechanics for ODF-compatible styling of tables was always there in LibreOffice, but the style definitions itself – <table:table-template ... table:name= "Box List Blue">...</table:table-template> --made its way in to styles.xml of LibreOffice recently. Unfortunately, I am unable to locate the entry from ReleaseNotes which formally blessed the application of table styles through TableTemplateName

Text table cells have no CellStyles. Spreadsheet cells have.

You may check how the style information is actually stored in the (F)ODT.

Say, you apply Academic table style to a table.

Indeed, the Academic.* cell styles (and other table-related styles) get saved to the file’s styles. But when you look at the styles applied to real tables in the document, you would see that:

  1. Tables are assigned autostyles (like Table1), and those autostyles do not reference table styles;
  2. Table columns are assigned autostyles (like Table1.A), and those autostyles do not reference column styles;
  3. Table rows are assigned autostyles (like Table1.1), and those autostyles do not reference row styles;
  4. Table cells are assigned autostyles (like Table1.A1), and those autostyles do not reference cell styles.

The Academic proper table style itself references the Academic.* column, row, and cell styles in different sub-elements; and - as @ajlittoz explains it, it all works roughly as if there was a “macro” (actually, some event handler), that applies the properties stored in the styles, as direct formatting to the actual tables, when some editing operations happen in the document.

It all is kludges all around, so - in the reality, we indeed have the proper table styles provisioned in the file format, but we don’t have the proper table style mechanism in the program.

And that explains why you fail to apply cell styles to cells. It simply doesn’t work properly, as @Villeroy mentioned - yes, for now we don’t have “cell style” support in Writer table cells.

1 Like

You can download all the artefacts included in this comment from Bug 158728: Feature Request: Add a facility to create a `ott’ template that includes ALL the “default” style definitions; .

You can also download vanilla-odt-styles.pdf. (I was not able to upload the pdf in this thread file due to restriction on attachment sizes)


The attached file vanilla-odt-styles.odt contains all vanilla styles available on my LO installation

vanilla-odt-styles.odt (60.4 KB)

The odt file contains

  1. a TOC of style families and associated styles
  2. an alphabetical index of style families and associated styles

The above odt file is created in Safe Mode, on following version of LibreOffice

Version: 24.2.0.0.alpha0+ (X86_64) / LibreOffice Community
Build ID: 2a217a80bf383ddab0a5e0959ab2fd907dfd3406
CPU threads: 4; OS: Linux 6.4; UI render: default; VCL: gtk3
Locale: en-IN (en_IN); UI: en-US
Calc: threaded

Here is a Basic script used to create the above odt file … The main entry point is CreateODTFileWithAllFactoryStyles. (Link: https://github.com/kjambunathan/org-mode-ox-odt/blob/eaef4ea87d671fbf601ba3f3aa6784931eccd59f/contrib/odt/LibreOffice/src/OrgModeUtilities.bas#L287)


Sub CreateIndexMark(oText, oCursor, bodyText, primaryKey, markEntry, alphaIndex)
    oText.insertString( oCursor, bodyText, True )
    ' Create Index Mark
    indexMark = ThisComponent.createInstance("com.sun.star.text.DocumentIndexMark")
    indexMark.PrimaryKey = primaryKey
    ' markEntry = bodyText
    indexMark.setMarkEntry(markEntry)
    ' Insert the Index Mark
    oText.InsertTextContent(oCursor, indexMark, False)
    ' No more text range
    oCursor.collapseToEnd()
End Sub

Function RepeatText(text, times)
    bigText = ""
    For i = 0 To times
        bigText = bigText & text
    Next i
    RepeatText = bigText
End Function

Function AnchoringParaText(i, Optional n)
    text = ""
    Select Case i

    Case 0:
        text = " xxxxxxxx yyyyyyyy"
        If IsMissing(n) Then
            n = 9
        End If
    Case 1:
        text = " aaaaaaaa bbbbbbbb"
        If IsMissing(n) Then
            n = 15
        End If
    Case Else
        text = "Id amet, velit fugiat sunt mollit dolor. Fugiat laborum deserunt cillum aliqua magna voluptate mollit. Nulla in qui ad elit, duis sit sit. Dolor et cupidatat in eiusmod ex. Occaecat culpa dolor et magna sed do culpa. "
        If IsMissing(n) Then
            n = 1
        End If
    End Select
    AnchoringParaText = RepeatText(text, n)
End Function

Sub AddPageNumber
    Doc = ThisComponent

    PageNumber = Doc.createInstance("com.sun.star.text.textfield.PageNumber")
    PageNumber.NumberingType = com.sun.star.style.NumberingType.ARABIC

    PageStyles = Doc.StyleFamilies.getByName("PageStyles")

    StdPage = PageStyles("Default")
    StdPage.FooterIsOn = True

    FooterCursor = StdPage.FooterTextLeft.Text.createTextCursor()
    FooterCursor.ParaAdjust = com.sun.star.style.ParagraphAdjust.CENTER
    StdPage.FooterTextLeft.Text.insertTextContent(FooterCursor, PageNumber, False)
End Sub

Sub ApplyTableTemplate(templateName)
    dim document   as object
    dim dispatcher as object

    document   = ThisComponent.CurrentController.Frame
    dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

    dim args1(1) as new com.sun.star.beans.PropertyValue
    args1(0).Name = "Template"
    args1(0).Value = templateName
    args1(1).Name = "Family"
    args1(1).Value = 32
    dispatcher.executeDispatch(document, ".uno:StyleApply", "", 0, args1())
End Sub

Sub ApplyTableTemplates
    inDoc = ThisComponent
    oTables = inDoc.getTextTables()
    If oTables.hasElements() Then
        For i = 0 To oTables.getCount() - 1
            oTable = oTables.getByIndex(i)
            inDoc.getCurrentController().select(oTable)
            ApplyTableTemplate(oTable.Name)
        Next
    End If
End Sub

Sub CreateODTFileWithAllFactoryStyles
    Dim inDoc
    Dim interactive
    ' BasicLibraries.loadLibrary("XrayTool")
    ' LoadMriLibrary()
    ' BasicLibraries.loadLibrary("MRILib")
    Dim oProps(0) as New com.sun.star.beans.PropertyValue
    oProps(0).Name = "Hidden"
    oProps(0).Value = False
    inDoc = StarDesktop.loadComponentFromURL( "private:factory/swriter", "_blank", 0, Array() )
    fileURL = ConvertToURL("/home/kjambunathan/vanilla-styles.odt")

    AddPageNumber()

    StyleFamilies = inDoc.StyleFamilies
    ParagraphStyles = StyleFamilies.getByName("ParagraphStyles")

    ' Create a Paragraph Style for Family Style Names and Insert it in
    ' to the StyleSheet
    myFamilyStyle = inDoc.createInstance("com.sun.star.style.ParagraphStyle")
    myFamilyStyle.Name = "My Family Style"
    myFamilyStyle.CharColor = RGB(255, 0, 0)
    myFamilyStyle.CharWeight = com.sun.star.awt.FontWeight.BOLD
    ParagraphStyles.insertByName("My Family Style", myFamilyStyle)

    ' Create a Paragraph Style for Style Names and Insert it in
    ' to the StyleSheet
    myStyle = inDoc.createInstance("com.sun.star.style.ParagraphStyle")
    myStyle.Name = "My Style"
    myStyle.CharColor = RGB(6, 154, 46)
    myStyle.CharWeight = com.sun.star.awt.FontWeight.BOLD

    ParagraphStyles.insertByName("My Style", myStyle)

    ' Obtain Text and Text Cursor
    oText = inDoc.getText()
    oCursor = oText.createTextCursor()

    ' Create and Configure TOC
    toc = inDoc.createInstance("com.sun.star.text.ContentIndex")
    toc.Title = "Table of Style Families & Styles"
    toc.CreateFromOutline = False
    toc.CreateFromLevelParagraphStyles = True
    oText.insertTextContent(oCursor, toc, False)

    oLevelParagraphStyles = toc.LevelParagraphStyles
    oLevelParagraphStyles.replaceByIndex(0, Array("My Family Style"))
    oLevelParagraphStyles.replaceByIndex(1, Array("My Style"))

    ' Create an Alphbhetical Index of Style Families & Style Names
    ' userIndex =  inDoc.createInstance("com.sun.star.text.UserIndex")
    ' userIndex.CreateFromMarks = True

    alphaIndex = ThisComponent.createInstance("com.sun.star.text.DocumentIndex")
    alphaIndex.UseCombinedEntries = False
    oText.insertTextContent(oCursor, alphaIndex, FALSE)

    ' Create Dummy User Index Marks

    styleFamilyNames = inDoc.StyleFamilies.getElementNames()

    ' For each StyleFamily
    For i = LBound(styleFamilyNames) To UBound(styleFamilyNames)
        styleFamilyName = styleFamilyNames(i)

        styleNames = inDoc.StyleFamilies.getByName(styleFamilyName).getElementNames()

        oText.insertString( oCursor, "STYLE FAMILY: " & styleFamilyName, False )
        oCursor.ParaStyleName = "My Family Style"
        oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
        oCursor.ParaStyleName = "Standard"

        ' For each StyleName in StyleFamily
        For j = LBound(styleNames) To UBound(styleNames)

            styleName = styleNames(j)
            xxx = inDoc.StyleFamilies.getByName(styleFamilyName).getByName(styleName)
            oCursor.CharWeight = com.sun.star.awt.FontWeight.NORMAL
            ' Print styleFamilyName & ": " & styleName
            ' oCursor.CharStyleName = "Standard"

            Select Case styleFamilyName
            Case "PageStyles":
            Case Else
                CreateIndexMark(oText, oCursor, "", styleFamilyName, styleName, alphaIndex)
            End Select

            Select Case styleFamilyName
            Case "CharacterStyles":
                ' Insert Style Name
                oCursor.CharStyleName = styleName
                oCursor.ParaStyleName = "My Style"

                oText.insertString( oCursor, styleName, False )
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )

                oCursor.CharStyleName = "Standard"
            Case "ParagraphStyles":

                ' Insert Style Name
                oCursor.ParaStyleName = "My Style"

                oText.insertString( oCursor, styleName, False )
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )

                oCursor.ParaStyleName = "Standard"

                ' Insert a big Paragraph
                oCursor.ParaStyleName = styleName
                oText.insertString( oCursor, AnchoringParaText(2), False )
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                oCursor.ParaStyleName = "Standard"

            Case "NumberingStyles":

                bodyText = styleName

                ' Insert Style Name
                oCursor.ParaStyleName = "My Style"
                oText.insertString( oCursor, bodyText, False )
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                oCursor.ParaStyleName = "Standard"

                nCount = xxx.NumberingRules.getCount()
                For k = 0 To nCount - 1
                    oCursor.NumberingLevel = k
                    oCursor.NumberingStyleName = styleName

                    oCursor.CharColor = RGB(0,0,255)
                    bodyText = styleName & " [Level " & k & "]"
                    oText.insertString( oCursor, bodyText, True )
                    ' oCursor.CharStyleName = "Standard"

                    oCursor.collapseToEnd()

                    oCursor.CharStyleName = "Standard"

                    bodyText = " " & AnchoringParaText(2)
                    oText.insertString( oCursor, bodyText, False )

                    oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                Next k
                oCursor.NumberingLevel = 0
                oCursor.NumberingStyleName = ""
                oCursor.ParaStyleName = "Standard"

            Case "CellStyles1":
                oTable = inDoc.createInstance( "com.sun.star.text.TextTable" )
                oTable.initialize(1, 1) 'Single Cell
                oTable.TableName = styleName
                oInsertPoint = ThisComponent.Text.getEnd()
                oInsertPoint.getText().insertTextContent(oInsertPoint , oTable, False)
                oCursor.ParaStyleName = "My Style"
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                oTableCell = oTable.getCellByPosition(0,0)
                oTableCell.setString(styleName & " {" & styleFamilyName & "}")
                ' TODO: Don't know how to associate oTableCell with the corresponding xxx
            Case "TableStyles":
                oCursor.ParaStyleName = "My Style"
                oText.insertString( oCursor, styleName, False )
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                oCursor.ParaStyleName = "Standard"

                oTable = inDoc.createInstance( "com.sun.star.text.TextTable" )
                oTable.initialize(6, 6) 'Two rows, three columns
                oTable.TableName = styleName
                ' Setting "TableTemplateName" doesn't give fancy tables
                ' oTable.setPropertyValue("TableTemplateName", styleName)
                oInsertPoint = ThisComponent.Text.getEnd()
                oInsertPoint.getText().insertTextContent(oInsertPoint , oTable, False)
                ' Invoking `autoformat' gives a fancy table, but
                ' the Table Template definition doesn't land in
                ' the `styles.xml'.
                '  oTable.autoformat(styleName)
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                oTableCell = oTable.getCellByPosition(0,0)
                oTableCell.setString(styleName & " {" & styleFamilyName & "}")
            Case "FrameStyles":

                ' Push the style
                oCursor.ParaStyleName = "My Style"

                ' Caption the Frame, and style it with 'My Style'
                ' Emit LineBreaks around the caption to create some breathing space.
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.LINE_BREAK, False )
                oText.insertString( oCursor,   styleName & " {" & styleFamilyName & "}", False )
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.LINE_BREAK, False )

                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )

                ' Pop the style
                oCursor.ParaStyleName = "Standard"

                ' Insert some text before the Frame
                bodyText = "^^^PARA BEGIN: " & styleName & AnchoringParaText(0) & RepeatText("+", 8)
                oText.insertString( oCursor, bodyText , False )

                ' Create and Insert the Text Frame
                oFrame = ThisComponent.createInstance( "com.sun.star.text.TextFrame" )
                oText.insertTextContent( oCursor, oFrame, false )

                ' Insert some text after the Frame
                bodyText = RepeatText("-", 8) + AnchoringParaText(1) & styleName & " :PARA END$$$$"
                oText.insertString(oCursor, bodyText, False)

                ' Insert Paragraph Break
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )

                ' Configure the Frame
                oFrame.FrameStyleName = styleName
                oFrame.Name = styleName
                If j = -1 Then
                    xray oFrame
                End If
                oFrame.Width = 4000

                ' Fill the Frame
                annotation = ""
                If oFrame.AnchorType = com.sun.star.text.TextContentAnchorType.AT_PARAGRAPH Then
                    annotation = annotation & " [" &  styleName & "@at-paragraph" &  "]"
                ElseIf oFrame.AnchorType = com.sun.star.text.TextContentAnchorType.AS_CHARACTER Then
                    annotation = annotation & " [" &  styleName & "@as-character" &  "]"
                ElseIf oFrame.AnchorType = com.sun.star.text.TextContentAnchorType.AT_PAGE Then
                    annotation = annotation & " [" &  styleName & "@at-page" &  "]"
                ElseIf oFrame.AnchorType = com.sun.star.text.TextContentAnchorType.AT_FRAME Then
                    annotation = annotation & " [" &  styleName & "@at-frame" &  "]"
                ElseIf oFrame.AnchorType = com.sun.star.text.TextContentAnchorType.AT_CHARACTER Then
                    annotation = annotation & " [" &  styleName & "@at-character" &  "]"
                Else
                    MsgBox "This shouldn't happen"
                End If

                oFrame.BackColor = RGB(255, 255, 215)
                oFrame.Text.String = RepeatText(annotation, 2)
            Case "PageStyles":
                oText.insertString(oCursor, "" & styleName & " {" & styleFamilyName & "}", False)
                oCursor.PageDescName = styleName
                oCursor.ParaStyleName = "My Style"
                oCursor.breakType = com.sun.star.style.BreakType.PAGE_BEFORE
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
                oCursor.ParaStyleName = "Standard"
                oCursor.PageDescName = "Standard"

                CreateIndexMark(oText, oCursor, "", styleFamilyName, styleName, alphaIndex)
                ' oText.insertString( oCursor, styleName & " {" & styleFamilyName & "}", False )
                ' oCursor.ParaStyleName = "My Style"
            Case Else
                ' MsgBox "You haven't handled " & styleName & "[" & styleFamilyName & "]"
                oCursor.ParaStyleName = "My Style"
                oText.insertString( oCursor, styleName & " {" & styleFamilyName & "}", False )
                oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
            End Select

        Next j
        oText.insertString(oCursor, "--- END STYLE FAMILY `" & styleFamilyName & "' ---", False)
        oCursor.breakType = com.sun.star.style.BreakType.PAGE_AFTER
        oText.insertControlCharacter( oCursor, com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK, False )
    Next i
    ApplyTableTemplates()
    If (inDoc.isModified() AND inDoc.hasLocation() AND (Not inDoc.isReadOnly())) Then
        inDoc.store()
    End If
    Dim xProps(0) as New com.sun.star.beans.PropertyValue
    xProps(0).Name = "Overwrite"
    xProps(0).Value = True
    ' inDoc.storeAsUrl(fileURL, xProps)
    toc.update()

    alphaIndex.update()

End Sub