1

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 
Rolf of Saxony
  • 21,661
  • 5
  • 39
  • 60
  • Enumerate the annotations and use [getAnchor()](https://www.openoffice.org/api/docs/common/ref/com/sun/star/text/XTextContent.html#getAnchor) to find out where each is located. See https://wiki.openoffice.org/wiki/Documentation/DevGuide/Text/Editing_Text#Text_Contents_Other_Than_Strings. – Jim K Jun 22 '17 at 20:22
  • Thanks for the reply. Perhaps it's me but I cannot find any method returned from either oField or oField.getAnchor() when I enumerate oEnum that provides a position for the annotation within the document. If I create a cursor and attempt to `gotoRange(oField,False)` it claims that there is no such interface. I've added my ill-conceived attempts to the question, in the hope that you can spot the glaring error. I'll admit to struggling with the API documentation, it's like swimming in treacle – Rolf of Saxony Jun 23 '17 at 08:18

2 Answers2

1

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.

Jim K
  • 12,824
  • 2
  • 22
  • 51
  • Being just millimetres away ultimately is the same as miles away. Thanks for the nudge in the right direction. I've posted the (final) version in a self answer for anyone else wading through this sort of thing. – – Rolf of Saxony Jun 24 '17 at 12:28
0

With much needed help from Jim K a self answer is posted below. I have commented where I believe it will help most.

#!/usr/bin/python
from com.sun.star.awt.MessageBoxButtons import BUTTONS_OK
from com.sun.star.awt.MessageBoxType import INFOBOX
def fs2_GoToTimestamp(*args):
    desktop = XSCRIPTCONTEXT.getDesktop()
    model = desktop.getCurrentComponent()
    oSelected = model.getCurrentSelection()
    doc = XSCRIPTCONTEXT.getDocument()
    parentwindow = doc.CurrentController.Frame.ContainerWindow
    cursor = desktop.getCurrentComponent().getCurrentController().getViewCursor()
    try:
        CursorPos = cursor.getText().createTextCursorByRange(cursor)#Store original cursor position
    except:# The cursor has been placed in the annotation not the text
        mess = "Position cursor in the text\nNot the comment box"
        heading = "Positioning Error"
        MessageBox(parentwindow, mess, heading, INFOBOX, BUTTONS_OK)
        return None
    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
            store_position = 0
            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()
            y = cursor.getPosition()
            store_position = y.value.Y
            # Deselect line to avoid inadvertently deleting it on next user keystroke
            cursor.gotoStartOfLine(False)

            if oText.count(":") == 0:
            # Still nothing found check for an annotation at this location
            #enumerate through annotations for the whole document
                oEnum = model.getTextFields().createEnumeration()
                while oEnum.hasMoreElements():
                    oField = oEnum.nextElement()
                    if oField.supportsService('com.sun.star.text.TextField.Annotation'):
                        anno_at = oField.getAnchor()
                        cursor.gotoRange(anno_at,False)
                        pos = cursor.getPosition()
                        if pos.value.Y == store_position: # Found an annotation at this location
                            oText = oField.Content
                            break
                # Re-set cursor to original position after enumeration & deselect
                cursor.gotoRange(CursorPos,False)
    except:pass

    time = str(oText)
    valid_chars=('0123456789:')
    time = ''.join(char for char in time if char in valid_chars) #Strip out all invalid characters
    if time.count(":") == 1: # time 00:00
        oM, oS = time.split(":")
        oH = "00"
    elif time.count(":") == 2: # time 00:00:00
        oH,oM,oS = time.split(":")
    else:
        return None
    if len(oS) != 2: # in case time includes tenths 00:00.0 reduce to whole seconds
        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'
    print("Seconds",str(secs))
    # Do something with seek_instruction

def MessageBox(ParentWindow, MsgText, MsgTitle, MsgType, MsgButtons):
    ctx = XSCRIPTCONTEXT.getComponentContext()
    sm = ctx.ServiceManager
    si = sm.createInstanceWithContext("com.sun.star.awt.Toolkit", ctx)
    mBox = si.createMessageBox(ParentWindow, MsgType, MsgButtons, MsgTitle, MsgText)
    mBox.execute() 
Rolf of Saxony
  • 21,661
  • 5
  • 39
  • 60