Search code examples
javaopenoffice-writeruno

How to check if a bookmark contains a table?


Is it possible to determine when a Bookmark contains a TextTable? I thought about looking through XTextRange objects, however, the documentation does not specify anything about comparing ranges.


Solution

  • So starting with the following code:

    XBookmarksSupplier xBookmarksSupplier =
        (XBookmarksSupplier)UnoRuntime.queryInterface(
        XBookmarksSupplier.class, xComponent);
        XNameAccess xNamedBookmarks = xBookmarksSupplier.getBookmarks();
    Object bookmark = xNamedBookmarks.getByName("TextAndTable");
    XTextContent xBookmarkContent = (XTextContent)UnoRuntime.queryInterface(
        XTextContent.class, bookmark);
    XTextRange xTextRange = xBookmarkContent.getAnchor();
    

    It sounds like you are asking how to determine if there are one or more text tables that are located within the range specified by xTextRange.

    To do this, I normally use the View Cursor. It's slow, but a normal text cursor is not able to traverse different text objects, so it would fail if there are text tables or other objects within the range.

    Here is my Python class, which perhaps you can adapt to Java:

    def differentPlaces(oCurs1, oCurs2):
        """Test using compareRegion to see if two cursors are in different places.
        If compareRegion fails, such as after a nested table, return False.
        """
        try:
            oText = oCurs1.getText()
            return oText.compareRegionEnds(oCurs1, oCurs2) != 0
        except IllegalArgumentException:
            logger.info("Could not compare region.")
            return False
    
    class RangeCompare:
        """Compare the viewcursor to a text range (a location).
        Can be useful when traversing a cursor over a range.
        The range is expected not to be modified.
        """
        def __init__(self, rangeEnd, viewCursor):
            self.oVC = viewCursor
            self.rangeEnd = rangeEnd
            self.endX = -1
            self.endY = -1
    
        def getCoords(self):
            if self.endY > -1:
                return
            # remember where we were, because we'll need to use the viewcursor
            originalVC = self.oVC.getText().createTextCursorByRange(self.oVC)
    
            self.oVC.gotoRange(self.rangeEnd, False)
            self.endX = self.oVC.getPosition().X
            self.endY = self.oVC.getPosition().Y
    
            self.oVC.gotoRange(originalVC, False)
    
        def compareVC(self):
            """Compare the viewcursor to the range.
            Assume we are travelling with the viewcursor.
            See if it is up to the end yet or not.
            The comparison is done by checking the physical position of the cursor.
            Returns -1 if the VC location is less than self.rangeEnd, 0 if it is
            the same, and 1 if it is greater.
            Returns -2 if they are on the same line but not in the same spot, and
            it's not certain which location is greater.
            """
            self.getCoords()
            curX = self.oVC.getPosition().X
            curY = self.oVC.getPosition().Y
            if curY < self.endY:
                logger.debug("%d < %d", curY, self.endY)
                return -1
            elif curY > self.endY:
                logger.debug("%d > %d", curY, self.endY)
                return 1
            elif curY == self.endY:
                if curX == self.endX:
                    if differentPlaces(self.oVC, self.rangeEnd):
                        # There is probably a word-final diacritic that doesn't
                        # change the position, so we're not to the end yet.
                        logger.debug("Including word-final diacritic.")
                        return -2
                    # We're at the end.
                    logger.debug(
                        "VC same loc as text range (%d, %d).", curX, curY)
                    return 0
                else:
                    logger.debug("Probably haven't gone far enough.")
                    return -2
    

    Instantiate the class with something like rangeCompare = RangeCompare(xTextRange.getEnd(), xViewCursor).

    Move the view cursor to the start of xTextRange. Then keep calling xViewCursor.goRight(1, False) in a loop. Each time, check if the cursor is located in a TextTable. Stop when rangeCompare.compareVC() > 0.