List all "Styles Used" in a new document

A

andreas

Dear Experts:

Is it possible to have Word list all "used styles" of the current
document in a new document? I use Word 2003.

Help is appreciated. Thank you very much in advance.

Regards,

Andreas
 
S

StevenM

Sub TestStyles()
Dim oStyle As Style
Dim sStyle As String
Dim actDoc As Document
Dim newDoc As Document

Set actDoc = ActiveDocument
Set newDoc = Documents.Add

For Each oStyle In actDoc.Styles
If oStyle.InUse Then
With oStyle
sStyle = sStyle & "Style: " & .NameLocal & vbCr
sStyle = sStyle & "Font: " & .Font.Name & vbCr
sStyle = sStyle & "Size: " & .Font.Size & vbCr & vbCr
End With
With newDoc.Range
.Text = sStyle
.Collapse wdCollapseEnd
.MoveEnd wdCharacter, 1
End With
End If
Next oStyle
End Sub
 
G

Gordon Bentley-Mix

Steven,

Your code _looks_ like it ought to do what Andreas wants to do, but...

I seem to recall reading somewhere (can't remember exactly where at the
moment unfortunately - I've slept a few times since then) that the .InUse
property of a Style object doesn't necessary behave the way you'd expect it
to. A Style may have its .InUse property set to 'True' even if the Style
isn't actually used in the document. From my admittedly fuzzy recollection, I
believe this occurs when as Style has been used in a document and then
subsequently removed and not used again elsewhere. The .InUse property still
shows as 'True' even though the Style technically isn't actually used.

The article I saw mentioned a way to get around this problem, but since it
didn't really have an impact on what I was doing at the time, I've forgotten
how the workaround... uhh... worked. ;-D

I can envisage a possible solution, but it might be rather clunky. I haven't
tested it, but I'll offer it anyway:
1) Go through the Paragraphs collection and record the Style used for each
Paragraph in an array
2) Sort the array and remove any duplicates
3) Print the array values in a new doc
It could probably be written to check each Style against the existing array
values and add it only if it's not already there, which might be more
efficient. (I've done something similar in a few of my templates.)

I'll go off and do a bit of work on this and post some code if I can get it
working in a reasonable amount of time. I'll also investigate to make sure
that the article I read presented a true picture of the situation. In the
meantime, maybe someone else can tell you where to find that article on why
the .InUse property lies sometimes.

--
Cheers!
Gordon
The Kiwi Koder

Uninvited email contact will be marked as SPAM and ignored. Please post all
follow-ups to the newsgroup.
 
G

Gordon Bentley-Mix

Well, I can definitely confirm that the .InUse property isn't a good
indicator of the Styles that are actually used in a document. Here's what I
did to prove it:

1) Created a new blank document, added an additional paragraph to it (for a
total of two) and then put a bit of text in the first paragraph - just for
some visual feedback.
2) Created a new style called 'BOB' that was just 'Normal + Font color: Red'
and applied it to the first paragraph.
3) Ran the following code:

Sub Test1()
Dim myStyle As Style
For Each myStyle In ActiveDocument.Styles
If myStyle.InUse Then Debug.Print myStyle.NameLocal
Next myStyle
End Sub

Which produced this result:
BOB
Default Paragraph Font
No List
Normal
Table Normal

Right away I could see a problem: I only have two paragraphs but there are
five styles listed; I expected to see only 'BOB' and 'Normal'.

Next I removed the 'BOB' style from the first paragraph so that my two
paragraphs both used the 'Normal' style, then I reran my code and got this
result:
BOB <--***NOTE***
Default Paragraph Font
No List
Normal
Table Normal

The 'BOB' style still shows as being in use even though I can see from
looking at my document that it clearly isn't.

Next I reapplied the 'BOB' style to the first paragraph and ran the following:

Sub Test2()
Dim myPara As Paragraph
For Each myPara In ActiveDocument.Paragraphs
Debug.Print myPara.Style
Next myPara
End Sub

This produced this result, which was exactly as expected:
BOB
Normal

Finally, I removed the 'BOB' style again and reran Test2, which showed the
following, again as expected:
Normal
Normal

I'm sure you can draw your own conclusions from this, and I think that
between my Test2 code and your TestStyles code, Steven, it should be pretty
easy to come up with a solution that works. However, this little experiment
did highlight something that might not have been clear before: The .InUse
property also applies to Character, List and Table styles - as is evident
from the presence of 'Default Paragraph Font' and 'No List' and 'Table
Normal' in the results from Test1.

My solution only deals with the Paragraph styles that are used in a
document, so if Andreas wants the Character, List and Table styles as well it
will be considerably more complicated...

Anyway, now my interested in piqued. I'll post back later with full code for
creating a new document listing all of the Paragraph styles used in an
existing document. This might come in handy for me at some point as well.
--
Cheers!
Gordon

Uninvited email contact will be marked as SPAM and ignored. Please post all
follow-ups to the newsgroup.
 
S

StevenM

To: Gordon Bentley-Mix,

I created a new document and ran the code presented in an earlier message
and it returned with only the Default Paragraph Font & Normal. I then created
a new Style called “Bob†and got “Bob†plus the other two. I changed all Bob
paragraphs to Normal, and still got Bob on my list (just as you did). But
then I deleted “Bob†from the Styles menu and “Bob†didn’t appear in the
list. I ran the code/program on other documents and I’ve come to the
following tentative conclusion: “InUse†appears to include:

(1) all the user defined styles available to the document;
(2) all the other styles once used in the document; and
(3) and Default Paragraph Font & Normal.

Steven Craig Miller
 
G

Gordon Bentley-Mix

Steven,

I've found the "article" I referenced earlier; it's the VBA help topic on
the .InUse property. (~smacks forehead with palm~) This topic reads in part:

Remarks
This property doesn't necessarily indicate whether the style is currently
applied to any text in the document. For instance, if text that's been
formatted with a style is deleted, the InUse property of the style remains
True. For built-in styles that have never been used in the document, this
property returns False.

Accordingly, I'd agree with your assessment of what "InUse" means, and I
believe this is pretty much the way the help explains it as well.

Unfortunately, it's hard to tell from Andreas's initial post if the goal is
to list the styles that Word identifies as "InUse" or if it is to list those
styles that are actually applied someplace in the document. Assuming the
latter then the following code should do the trick (complete with a bit of
error handling and a few other bells & whistles):

Option Explicit
Dim StylesArray() As Variant
Dim SourceDoc As Document

Sub ListStylesInUse()
If Documents.Count = 0 Then
MsgBox "There are no open documents.", vbCritical, "List Style Error"
Else
Set SourceDoc = ActiveDocument
If SourceDoc.ProtectionType <> wdNoProtection Then
MsgBox "Document protected. Cannot list styles.", vbCritical,
"List Style Error"
Else
Dim ParaCount As Integer
Dim myPara As Paragraph
Dim ParaIdx As Integer
Dim ThisParaStyleName As String
Dim ThisParaStyleFontName As String
Dim ThisParaStyleFontSize As String
Dim StyleCount As Integer
Dim i As Integer
Dim bMatchFound As Boolean
Dim StyleDetails As String
ParaCount = SourceDoc.Paragraphs.Count
For ParaIdx = 1 To ParaCount
bMatchFound = False
Set myPara = SourceDoc.Paragraphs(ParaIdx)
ThisParaStyleName = myPara.Style.NameLocal
For i = 1 To StyleCount
If ThisParaStyleName = StylesArray(0, i) Then
bMatchFound = True
Exit For
End If
Next i
If Not bMatchFound Then
StyleCount = StyleCount + 1
With myPara.Style
ThisParaStyleFontName = .Font.Name
ThisParaStyleFontSize = .Font.Size
End With
ReDim Preserve StylesArray(2, 1 To StyleCount)
StylesArray(0, StyleCount) = ThisParaStyleName
StylesArray(1, StyleCount) = ThisParaStyleFontName
StylesArray(2, StyleCount) = ThisParaStyleFontSize
End If
Next ParaIdx
StyleDetails = fcnBuildStyleDetails(StyleCount)
BuildTargetDoc (StyleDetails)
End If
End If
End Sub

Private Function fcnBuildStyleDetails(StyleCount As Integer) As String
Dim n As Integer
Dim Temp As String
Temp = "Styles found in " & SourceDoc.Name & vbCr
Temp = Temp & StyleCount & " styles, as follows:" & vbCr & vbCr
For n = 1 To StyleCount
Temp = Temp & "Style " & n & " -" & vbCr
Temp = Temp & "Style Name: " & StylesArray(0, n) & vbCr
Temp = Temp & "Font Name: " & StylesArray(1, n) & vbCr
Temp = Temp & "Font Size: " & StylesArray(2, n) & vbCr & vbCr
Next n
fcnBuildStyleDetails = Temp
End Function

Private Sub BuildTargetDoc(StyleDetails As String)
Dim TargetDoc As Document
Set TargetDoc = Documents.Add
With TargetDoc.Range
.Text = StyleDetails
.Collapse wdCollapseEnd
.MoveEnd wdCharacter, 1
End With
End Sub

Note that on a *REALLY BIG* document this code can take a long time to
execute because it has to run through a lot of paragraphs. A couple of
hundred paragraphs is probably OK, but I pointed it at a document that
contained 2000+ paragraphs and then went out for coffee... Maybe some other
Clever Dick in here has a faster solution.

*** This code is supplied 'as is' with no warrantee of fitness for a
particular use. E&OE. Caveat emptor. Res ipsa. Etc., etc. ***
--
Cheers!
Gordon

Uninvited email contact will be marked as SPAM and ignored. Please post all
follow-ups to the newsgroup.
 
S

StevenM

To: Gordon Bentley-Mix,

Valiant effort, but when I ran your code it didn't pick up the header or
footer styles. I don't have a document on hand with endnotes, but I wonder if
it would pick up styles used there as well? I was reading online (somewhere)
about the "Find" object, and it has the samesort of problem. One cannot
search the whole document with "Find" since it only works on one story at a
time (or something like that).
 
G

Gordon Bentley-Mix

Yup Steven, I had a feeling that styles used in headers/footers wouldn't be
found.
There are probably a few other gaps as well - styles used in TextBoxes for
example. Similar things happen when trying to update the fields in a
document. It's definitely related to that whole 'Story' concept. I'm sure it
can be coded around without too much effort. Maybe I'll have a look at it
later.

BTW, I've been doing a bit of experimentation and it appears that loading
the style definitions for _ALL_ of the paragraphs in a document into an array
and then finding the unique values in the array is markedly quicker than
trying to load only the unique values into the array in a single pass. I set
up a little 'watch window' to monitor how much time it was taking to process
the paragraphs, and it appears that the time increases exponentially as you
go down the document; that is, the time taken to process the second paragraph
is n-times as long as the time for the first, the time for the third is
n-times the time for the second, and so on. I don't know why this should be
since the only thing that could possible change between paragraphs is number
of styles in the array - and then only by a relatively small amount. (My test
doc has 2112 paragraphs but only 12 unique styles.) The actual number of
lines of code executed for each paragraph is nearly the same. Makes no sense
to me but I'll keep looking. However, I may just use the
'collect-first-sort-later' method instead.
--
Cheers!
Gordon

Uninvited email contact will be marked as SPAM and ignored. Please post all
follow-ups to the newsgroup.
 
S

StevenM

To: Gordon Bentley-Mix,

The following code doesn't seem to pick up the header styles, and I don't
know why, but it otherwise works and is much faster than looping through each
paragraph.

Sub StylesInUse()
Dim oStyle As Style
Dim sStyle As String
Dim actDoc As Document
Dim newDoc As Document

Set actDoc = ActiveDocument
Set newDoc = Documents.Add

For Each oStyle In actDoc.Styles
If oStyle.InUse And IsStyleInUseInDoc(oStyle, actDoc) Then
With oStyle
sStyle = sStyle & "Style: " & .NameLocal & vbCr
sStyle = sStyle & "Font: " & .Font.Name & vbCr
sStyle = sStyle & "Size: " & .Font.Size & vbCr & vbCr
End With
With newDoc.Range
.Text = sStyle
.Collapse wdCollapseEnd
.MoveEnd wdCharacter, 1
End With
End If
Next oStyle
End Sub

Function IsStyleInUseInDoc(ByVal oStyle As Style, ByVal oDoc As Document) As
Boolean
Dim oRange As Range
Dim bReturn As Boolean

bReturn = False
For Each oRange In oDoc.StoryRanges
If IsStyleInRange(oStyle, oRange) = True Then
bReturn = True
End If
Next oRange
IsStyleInUseInDoc = bReturn
End Function

Function IsStyleInRange(ByVal oStyle As Style, ByVal oRange As Range) As
Boolean
With oRange.Find
.ClearFormatting
.Style = oStyle
.Forward = True
.Format = True
.Text = ""
.Execute
End With
If oRange.Find.Found = True Then
IsStyleInRange = True
Else
IsStyleInRange = False
End If
End Function

Do you have any suggestions?
 
S

StevenM

I believe the following code works.

Sub ListStylesInUse()
Dim oStyle As Style
Dim sStyle As String
Dim actDoc As Document
Dim newDoc As Document

Set actDoc = ActiveDocument
Set newDoc = Documents.Add

For Each oStyle In actDoc.Styles
If oStyle.InUse Then
If IsStyleInUseInDoc(oStyle, actDoc) Then
With oStyle
sStyle = sStyle & "Style: " & .NameLocal & vbCr
sStyle = sStyle & "Font: " & .Font.Name & vbCr
sStyle = sStyle & "Size: " & .Font.Size & vbCr & vbCr
End With
With newDoc.Range
.Text = sStyle
.Collapse wdCollapseEnd
.MoveEnd wdCharacter, 1
End With
End If
End If
Next oStyle
End Sub

Function IsStyleInUseInDoc(ByVal oStyle As Style, ByVal oDoc As Document) As
Boolean
Dim oRange As Range
Dim bReturn As Boolean

bReturn = False
For Each oRange In oDoc.StoryRanges
If IsStyleInRange(oStyle, oRange) = True Then
bReturn = True
End If
Do While Not (oRange.NextStoryRange Is Nothing)
Set oRange = oRange.NextStoryRange
If IsStyleInRange(oStyle, oRange) = True Then
bReturn = True
End If
Loop
Next oRange
IsStyleInUseInDoc = bReturn
End Function

Function IsStyleInRange(ByVal oStyle As Style, ByVal oRange As Range) As
Boolean
oRange.Collapse Direction:=wdCollapseStart
With oRange.Find
.ClearFormatting
.Style = oStyle
.Forward = True
.Format = True
.Text = ""
.Execute
End With
If oRange.Find.Found = True Then
IsStyleInRange = True
Else
IsStyleInRange = False
End If
End Function

Steven Craig Miller
 
A

andreas

I believe the following code works.

Sub ListStylesInUse()
    Dim oStyle As Style
    Dim sStyle As String
    Dim actDoc As Document
    Dim newDoc As Document

    Set actDoc = ActiveDocument
    Set newDoc = Documents.Add

    For Each oStyle In actDoc.Styles
        If oStyle.InUse Then
            If IsStyleInUseInDoc(oStyle, actDoc) Then
                With oStyle
                    sStyle = sStyle & "Style: " & .NameLocal & vbCr
                    sStyle = sStyle & "Font: " & .Font.Name & vbCr
                    sStyle = sStyle & "Size: " & .Font.Size & vbCr & vbCr
                End With
                With newDoc.Range
                    .Text = sStyle
                    .Collapse wdCollapseEnd
                    .MoveEnd wdCharacter, 1
                End With
            End If
        End If
    Next oStyle
End Sub

Function IsStyleInUseInDoc(ByVal oStyle As Style, ByVal oDoc As Document) As
Boolean
    Dim oRange As Range
    Dim bReturn As Boolean

    bReturn = False
    For Each oRange In oDoc.StoryRanges
        If IsStyleInRange(oStyle, oRange) = True Then
            bReturn = True
        End If
        Do While Not (oRange.NextStoryRange Is Nothing)
            Set oRange = oRange.NextStoryRange
            If IsStyleInRange(oStyle, oRange) = True Then
                bReturn = True
            End If
        Loop
    Next oRange
    IsStyleInUseInDoc = bReturn
End Function

Function IsStyleInRange(ByVal oStyle As Style, ByVal oRange As Range) As
Boolean
    oRange.Collapse Direction:=wdCollapseStart
    With oRange.Find
        .ClearFormatting
        .Style = oStyle
        .Forward = True
        .Format = True
        .Text = ""
        .Execute
    End With
    If oRange.Find.Found = True Then
        IsStyleInRange = True
    Else
        IsStyleInRange = False
    End If
End Function

Steven Craig Miller

Thank you to both of you for your terrific help
I fell unexpectedly ill, will test it as soon as possible. thanks for
the quick answer.
regards andreas
 
A

andreas

Thank you to both of you for your terrific help
I fell unexpectedly ill, will test it as soon as possible. thanks for
the quick answer.
regards andreas- Zitierten Text ausblenden -

- Zitierten Text anzeigen -

Dear Gordon Bentley and StevenM,

thank you so much for your terrific help. I tried the last code you
submitted (by StevenMatdot). It is working as desired. Very good job.

Thank you, Regads, Andreas
 
J

Jessica Weissman

This seems to pick up a few strange ones, such as the "no list" phantom
style. I have some documents where every paragraph has the "no list" style
attached somehow to it.

- Jessica
 

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