Python macro: insert bookmarks at placeholders

Hello everyone !

My problem is quite simple. My OO Writer document has a few beacons that look like {bookmark:NAME}. For each beacon found in the doc, I want to create a bookmark with the name NAME at the beacon’s position, then erase the beacon.

Here is my closest solution:

import re

def Finalize():
    ActiveDocument = XSCRIPTCONTEXT.getDocument()
    ImportDocuments(ActiveDocument)

    # Create bookmarks
    searchBookmarks = ActiveDocument.createSearchDescriptor()
    searchBookmarks.SearchString = "\{bookmark:.*\}"
    searchBookmarks.SearchRegularExpression = True
    searchBookmarks.SearchAll = True
    searchBookmarks.SearchCaseSensitive = True
    searchBookmarks.SearchWords = False

    bookmarksFound = ActiveDocument.findAll(searchBookmarks)

    for bookmarkIndex in range(0, bookmarksFound.getCount()):
        bookmarkFound = bookmarksFound.getByIndex(bookmarkIndex)
        bookmarkName = re.sub(r'{bookmark:(.*)}', r'\1', bookmarkFound.getString())
        bookmark = ActiveDocument.createInstance("com.sun.star.text.Bookmark")
        bookmark.setName(bookmarkName)
        ActiveDocument.Text.insertTextContent(bookmarkFound, bookmark, True)

def ImportDocument(ActiveDocument):
    pathname = os.path.dirname(ActiveDocument.getURL())
    importCursor = ActiveDocument.Text.createTextCursor()

    search = ActiveDocument.createSearchDescriptor()
    search.SearchString = "\{includetext:.*\}"
    search.SearchRegularExpression = True
    search.SearchAll = True
    search.SearchCaseSensitive = True
    search.SearchWords = False

    selsFound = ActiveDocument.findAll(search)

    while selsFound.getCount() > 0:
        for selIndex in range(0, selsFound.getCount()):
            selFound = selsFound.getByIndex(selIndex)
            importCursor.gotoRange(selFound, False)
            filename = re.sub(r'{includetext:(.*)}', r'\1', selFound.getString())
            filename = filename.replace("${path}", pathname)
            
            importCursor.insertDocumentFromURL(filename, ())

        selsFound = SearchRegex(ActiveDocument, "\{includetext:.*\}")
    importCursor.gotoStart(False)

The problem is I really struggle with XTextRange type and cursors, LO throws a RuntimeException saying “text interface and cursor not related” at the insertTextContent call. Do you have any idea ?

Thanks a lot

the following works so far:

import re

def set_bookmarks():
    doc = XSCRIPTCONTEXT.getDocument()
    print(f"{doc.Title = }")
    # search patterns 
    searchBookmarks = doc.createSearchDescriptor()
    searchBookmarks.SearchString = "\{bookmark:.*?\}"
    searchBookmarks.SearchRegularExpression = True
    searchBookmarks.SearchAll = True
    searchBookmarks.SearchCaseSensitive = True
    searchBookmarks.SearchWords = False
    
    bookmarks = doc.findAll(searchBookmarks)
    for pattern in bookmarks:
        # create bookmarks
        print(pattern.String)
        name = re.sub(r'{bookmark:\s*?(.*)}', r'\1', pattern.String)
        bookmark = doc.createInstance("com.sun.star.text.Bookmark")
        bookmark.setName(name)
        doc.Text.insertTextContent(pattern, bookmark, True) 

Hallo
To replace also the patterns {bookmark: some_name} with some_name :

import re

def set_bookmarks():
    doc = XSCRIPTCONTEXT.getDocument()
    print(f"{doc.Title = }")
    # search patterns 
    searchBookmarks = doc.createReplaceDescriptor() ##!!
    searchBookmarks.SearchString = "\{bookmark:\s*(.*?)\}"
    searchBookmarks.SearchRegularExpression = True
    searchBookmarks.SearchAll = True
    searchBookmarks.SearchCaseSensitive = True
    searchBookmarks.SearchWords = False
    searchBookmarks.setReplaceString("$1")
    
    bookmarks = doc.findAll(searchBookmarks)
    for pattern in bookmarks:
        name = re.sub(r'{bookmark:\s*?(.*)}', r'\1', pattern.String)
        bookmark = doc.createInstance("com.sun.star.text.Bookmark")
        bookmark.setName(name)
        doc.Text.insertTextContent(pattern, bookmark, True) 
    #and last:
    doc.replaceAll(searchBookmarks)

Thank you for your answer. It seems that my problem is a bit trickier than I thought in the first place: I completed my first post with more operations that I’m actually doing in my real code. The first step is to import other text documents with the same beacons principle ({includetext:path/to/document}). To insert documents, I’m using a cursor, which is messing up with my bookmarks stuff, giving me the RuntimeException from the first post

ThisComponent.Text.insertTextContent() isn’t functional for example in TextTables.

def Finalize():
    ActiveDocument = XSCRIPTCONTEXT.getDocument()

    # Create bookmarks
    searchBookmarks = ActiveDocument.createSearchDescriptor()
    searchBookmarks.SearchString = "\{bookmark:.*\}"
    searchBookmarks.SearchRegularExpression = True
    searchBookmarks.SearchAll = True
    searchBookmarks.SearchCaseSensitive = True
    searchBookmarks.SearchWords = False


    bookmarksFound = ActiveDocument.findAll(searchBookmarks)

    for x in bookmarksFound:
        bookmarkName = re.sub(r'{bookmark:(.*)}', r'\1', x.getString())
        bookmark = ActiveDocument.createInstance("com.sun.star.text.Bookmark")
        bookmark.setName(bookmarkName)
        x.Text.insertTextContent(x.Start, bookmark, True)
1 Like

Indeed I had lots of bookmarks in tables ! Thank you very much :tada: