Trying to understand Anchors (XTextRange)

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
_savage
Posts: 187
Joined: Sun Apr 21, 2013 12:55 am

Trying to understand Anchors (XTextRange)

Post by _savage »

I'm trying to understand anchors.

If I look at my document then I can get an iterator over paragraphs and tables (through XTextContent), or an iterator over the graphic elements (through XShape). Both iterators are independent of each other. In both cases though, the elements I iterate over have an "Anchor" property, an XTextRange, and an "AnchorType" (link). It seems that the anchor type indicates how to interpret the anchor itself; for example a AT_PARAGRAPH means that "The anchor of the object is set at the top left position of the paragraph." But which one?

How do these anchors relate to each other, if they do at all? Is there a relative order of text ranges to each other, other than placement on a page?
Mac 10.14 using LO 7.2.0.2, Gentoo Linux using LO 7.2.3.2 headless.
B Marcelly
Volunteer
Posts: 1160
Joined: Mon Oct 08, 2007 1:26 am
Location: France, Paris area

Re: Trying to understand Anchors (XTextRange)

Post by B Marcelly »

Property Anchor points to the paragraph where the graphic is anchored.
From the paragraph, getText() returns the text the paragraph belongs to.
In the general case, this text may be the ordinary text you write, or the text inside a text frame, or the text inside a cell of a table, or the text of the left part of the header of the page, or in a Endnote, etc...
Furthermore you can for example have a frame inserted in the main text, and a table inside this frame.
Finding out where is the anchor is nearly impossible in the general case.
Bernard

OpenOffice.org 1.1.5 / Apache OpenOffice 4.1.1 / LibreOffice 5.0.5
MS-Windows 7 Home SP1
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Trying to understand Anchors (XTextRange)

Post by musikai »

B.Marcelly gives invaluable information.
Perhaps you might find some further infos in this thread:
viewtopic.php?f=20&t=80329&hilit=anchors

It uses equalunoobjects() to find out where an anchor is anchored in.
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
_savage
Posts: 187
Joined: Sun Apr 21, 2013 12:55 am

Re: Trying to understand Anchors (XTextRange)

Post by _savage »

musikai wrote:B.Marcelly gives invaluable information. Perhaps you might find some further infos in this thread:
viewtopic.php?f=20&t=80329&hilit=anchors
Thank you! The linked thread looks very much like what I'm after, I'll take a good look...
musikai wrote:It uses equalunoobjects() to find out where an anchor is anchored in.
I'm using Python. Any idea how to import this function, or in which module I can find it? There is some talk about equality of Uno structures in Python in the Python Bridge documentation, but not sure that's the right way to go.
Mac 10.14 using LO 7.2.0.2, Gentoo Linux using LO 7.2.3.2 headless.
User avatar
karolus
Volunteer
Posts: 1158
Joined: Sat Jul 02, 2011 9:47 am

Re: Trying to understand Anchors (XTextRange)

Post by karolus »

Hallo
_savage wrote:
musikai wrote:B.Marcelly gives invaluable information. Perhaps you might find some further infos in this thread:
viewtopic.php?f=20&t=80329&hilit=anchors
Thank you! The linked thread looks very much like what I'm after, I'll take a good look...
musikai wrote:It uses equalunoobjects() to find out where an anchor is anchored in.
I'm using Python. Any idea how to import this function, or in which module I can find it? There is some talk about equality of Uno structures in Python in the Python Bridge documentation, but not sure that's the right way to go.
in Python use `is`-keyword to test Object_Identity:

Code: Select all

if some_object is some_may_be_other_object: 
Karolus
AOO4, Libreoffice 6.1 on Rasbian OS (on ARM)
Libreoffice 7.4 on Debian 12 (Bookworm) (on RaspberryPI4)
Libreoffice 7.6 flatpak on Debian 12 (Bookworm) (on RaspberryPI4)
_savage
Posts: 187
Joined: Sun Apr 21, 2013 12:55 am

Re: Trying to understand Anchors (XTextRange)

Post by _savage »

I still can't quite get this right. For example, in the following code I iterate over all "shapes" (i.e. objects that implement the XShape interface) and I collect the following information: their anchor (i.e. object that implements the XTextRange interface), page number they're currently located on, and their bitmap (BMP, or DIB, device-independent bitmap) if there is one. Finding the page number for a text range as discussed in this thread.

Code: Select all

shape_list = [] # New empty list
shape_enum = document.DrawPage.createEnumeration()                           
while shape_enum.hasMoreElements():                                          
    shape = shape_enum.nextElement()                                         
    anchor = shape.Anchor                                                  
    pageno = get_page_no(anchor)                                          
    if hasattr(shape, "Graphic"):
        graphic = getattr(shape, "Graphic")
        bmp = graphic.DIB.value
    else:
        bmp = None
    shape_list.append( (anchor, pageno, bmp) )
Next I iterate over all paragraphs of a document, and I want to check which paragraph has a shape anchored on it. I can always compare the page numbers, but if possible I'd like to be more precise.

Code: Select all

par_enum = document.Text.createEnumeration()                                 
while par_enum.hasMoreElements():                                            
    par = parenum.nextElement()                                             
    pageno = get_page_no(par)
    # Iterate over all known shapes and find if one anchors to this paragraph.
    for shape_anchor, shape_pgno, shape_bmp in shape_list:
        if shape_anchor is par:
            print("Found a shape that anchors to this par!")
        if shape_pgno == pageno:
            print("Found a shape that anchors to the same page as this par!")
I am uncertain as to what I'm supposed to compare: that paragraph against the shape's anchor, or the parargaph's anchor against the shape's anchor? And how? Using the "is" keyword as suggested above doesn't seem to yield a match, and I can't find equalunoobjects() in Python's UNO bridge.

Another Python specific problem seems to be the AnchorType enum. How do I import it, and from where?

Code: Select all

from com.sun.star.beans import PropertyValue # Works
from com.sun.star.text import TextContentAnchorType # Fails
Above doesn't work, but it does work for e.g. importing the PropertyValue structure.
Mac 10.14 using LO 7.2.0.2, Gentoo Linux using LO 7.2.3.2 headless.
_savage
Posts: 187
Joined: Sun Apr 21, 2013 12:55 am

Re: Trying to understand Anchors (XTextRange)

Post by _savage »

For testing purposes I placed the following image into a document, and anchored it to the paragraph.
anchor.jpg
The AnchorType of the graphic object is AT_PARAGRAPH.

When I inspected the Anchor element itself I would have expected its getString() to return the paragraph's text "At the end...". However, it was empty, and the Anchor element doesn't support the com.sun.star.text.Paragraph service, which lets me to think that it's not actually a paragraph!
B Marcelly wrote:Property Anchor points to the paragraph where the graphic is anchored. From the paragraph, getText() returns the text the paragraph belongs to.
Do I compare the graphic's anchor with the paragraph itself, or with the paragraph's anchor? Neither seems to return a match.

Code: Select all

if par.Anchor is shape.Anchor # False
if par is shape.Anchor # False
What am I missing?
Mac 10.14 using LO 7.2.0.2, Gentoo Linux using LO 7.2.3.2 headless.
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Trying to understand Anchors (XTextRange)

Post by musikai »

I think you would compare Par.text with shape.Anchor. But this will only tell you if the shape is anchored in the same text as the paragraph is in. eg. both are in the same textframe. But you want a more precise information. So your idea of comparing pagenumbers is perhaps the way to go.
Little question: Do you get pagenumber infos when iterating over paragraphs? I thought pagenumber is only available to a viewcursor.

So perhaps you can get and compare some position y infos from the anchor with a paragraph if it has some.
Or: If you select the paragraph text range (via a textcursor) then you should be able to compare if the anchor is in the selected textrange with compareRegionStarts. This is what I did in my link above (but with a manual selection of the viewcursor)
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
_savage
Posts: 187
Joined: Sun Apr 21, 2013 12:55 am

Re: Trying to understand Anchors (XTextRange)

Post by _savage »

musikai wrote:Little question: Do you get pagenumber infos when iterating over paragraphs? I thought pagenumber is only available to a viewcursor.
I am using this helper function:

Code: Select all

    def get_page_no(textrange):                                                 
        cursor = controller.getViewCursor()                                     
        cursor.gotoRange(textrange, False)                                      
        return cursor.getPage()
and pass shape.Anchor or the paragraph itself. In both cases I get the page number of the element.

Thank you for your other tips, I'll see if I can find more precise information using the coordinates as you suggest. I guess that my interpretation of the meaning of the AT_PARAGRAPH anchor was wrong then?
Mac 10.14 using LO 7.2.0.2, Gentoo Linux using LO 7.2.3.2 headless.
_savage
Posts: 187
Joined: Sun Apr 21, 2013 12:55 am

Re: Trying to understand Anchors (XTextRange)

Post by _savage »

musikai wrote:So perhaps you can get and compare some position y infos from the anchor with a paragraph if it has some.
Interesting tip using the coordinates of the anchor's text view cursor. Turns out that that cursor's position is based off of the document's first page, so that paragraphs and graphics have fairly accurate and increasing Y coordinates. Assuming these positions are valid in all cases, that's a close-enough solution to tie a graphic to a paragraph.

Unfortunately, though, the coordinates of a graphics' anchor can be even on a different page than the graphics itself... :crazy:
Last edited by _savage on Wed Apr 13, 2016 8:00 pm, edited 1 time in total.
Mac 10.14 using LO 7.2.0.2, Gentoo Linux using LO 7.2.3.2 headless.
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Trying to understand Anchors (XTextRange)

Post by musikai »

Haha, sounds like oo is full of surprises. Btw what do you want your macro to do?
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
_savage
Posts: 187
Joined: Sun Apr 21, 2013 12:55 am

Re: Trying to understand Anchors (XTextRange)

Post by _savage »

musikai wrote:Haha, sounds like oo is full of surprises. Btw what do you want your macro to do?
I'd like to "linearize" the text content of a document and its images. I mean, iterate over all paragraphs and read them out, and if there is a graphic object next to the paragraph (whatever "next" means for AOO) then I'd like to extract that as well and tie/associate it with the closest text paragraph.
Mac 10.14 using LO 7.2.0.2, Gentoo Linux using LO 7.2.3.2 headless.
musikai
Volunteer
Posts: 294
Joined: Wed Nov 11, 2015 12:19 am

Re: Trying to understand Anchors (XTextRange)

Post by musikai »

Would that be different than switching to web-view?
Win7 Pro, Lubuntu 15.10, LO 4.4.7, OO 4.1.3
Free Project: LibreOffice Songbook Architect (LOSA)
http://struckkai.blogspot.de/2015/04/li ... itect.html
Post Reply