Cross reference to custom reference type - vba

I'm trying to add a cross reference into a SEQ field.
My document contains "point headings" which means that between two heading elements, the user can add an extension (between 1.1 and 1.2 may be 1.1A, 1.1B, ...)
Here is how the point heading code looks like:
{STYLEREF "HEADING 2" \N}{SEQ "HEADING 2 POINT" \* ALPHABETIC \S 2}
Which results with: 1.1A
I want to be able to do a cross reference into the point heading.
While I can set the reference type into 'Heading' I can't find out how to reference it to a custom element.
Searching through the web did not reveal any solution but some clues that it might be possible:
This website which explains cross-reference formatting, contains an image with custom type (My New Caption).
Microsoft DOC's description for ReferenceType is: The type of item for which a cross-reference is to be inserted. Can be any WdReferenceType or WdCaptionLabelID constant or a user defined caption label.
My client is used to work with the cross reference dialog box hence I prefer this approach, but VBA script will also be appreciated.
Thanks!
Update:
I'll try to describe my constraints and environment.
Headings 1-9 are used inside Multi-Level list item, hence they have custom styling.
They cannot be changed.
For a specific task, which is described and answered here, I've created what I call 'Point Headings'.
'Point Headings' are basically an extension that the user can add in between the Multi-Level numbering with a VBA macro.
Let's say that I have two Heading 2 items (1.1, 1.2), the user can add 1.1A, followed by 1.1B and so on.
The user can add point headings from level 2 up to level 5.
Their style is 'Heading 2 Point', 'Heading 3 Point' and so on, and each one is based on its relevant Heading.
As described above, eventually in the document, the word field has the following structure: {STYLEREF "HEADING 2" \N}{SEQ "HEADING 2 POINT" \* ALPHABETIC \S 2}.
My goal is to be able to cross reference into these items, but they do not appear in the Heading type, well because they are not of style Heading.
I wish to be able to create a custom reference type, which will show these items.

After some research, here is my answer. Hopefully it will help some future viewers.
Private Sub createPointHeader(pointLevel As Integer, Optional appendixPrefix As String = "")
Dim sQuote As String, referencedStyle As String, captionName As String
sQuote = Chr(34)
referencedStyle = appendixPrefix & "Heading " & pointLevel
captionName = referencedStyle & " Point"
With Selection
.Fields.Add .Range, wdFieldEmpty, "StyleRef " & sQuote & referencedStyle & sQuote & " \n", False
.Collapse wdCollapseEnd
CaptionLabels.Add (captionName)
.InsertCaption Label:=captionName, ExcludeLabel:=True
' Select the created field
.MoveLeft Count:=1, Extend:=True
' Replace the syntax from Arabic to Alphabetic
.Fields.ToggleShowCodes
With .find
.Text = "ARABIC"
.Forward = False
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchKashida = False
.MatchDiacritics = False
.MatchAlefHamza = False
.MatchControl = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
If .Found = True Then
Selection.Range.Text = "ALPHABETIC \s " & pointLevel
End If
End With
.Fields.ToggleShowCodes
.Fields.Update
.MoveRight Count:=1
.InsertAfter vbTab
.Collapse wdCollapseEnd
' Apply style after .InsertCaption, because it changes the style to Caption
.Style = ActiveDocument.Styles(referencedStyle & " Point")
End With
End Sub
Few remarks
I have two styles to base upon: Heading (2-5), and Appendix Heading (2-5). This is the reason for the optional appendixPrefix as a sub variable.
CaptionLabels.Add as I've checked can get the same value. No need to check in advance if it already exists.
Selection.InsertCaption automatically changes the style into Caption. This is why I apply the style change at the end.
The result
Here is how Point Heading 2 looks like:
{STYLEREF "HEADING 2" \N"}{SEQ HEADING_2_POINT \* ALPHABETIC \S 2}
Snapshot of the document with the point headings
And finally, as requested, cross reference to the Point headings from the Cross reference box

The question asks how to create a cross reference to a custom reference type. I suspect this answer may actually respond to what the original asker might have been getting at.
The idea is to use custom caption labels. A custom caption label appears (ideally) in the Insert/Cross Reference dialog.
A custom caption label is created when you say Insert/Caption and then ask to add a new custom label.
If you have added a custom caption label yourself in a given document, then it automatically appears as a choice when you say Insert/Cross Reference ...
However a difficulty arises when you are given a document where someone else has already added the cross reference type and you want to edit it (by adding additional cross references to the given type of caption). The secret here is to add the custom caption label yourself (even though it already exists), by creating a new temporary caption with the custom label type. You can then go ahead and delete the temporary caption, but you will from then on be able to add cross references to that caption type.
I use this when I want to make reference to 'Code Snippets' or 'Boxes' or 'Algorithms'.

I'm taking the chance of responding as an answer rather than as a comment as the reply is longish but hopefully should get you going in the right direction.
I think you have been led down the wrong path by the point pages article you have referenced.
I'm assuming that we can't modify the styles 'Heading 1' to 'Heading 9'. If you can then you will be able to adapt the suggestion below to use with only 'Heading 1' to 'Heading 9' styles.
You will need to create some new styles. I've used the following styles
Name Based on Style Outline level
Heading Point 1 Heading 1 1
Heading Point 2 Heading 2 2
Heading Point 2 Ext Heading 2 3
Heading Point 3 Heading 3 4
Heading Point 3 Ext Heading 3 5
Heading Point 4 Heading 4 6
Heading Point 4 Ext Heading 4 7
Heading Point 5 Heading 5 8
Heading Point 5 Ext Heading 5 9
Please note that getting the outline level correct is important for Heading numbering.
Next create a new Multilevel list. Call the list 'PointNumbering' (Because if you do this you can identify the list by the name in VBA should you need this facility). Link the styles 'Heading Point 1' to 'Heading Point 5 Ext' to levels 1 to 9 of the numbering sequence (e.g. Outline level 1 matches level 1 in the numbering sequence etc).
Turn off the legal style numbering for each level otherwise we won't be able to use Alphabetic numbering. Set the numbering scheme as indicated below.
Level Number style format levels* Final Appearance
1 1,2,3, 1 1
2 1,2,3 1.2 1.1
3 A,B,C 1.23 1.1A
4 1,2,3 1.2.4 1.1.1
5 A,B,C 1.2.45 1.1.1A
6 1,2,3 1.2.4.6 1.1.1.1
7 A,B,C 1.2.4.67 1.1.1.1A
8 1,2,3 1.2.4.6.8 1.1.1.1.1
9 A,B,C 1.2.3.6.89 1.1.1.1.1A
The actual levels are picked from a drop down list and appear as '1' in the number format box. This makes getting the numbering wrong quite easy so take care. The last number in each level is obtained by selecting the number format in the 'Number style for this level' box.
Once you have set up your styles and ensured that they are linked to the above numbering scheme you need to adjust the styles used for the headings in you current document.
Do a search and replace to do the following style replacements
Current Style New Style
Heading 1 Heading Point 1
Heading 2 Heading Point 2
Heading 3 Heading Point 3
Heading 4 Heading Point 4
Heading 5 Heading Point 5
Then for each of your extension headings where you are currently creating the numbering using style ref and seq field delete the fields and apply the relevant Ext Heading.
Thus for A,B,C numbering after 'Heading Point 2', apply the 'Heading Point 2 Ext' style.
This should now mean that all Heading Point styles can be accessed through the cross reference dialog.
If you document headings at 'Heading 6' Level 6 and below the after 'Heading Point 5 Ext you can use the Heading styles (Heading 6 to Heading 9) as normal. However, each time you use a Heading 6 you will need to manually reset the number. I think this is an easier task than asking users to insert multiple styleref and seq fields because you just select then right click on the heading number and then tick buttons to enable 'Advanced value (skip number)' which allows you to reset any level within your current Heading Number.
If you subsequently need to create a TOC field for your document you will now have to use the \t switch and provide a list of styles and the level number to use for the style in the TOC. e.g. {toc \t "Heading Point 1,1,Heading Point 2,2,Heading Point 2 Ext,2,Heading Point 3,3,Heading Point 3 Ext,3.....etc}.
I have created and tested all of the above in a Word document.

Related

Get table values from certain section in word VBA

I have a large word document that has several tables in several different sections. Something that looks like the following:
Section 1
Section 1.1 (has table)
Section 1.2
Section 1.2.1 (has table)
Section 2
Section 2.1 (has table)
Section 2.1.1 (has table)
Section 2.2
Section 3 (has table)
However, I only want the tables in one section. Is there a way to create a loop that can get the data from all the tables only in a certain section?
I was thinking about using something like ActiveDocument.TablesOfContents(1), but I think I'll need more than that. Is there a way to constantly check which section you're in? Maybe some pseudocode like...
'Starting at the top of the document
'This would not start until the document found Section 2, and would end once it found section 3
While [ActiveDocument.TablesOfContents("name")]
'Which would include 2.1, 2.1.1, and 2.2 because they are a part of 2
TableCount = ActiveDocument.Tables.Count 'But only header 2
For tableNum = 1 To TableCount
' do something/get data
Next tableNum
Wend
The first thing you need to do is find the Heading 1 styled paragraph that marks the start of the range you want to look in. You can then use the document’s GoTo method to go to the predefined bookmark that will give you the entire range of the heading level, starting at the Heading 1 para and extending to the next Heading 1 para.
You can then access the Tables collection of that Range
Don’t have access to a PC right now to give you the code, but there are numerous examples here on SO, for example Word VBA: How to delete sections of text from a template document using a heading (purely conicidental that it is one of mine!)

Get Heading Number and Text from current selection

I am looking for a function that returns the number and text of the currently last heading in a text, based on the current selection.
I want a function to return "1.1. Felines" from
1. Animals
Animals are sometimes domesticated.
1.1. Felines
Felines are *often* cats.
1.2. Canines
Canines are sometimes dogs.
where "often" ist my current selection. My current selection may (and will) be inside a table in my final application, so the function has to work inside tables, too.
The headings are the standard format templates "Heading 1" or "Heading 2" or "Heading 3" that are present in every empty Word file.
The function should return the lowest level heading that is the last heading above the selection. Bonus points for a second function that returns the previous "level 1 Heading".
I have found this: this and other SO questions, but I am not deep enough into VBA to modify them to do what I want. I also googled into the Selection.Information and Selection.Style but hit a wall with both. For example wdActiveEndSectionNumber from .Information only returns the section number, but I do not use a new section for each heading. With the .Style I did not manage to find the last Heading before the selection.

Word VBA: How to get the current section number

I'm building a macro that loops through each word of a document and checks via a regex whether it matches a pattern and if so, writes the found word to an excel sheet. It goes like this:
For Each sentence In ActiveDocument.StoryRanges
For Each w In sentence.Words
myWord = w
If TestRegExp(myPattern, myWord) Then
WKS.Cells(myCount, 1).Value = myWord
myCount = myCount + 1
End If
Next
Next
This part works fine. Now I would also like to get the section per found word (aka "in what section did the found word appear"). I found the command "selection.Information" but no matter what I try, I only get "Section = 1". Even if I just check the whole document for sections ("ActiveDocument.Sections.Count") I only get 1. So there must be something off with the sections, but this document definitely has sections. Has anybody an idea what I do wrong?
Page and section numbers in Word are difficult since the document's logical structure may not match the displayed text. I can, for example, reset page numbering in the middle of a document.
Similarly, a "section" to word is the separation of parts of the document by virtue of the insertion of a section break, whether next page, continuous, next odd, next even, etc. However, the reader often thinks of the "section" as the number that appears before a "heading 1" style paragraph. Again, I can reset those numbers mid-document. So, a document that has 3 sections (logical) might have only two headings: none in section 1, one in section 2 that says "1. Introduction", and another in section 3 that says "Appendix A. Glossary". The (logical) sections are still 1, 2, 3......
w = ActiveDocument.Sentences(10).Words(1) ' given some word in the document
MsgBox w.Information(wdActiveEndPageNumber) ' logical page number
MsgBox w.Information(wdActiveEndAdjustedPageNumber) ' displayed page number
MsgBox w.Information(wdActiveEndSectionNumber) ' logical section number
As for the displayed section number, which is there by virtue of being "Heading 1" style and that style having been set to a multi-level numbered format... getting the displayed number of that list item appears to be very difficult, in the general case.
Solutions I've seen involve searching for the previous paragraph that matches a heading style then getting the .ListFormat.ListString from that.
MsgBox w.GoTo(What:=wdGoToHeading, Which:=wdGoToPrevious).ListFormat.ListString
but that gets the previous heading of any level, not just "Heading 1".
Sections are different from StoryRanges, and are part of the StoryRanges(wdMainTextStory) range. You can use For loop instead of For Each loop to get the WdStoryType number:
For i = 1 To ActiveDocument.StoryRanges.Count ' or 1 To 17
For Each w In ActiveDocument.StoryRanges(i).Words
If TestRegExp(myPattern, w) Then
WKS.Cells(myCount, 1).Value = myWord
myCount = myCount + 1
Debug.Print i, myCount, w ' i has the WdStoryType number
End If
Next
Next
Also, RegExp is probably not needed, as Word has wildcard Find and Replace https://superuser.com/questions/86397/wildcards-in-word, and VBA has the Like Operator

VBA: Word 2013 Expand/Collapse Specific Headings

I need help, and I think this is pretty easy if you know VBA:
I want to have a button or dropdown menu that expands/collapses specific menu headings.
Here is an outline of the layout of the document (there are menus and data within the Department levels as well, but I don't need to collapse/expand those levels):
- Daily Processes
Department A
Department B
Department C
Department D
- Weekly Processes
Department A
Department B
Department C
Department D
- Monthly Processes
Department A
Department B
Department C
Department D
- Annual Processes
Department A
Department B
Department C
Department D
- Appendix
I want there to be buttons for each department, hiding all other departments. For example, if I click Department A, all Dept B, C, D menus will collapse, only showing Dept A.
I would imagine these would be the buttons that I would need:
ExpandAll
ShowDeptA
ShowDeptB
ShowDeptC
ShowDeptD
This is the pseudocode for one dept that I think would work:
ExpandAll
Start at top of Document
Search Format=Heading2
If Heading2=DepartmentA: expand heading,
Else: collapse heading
What I have so far: (All I need the command to collapse headings)
Sub OpenDeptA()
'
' OpenDeptA Macro
' Show only DeptA sections
'
' Expand all menus
ActiveDocument.ActiveWindow.View.ExpandAllHeadings
' Move cursor to the top
Selection.HomeKey Unit:=wdLine, Extend:=wdExtend
Selection.HomeKey Unit:=wdStory
' Find first menu using format: Heading 2
Selection.Find.Style = ActiveDocument.Styles("Heading 2")
Selection.Find.Execute
' Loop through document collapsing heading if not equal to "DeptA"
Do Until Selection.Find.Found = False
If Selection.Text = "DeptA" Then
Selection.Find.Style = ActiveDocument.Styles("Heading 2")
Selection.Find.Execute
Else: Selection.CollapseHeading ***NOT SURE HOW TO COLLAPSE MENUS***
Selection.Find.Style = ActiveDocument.Styles("Heading 2")
Selection.Find.Execute
End If
Loop
End Sub
I don't have Word 2013, so I can't provide a complete answer. But I can help with two aspects of what you are doing.
Comparing text. Right now you are comparing just words "Dept A", but it is likely that the actual selection contains the line break as well. You could try
Selection.Text = "DeptA" & vbCR
or
Selection.Text Like "DeptA*"
It depends a bit on how tightly controlled those headings are.
Collapsing the content. I assume you are already putting the document into Outline View. If so, the command is
ActiveWindow.View.CollapseOutline Selection.Range
the thing about CollapseOutline, though, is that it only collapses by one level. So if you had a Heading 3 under your Heading 2, that would be collapsed but your Heading 2 would not be. From what I can tell there's no harm in running CollapseOutline several times, so I'd work out ahead of time how deeply the levels in your document go and then run the method enough times to accommodate that.
Ok, revisiting this with a copy of Word 2013 in front of me. There doesn't seem to be a method for collapsing the text; instead, you set its collapsed state to true. And, it works on paragraphs, not ranges or selections. So here is the final portion of your code, with the collapsing code included:
Do Until Selection.Find.Found = False
If Selection.Text Like "Department A*" Then
Selection.Find.Style = ActiveDocument.Styles("Heading 2")
Selection.Find.Execute
Else: Selection.Paragraphs(1).CollapsedState = True
Selection.Find.Style = ActiveDocument.Styles("Heading 2")
Selection.Find.Execute
End If
Loop
As to your question about Word Commands that you can see in the Macros list, you can run these, but their real power lies in the ability to recode them to do what you prefer. In this case what you need to do is supported by the object model so I wouldn't bother with them.
Lastly, if you intend to do a lot of VBA coding, I'd recommend getting familiar with the Object Browser (F2 from the VB Editor). You can search for something you think might exist there; for instance, in looking into this question I searched for "Collapseheading". In this case that wasn't fruitful on its own, but it did put me in the neighborhood of CollapsedState.
Hope this helps.

How do I apply a style to multiple selections in Word using VBA?

I created a macro that will apply a particular style to whatever is selected in the document. However, when in draft view, when the user clicks in the style area pane to select a paragraph and then Ctrl + clicks on an additional paragraph, this additional selection is not applied when this macro is run:
Sub BodyTextApply()
Selection.Style = ActiveDocument.Styles("Body Text,bt")
End Sub
What do I need to add to this? Note: The workflow cannot change so that the user selects that actual text in the document; they are set on using the style area pane...
The workflow is as follows:
alt text http://img6.imageshack.us/img6/1994/91231840.png
The (undesired) output is as follows:
alt text http://img34.imageshack.us/img34/1239/outputt.png
Looks like your style "Body Text,bt" is a pure paragraph style. That means it will only be applied to a complete paragraph.
However, in your screenshot there is only part of the second paragraph selected. Make sure the complete paragraph is selected or, if the style should only be applied to part of the paragraph, make your style "Body Text,bt" a linked (paragraph and character) style.
Programmatic access to discontiguous selections is very limited, and such selections can only be created using the Word UI. The MSDN article Limited programmatic access to Word discontiguous selections gives some more details.
If applying the style only to part of the paragraph (by making it a linked style) is not what you want you probably have to come up with a hack like this:
Sub BodyTextApply()
Dim oRange As Range
' create a temporary character style
ActiveDocument.Styles.Add "_TEMP_STYLE_", wdStyleTypeCharacter
' apply the temporary style to the discontiguous selection
Selection.Style = ActiveDocument.Styles("_TEMP_STYLE_")
Set oRange = ActiveDocument.Range
With oRange.Find
.ClearAllFuzzyOptions
.ClearFormatting
.ClearHitHighlight
.Style = ActiveDocument.Styles("_TEMP_STYLE_")
.Text = ""
.Wrap = wdFindStop
' search for all occurences of the temporary style and format the
' complete paraphraph with the desired style
Do While .Execute
oRange.Paragraphs(1).Style = ActiveDocument.Styles("Body Text,bt")
Loop
End With
' cleanup
ActiveDocument.Styles("_TEMP_STYLE_").Delete
End Sub
You probably want to add some error handling as well to make sure that the temporary style used is finally removed from the document.