Search code examples
pythonmacrosunolibreoffice-writer

How to read contents of a LibreOffice writer annotation from a python macro


LibreOffice writer allows the user to insert annotations(notes/comments) within the text.

My issue is I am unable to find a method to access the contents of a line specific annotation.
The following python code looks for selected/highlighted text and then strips out everything except a formatted time code (e.g. 01:10:23 or 11:10) which it converts into seconds.
If no text has been selected, it selects the entire current line and attempts to find the time code. However, the time code could be in an annotation.

I have managed to get a list of all of the annotations within the document, commented out at the start of the code but it is of no use to me.

I have been unable to discover a method of divining

a) whether the current line has an annotation or
b) how to access its contents.

If anyone has managed to achieve this, I'd appreciate any pointers.

def fs2_GoToTimestamp(*args):
#get the doc from the scripting context which is made available to all scripts
    desktop = XSCRIPTCONTEXT.getDesktop()
    model = desktop.getCurrentComponent()
    oSelected = model.getCurrentSelection()
#access annotations for the whole document
#    oEnum = model.getTextFields().createEnumeration()
#    cursor = desktop.getCurrentComponent().getCurrentController().getViewCursor()
#    while oEnum.hasMoreElements():
#        oField = oEnum.nextElement()
#        cursor.gotoRange(oField,False)
#        print (cursor.getPosition())
#        if oField.supportsService('com.sun.star.text.TextField.Annotation'):
#            print (oField.Content)
#            x = oField.getAnchor()
#            print (dir(x))
    oText = ""
    try: #Grab the text selected/highlighted
        oSel = oSelected.getByIndex(0)
        oText= oSel.getString()
    except:pass
    try:
        if oText == "": # Nothing selected grab the whole line
            cursor = desktop.getCurrentComponent().getCurrentController().getViewCursor()
            cursor.gotoStartOfLine(False) #move cursor to start without selecting (False)
            cursor.gotoEndOfLine(True) #now move cursor to end of line selecting all (True)
            oSelected = model.getCurrentSelection()
            oSel = oSelected.getByIndex(0)
            oText= oSel.getString()
            # Deselect line to avoid inadvertently deleting it on next keystroke
            cursor.gotoStartOfLine(False)
    except:pass
    time = str(oText)
    valid_chars=('0123456789:')
    time = ''.join(char for char in time if char in valid_chars)
    if time.count(":") == 1:
        oM, oS = time.split(":")
        oH = "00"
    elif time.count(":") == 2:
        oH,oM,oS = time.split(":")
    else:
        return None
    if len(oS) != 2:
        oS=oS[:2]
    try:
        secs = int(oS)
        secs = secs + int(oM) * 60
        secs = secs + int(oH) *3600
    except:
        return None
    seek_instruction = 'seek'+str(secs)+'\n'
    #Now do something with the seek instruction 

Solution

  • Enumerate the annotations and use getAnchor() to find out where each is located. This answer is based on https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Editing_Text#Text_Contents_Other_Than_Strings.

    Your code is close to working.

    while oEnum.hasMoreElements():
        oField = oEnum.nextElement()
        if oField.supportsService('com.sun.star.text.TextField.Annotation'):
            xTextRange = oField.getAnchor()
            cursor.gotoRange(xTextRange, False)
    

    Instead of print (dir(x)), an introspection tool such as XrayTool or MRI will give better information. It makes the API docs easier to figure out.