How to find a bookmark's parent bookmarks?

A

Andrew Sharpe

Given an instance of Microsoft.Office.Tools.Word.Bookmark, is there a way to
determine any surrounding bookmarks? I want to know all the bookmarks that
contain the range of a given bookmark.

Thoughts?
 
H

Helmut Weber

Hi Andrew,

like this, if I get You right:

Sub Test0023()
Dim oRng As Range ' range of given bookmark
Dim rTmp As Range ' range of bookmarks that contain oRng
Set rTmp = Selection.Range
Set oRng = ActiveDocument.Bookmarks("Mark1").Range
rTmp.SetRange oRng.Bookmarks(1).Start, _
oRng.Bookmarks(oRng.Bookmarks.Count).End
rTmp.Select
End Sub


--
Greetings from Bavaria, Germany

Helmut Weber, MVP WordVBA

Win XP, Office 2003
"red.sys" & Chr$(64) & "t-online.de"
 
J

Jay Freedman

Andrew said:
Given an instance of Microsoft.Office.Tools.Word.Bookmark, is there a
way to determine any surrounding bookmarks? I want to know all the
bookmarks that contain the range of a given bookmark.

Thoughts?

Use the InRange function like this, as you iterate through the Bookmarks
collection:

Dim firstBk As Bookmark, tryBk As Bookmark

Set firstBk = ActiveDocument.Bookmarks("bk3")

For Each tryBk In ActiveDocument.Bookmarks
If firstBk.Range.InRange(tryBk.Range) _
And (firstBk.Name <> tryBk.Name) Then
MsgBox firstBk.Name & " is inside " & tryBk.Name
End If
Next tryBk

Note that bookmarks that only partly overlap won't pass the test. That is,
if you have the sentence "The quick brown fox jumps over the lazy dog",
where bk1 covers "quick brown fox" and bk3 covers "fox jumps", then bk3
won't be considered to be inside bk1.
 
A

Andrew Sharpe

Thanks Jay. I was hoping there was an easier way then iterating through all
the bookmarks and checking InRange, because I need to know the hierarchy of
them as well, ie I need to know if A contains B, C contains A, etc. So I
will need to "sort" them afterward. But your suggestion will definitely
work, so thanks a lot for it.
 
J

Jay Freedman

Hi Andrew,

Actually, you can reduce the number of candidates by iterating through
firstBk.Range.Bookmarks instead of ActiveDocument.Bookmarks:

For Each tryBk In firstBk.Range.Bookmarks

That will test only the bookmarks that have some part of their range in
firstBk.Range (either enclosing it, inside it, or overlapping it), but it
will ignore any bookmarks that don't touch firstBk. If you have a lot of
bookmarks, that'll reduce the work considerably.

As for "sorting" the hierarchy, once you have the list of enclosing
bookmarks you should be able to sort them in order of their .Start values.
 
A

Andrew Sharpe

Good stuff Jay. If I were looking for all the bookmarks "contained" within
a given bookmark that would work perfectly. But what I actually want to do
is look for all bookmarks that "contain" a given bookmark. So I think I
still have to iterate through all bookmarks. But yeah good point about
using Range.Start to sort them. That's better.

Another somewhat related problem is given a bookmark, how do I get a
reference to the master collection of bookmarks (need the new
Tools.Word.Bookmark objects as opposed to the Interop.Word.Bookmark
objects)? The Container property looked promising, in the Immediate window
it returned an instance of ThisDocument, which is perfect because it has the
Controls property that I can use. But anytime I try to reference the
Controls property in code, it returns a Null Reference error. The API docs
say that this will be the case if the object returned does not implement
IContainer, which ThisDocument of course does not. Have a look, let me know
what you think. Note that the Bookmark class refers to the new
Tools.Word.Bookmark version (which i require).

Public Shared Function GetSurroundingBookmarks(ByVal bMark As Bookmark)
As List(Of Bookmark)
Dim surBMarks As New List(Of Bookmark) ' surrounding bookmarks

Dim doc As ThisDocument = DirectCast(bMark.Container, ThisDocument)
' doc is Nothing, despite the fact that evaluating bMark.Container
in the Watch or Immediate windows clearly show it returning an instance of
ThisDocument
Dim all As ControlCollection = doc.Controls

For Each obj As Object In all
If TypeOf obj Is Bookmark Then
Dim curBMark As Bookmark = DirectCast(obj, Bookmark)
If bMark.InRange(curBMark.Range) Then
Dim i As Integer
For index As Integer = 0 To surBMarks.Count - 1
If surBMarks(index).InRange(curBMark.Range) Then
i = index
End If
Next
surBMarks.Insert(i, curBMark)
End If
End If
Next

Return surBMarks
End Function

Thank you SO MUCH for your continued efforts. They are MUCH appreciated.

Andrew
 
J

Jay Freedman

Hi Andrew,

Actually, iterating through firstBk.Range.Bookmarks will give you both the
bookmarks that contain firstBk and the ones it contains, and the expression
firstBk.Range.InRange(tryBk.Range) will return True only when firstBk is
inside (or equal to) tryBk. That's exactly the relation you want.

I've never worked with code like yours -- is that VB.Net? -- so I can't help
with the problem. You might have a better chance of getting answers in one
of the microsoft.public.office.developer newsgroups.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top