Consulting

Page 2 of 5 FirstFirst 1 2 3 4 ... LastLast
Results 21 to 40 of 92

Thread: LinkToPrevious

  1. #21
    VBAX Regular
    Joined
    Nov 2011
    Posts
    71
    Location
    Quote Originally Posted by fumei View Post
    Why on earth are users making any comments on what is in a header!!!! That is absurd. It is not their document, tell them to mind their own business. Just kidding.

    Yes, I know the string with the tags are normal strings, it is annoying thing of having test random length starting and ending portions.
    Well, the good news is: whatever those tags are, and it doesn't matter why they are in headers, since they are only temporary! The algorithm is designed to find them and delete them... :-)
    Now, don't bother trying to figure out how to find each opening/closing tag, I've got that and it works. The only part that I am still struggling with is how to detect linked headers. I might give up if I see it's not worth it, but still, I'd like to know how to do it properly.
    My current code is failing:

    Dim oHF As HeaderFooter
            Dim oSection As Section
            Dim LinkToPreviousFlag As Integer
            For Each oSection In Application.ActiveDocument.Sections
                For Each oHF In oSection.Headers
                    LinkToPreviousFlag = 0
                    oHF.Range.Select
                    If oSection.PageSetup.OddAndEvenPagesHeaderFooter = False And oSection.PageSetup.DifferentFirstPageHeaderFooter = False And oSection.Headers(wdHeaderFooterPrimary).LinkToPrevious = True Then 'if FirstPage and OddEven are unchecked and header is linked
                        LinkToPreviousFlag = 1
                    ElseIf oSection.PageSetup.DifferentFirstPageHeaderFooter = True And oSection.Headers(wdHeaderFooterFirstPage).LinkToPrevious = True Then 'if FirstPage is checked and header is linked
                        LinkToPreviousFlag = 1
                    ElseIf oSection.PageSetup.OddAndEvenPagesHeaderFooter = True And oSection.Headers(wdHeaderFooterEvenPages).LinkToPrevious = True Then 'if OddEven is checked and header is linked
                        LinkToPreviousFlag = 1
                    End If
    those "if" don't give the right result... Any suggestion?

    Otherwise, I found another discussion on a similar issue (http://www.vbaexpress.com/forum/show...linktoprevious), and the suggestion is

    For Each S In ActiveDocument.Sections 
    If S.Index > 1 Then 
    For Each HF In S.Headers 
    If HF.Exists Then 
    MsgBox Choose(HF.Index, "Primary", "First Page", "Even Page") & " Header" & _ 
    " in Section " & S.Index & _ 
    " is " & IIf(HF.LinkToPrevious, "", "not ") & "linked to previous" 
    End If 
    Next 
    For Each HF In S.Footers 
    If HF.Exists Then 
    MsgBox Choose(HF.Index, "Primary", "First Page", "Even Page") & " Footer" & _ 
    " in Section " & S.Index & _ 
    " is " & IIf(HF.LinkToPrevious, "", "not ") & "linked to previous" 
    End If 
    Next 
    End If 
    Next S

    I will have to check this as well. Not sure how the msgbox works here though...
    Last edited by glencoe; 02-01-2014 at 11:17 AM.

  2. #22
    VBAX Wizard
    Joined
    May 2004
    Posts
    6,713
    Location
    Do NOT - repeat NOT - use Exists in this case. Exists only is whether FirstPage or OddEven is being displayed. It has nothing whatsoever to do with whether it exists, or not.
    The only part that I am still struggling with is how to detect linked headers. I might give up if I see it's not worth it, but still, I'd like to know how to do it properly.
    You were correct in the first place, Link is Boolean, therefore use it as Boolean. And stop using Select!
    Dim oHF As HeaderFooter 
    Dim oSection As Section 
    Dim LinkToPreviousFlag As Integer 
    For Each oSection In Application.ActiveDocument.Sections 
        For Each oHF In oSection.Headers 
    If oHF.LinkToPrevious = False Then
    'it is NOT linked so
    ' do whatever it is you are doing
    End If

  3. #23
    Knowledge Base Approver VBAX Guru macropod's Avatar
    Joined
    Jul 2008
    Posts
    4,435
    Location
    There are basically two ways of processing all headers/footers in a document. The following two subs demonstrate them.

    The first sub loops through all sections, then through all headers/footers in the section, testing whether they're linked to a previous one.

    The second sub achieves the same result more simply and more efficiently, without the need to check the LinkToPrevious state, by processing the corresponding story-ranges.

    There are, of course, advantages to the first approach in some situations.
    Sub Demo1()
    Application.ScreenUpdating = False
    Dim Fld As Field, Sctn As Section, HdFt As HeaderFooter
    With ActiveDocument
      For Each Sctn In .Sections
        For Each HdFt In Sctn.Headers
          With HdFt
            If .LinkToPrevious = False Then
              With .Range.Find
                .ClearFormatting
                .Replacement.ClearFormatting
                .Format = False
                .Forward = True
                .Wrap = wdFindStop
                .Text = ""
                .Replacement.Text = ""
                .MatchCase = True
                .MatchAllWordForms = True
                .MatchWholeWord = False
                .MatchWildcards = False
                .Execute Replace:=wdReplaceAll
              End With
            End If
          End With
        Next
        For Each HdFt In Sctn.Footers
          With HdFt
            If .LinkToPrevious = False Then
              With .Range.Find
                .ClearFormatting
                .Replacement.ClearFormatting
                .Format = False
                .Forward = True
                .Wrap = wdFindStop
                .Text = ""
                .Replacement.Text = ""
                .MatchCase = True
                .MatchAllWordForms = True
                .MatchWholeWord = False
                .MatchWildcards = False
                .Execute Replace:=wdReplaceAll
              End With
            End If
          End With
        Next
      Next
    End With
    End Sub
    Sub Demo2()
    Dim Stry As Range
    With ActiveDocument
      For Each Stry In .StoryRanges
        With Stry
          Select Case .StoryType
            Case wdEvenPagesHeaderStory, wdFirstPageHeaderStory, wdPrimaryHeaderStory
              With .Find
                .ClearFormatting
                .Replacement.ClearFormatting
                .Format = False
                .Forward = True
                .Wrap = wdFindStop
                .Text = ""
                .Replacement.Text = ""
                .MatchCase = True
                .MatchAllWordForms = True
                .MatchWholeWord = False
                .MatchWildcards = False
                .Execute Replace:=wdReplaceAll
              End With
            Case wdEvenPagesFooterStory, wdFirstPageFooterStory, wdPrimaryFooterStory
              With .Find
                .ClearFormatting
                .Replacement.ClearFormatting
                .Format = False
                .Forward = True
                .Wrap = wdFindStop
                .Text = ""
                .Replacement.Text = ""
                .MatchCase = True
                .MatchAllWordForms = True
                .MatchWholeWord = False
                .MatchWildcards = False
                .Execute Replace:=wdReplaceAll
              End With
          End Select
        End With
      Next
    End With
    End Sub
    I too would prefer not to entangle myself in yet another attempt to (mis)use Word as an HTML editor.
    Cheers
    Paul Edstein
    [Fmr MS MVP - Word]

  4. #24
    VBAX Wizard
    Joined
    May 2004
    Posts
    6,713
    Location
    And there ya go. I was hoping macropod would put in a post. Glencoe I think you have enough information to action the headers you want, as required. WHAT that action is, is up to you. Messing with tags is a pain in the butt. Good luck.

  5. #25
    VBAX Regular
    Joined
    Nov 2011
    Posts
    71
    Location
    Thank you very much to both of you, fumei and macropod for your precious help!
    I just managed to get something working without going too far from your original algorithms, but I will study closely all your advise and loops to see what would be the best.
    I obviously do not want to get my code more complex than it should, and the whole point is not to go against common sense, but more to process the data I am given the best possible way.

    Again, big applause to both of you. I will mark the case as solved shortly, once I have gone through all your points again, and I will probably leave my "final" code in here as well if it may be useful to anyone else.

  6. #26
    VBAX Wizard
    Joined
    May 2004
    Posts
    6,713
    Location
    Yes, please post whatever code you do come up with.

  7. #27
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    Paul, I'm not sure you should rely on the .StoryRanges collection in Word when dealing with headers/footers-- to me it seems completely broken when using it in a For each loop. Turn off Link to Previous in the primary header of section 2, drop some text in there.. and then try your code. You won't find it, becaue the for each loop completely skips it. I *think* you can use the .NextStoryRange method to get around this bug, but I use some sort of structure like the following function to iterate through all of theI think the .StoryRanges collection is broken in Word (at least, in Word 2010). I believe it creates the .StoryRanges collection based on the setup of the first section, and so can ignore other sections when they aren't linked... so if you have the following set up:1. Section 1, no first page different, no even pages2. Section 2, first page different, primary header not linked to previousThe for each loop for .StoryRanges fails to access the Primary Header in section 2.If you set up a multi-section document put some text in the headers/footers that you are showing... it should pretty easily demonstrate the problem.For the OP -- I would use my fGetStoryRanges function with the default options (the way the second test routine does), and then have a separate function process each unique range. In terms of optimizing the code -- it's definitely better to check a boolean property of whether a header/footer range is linked than to use a string test on the range. That said, if you end up with something working- then go for it. But I would *not* trust the For Each loop on StoryRanges, especially on large documents where you're unlikely to notice a failure (as opposed to the simple documents you'd probably test on).I agree with Fumei -- post whatever you come up with, the below
    Sub TestBadStoryRanges()  Dim r As Range    For Each r In ActiveDocument.StoryRanges    Select Case r.StoryType      Case wdEvenPagesFooterStory, wdEvenPagesHeaderStory, wdFirstPageFooterStory, wdFirstPageHeaderStory, _           wdPrimaryFooterStory, wdPrimaryHeaderStory          ' r.Select          Debug.Print Replace(r.Paragraphs.First.Range.Text, vbCr, "")    End Select  NextEnd SubSub TestGoodStoryRanges()  Dim r As Range    For Each r In fGetStoryRanges    Debug.Print Replace(r.Paragraphs.First.Range.Text, vbCr, "")  NextEnd Sub'----------------------------------------------------------------------------------------------'The MS StoryRanges collection is fundamentally broken when trying to search headers/footers'as well, since a for each loop doesn't return unlinked headers'This is an attempt to generate an accurate collection of story ranges for the passed document.'Uses the activedocument (if any) if no document is passed'doesn't currently return ranges of any textboxes'----------------------------------------------------------------------------------------------Public Function fGetStoryRanges(Optional oDoc As Document, _                                Optional bHeadersFootersOnly As Boolean = True, _                                Optional bAddHeadersFootersOnlyIfShowing As Boolean = True) As Collection  Dim colRet As Collection  Dim rngStory As Range  Dim hf As HeaderFooter  Dim oSec As Section    On Error GoTo l_err  Set colRet = New Collection  If oDoc Is Nothing Then    Set oDoc = ActiveDocument  End If    'easy story ranges, if desired  If bHeadersFootersOnly = False Then    For Each rngStory In oDoc.StoryRanges      Select Case rngStory.StoryType        Case wdCommentsStory, wdFootnotesStory, wdEndnotesStory, wdMainTextStory          colRet.Add rngStory.Duplicate      End Select    Next  End If    'headers/footers (for each not reliable!!)  For Each oSec In oDoc.Sections    For Each hf In oSec.Headers      'don't add linked ranges      If hf.LinkToPrevious = False Or oSec.Index = 1 Then        'don't add hidden ranges, unless specified        If bAddHeadersFootersOnlyIfShowing And hf.Exists _        Or bAddHeadersFootersOnlyIfShowing = False Then          colRet.Add hf.Range.Duplicate        End If      End If    Next        For Each hf In oSec.Footers      'don't add linked ranges      If hf.LinkToPrevious = False Or oSec.Index = 1 Then        'don't add hidden ranges, unless specified        If bAddHeadersFootersOnlyIfShowing And hf.Exists _        Or bAddHeadersFootersOnlyIfShowing = False Then          colRet.Add hf.Range.Duplicate        End If      End If    Next  Nextl_exit:  Set fGetStoryRanges = colRet  Exit Functionl_err:  'any errors, blackbox and return an empty collection  Set colRet = New Collection  Resume l_exitEnd Function
    Last edited by Frosty; 02-03-2014 at 03:54 PM.

  8. #28
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    I don't know what's going on with the formatting here... but I can't make it hold any line breaks... sorry for the mess. If an admin can solve, great... maybe this is an IE11 "feature"
    _______________________________________________
    Please don't cross-post without providing links to your cross-posts. We answer questions for free. Please don't waste the time of the people helping you.
    For cross-posting etiquette, please read: http://www.excelguru.ca/content.php?184

    - Frosty

  9. #29
    VBAX Regular
    Joined
    Nov 2011
    Posts
    71
    Location
    Frosty,

    Thanks for your input and code. I'll check it as well. Don't worry about the "mess", I can still easily copy and paste your code.
    Macropod, I actually found a glitch in your code (first option). I can't explain why, but though the loop works perfectly fine, the first section is not always processed properly. When checking step by step, I find that the line "If .LinkToPrevious = FalseThen" is considered as True on the first section (first page), while it actually is False! Therefore, that section is skipped, while it should be processed as well... Then, going through the loop again will process the First page just fine!
    I thought it may be a "speed" issue (the code being processed too fast), so I added a DoEvents line, without success either...
    Will check further, but if you can think of anything, I'd be happy to hear about the reason why it would fail!

  10. #30
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    Well, I'll keep my response short and sweet... you should change the logic test to be if the .LinkToPrevious = False OR Sctn.Index = 1

  11. #31
    Knowledge Base Approver VBAX Guru macropod's Avatar
    Joined
    Jul 2008
    Posts
    4,435
    Location
    There does indeed seem to be a bug in the StoryRanges objects.

    However, for the Demo1 code, there should be no need to change the logic or the test - the .LinkToPrevious value for the first Section is always false. You can verify that by inserting:
    MsgBox "Section: " & Sctn.Index & vbTab & "Link To Previous: " & .LinkToPrevious
    after:
    With HdFt
    If that's not processing correctly, we have yet another bug...
    Cheers
    Paul Edstein
    [Fmr MS MVP - Word]

  12. #32
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    In my testing, even though the .LinkToPrevious was false, it still skipped the logic block. I think that's indeed another bug.

  13. #33
    VBAX Regular
    Joined
    Nov 2011
    Posts
    71
    Location
    Macropod,
    Well, I am afraid that I did see .LinkToPrevious as true for Section 1! How come, I don't know. The button is obviously disabled in Word for this section, so it cannot be a user setting (and certainly not changed in my code either)...
    Anyway, the solution offered by Frostly counteracts the bug, so I'm happy with it, even though your code should be working fine all the way... I guess it's some sort of glitch due to Microsoft, and the behaviour is not always consistent!

  14. #34
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    Well, at least I can clean up the code from another browser... I hate that ugly block of unformatted code.
    [VBA]
    Sub TestBadStoryRanges()
    Dim r As Range
    For Each r In ActiveDocument.StoryRanges
    Select Case r.StoryType
    Case wdEvenPagesFooterStory, wdEvenPagesHeaderStory, wdFirstPageFooterStory, wdFirstPageHeaderStory,_
    wdPrimaryFooterStory, wdPrimaryHeaderStory
    ' r.Select
    Debug.Print Replace(r.Paragraphs.First.Range.Text, vbCr, "")
    End Select
    Next
    End Sub


    Sub TestGoodStoryRanges()
    Dim r As Range
    For Each r In fGetStoryRanges
    Debug.Print Replace(r.Paragraphs.First.Range.Text, vbCr, "")
    Next
    End Sub
    '----------------------------------------------------------------------------------------------
    'The MS StoryRanges collection is fundamentally broken when trying to search headers/footers
    'as well, since a for each loop doesn't return unlinked headers
    'This is an attempt to generate an accurate collection of story ranges for the passed document.
    'Uses the activedocument (if any) if no document is passed'doesn't currently return ranges of any textboxes
    '----------------------------------------------------------------------------------------------
    Public Function fGetStoryRanges(Optional oDoc As Document, _
    Optional bHeadersFootersOnly As Boolean = True,
    Optional bAddHeadersFootersOnlyIfShowing As Boolean = True) As Collection
    Dim colRet As Collection
    Dim rngStory As Range
    Dim hf As HeaderFooter
    Dim oSec As Section
    On Error GoTo l_err
    Set colRet = New Collection
    If oDoc Is Nothing Then
    Set oDoc = ActiveDocument
    End If
    'easy story ranges, if desired
    If bHeadersFootersOnly = False Then
    For Each rngStory In oDoc.StoryRanges
    Select Case rngStory.StoryType
    Case wdCommentsStory, wdFootnotesStory, wdEndnotesStory, wdMainTextStory
    colRet.Add rngStory.Duplicate
    End Select
    Next
    End If
    'headers/footers (for each of story ranges not reliable!!)
    For Each oSec In oDoc.Sections
    For Each hf In oSec.Headers
    'don't add linked ranges
    If hf.LinkToPrevious = False Or oSec.Index = 1 Then
    'don't add hidden ranges, unless specified
    If bAddHeadersFootersOnlyIfShowing And hf.Exists _
    Or bAddHeadersFootersOnlyIfShowing = False Then
    colRet.Add hf.Range.Duplicate
    End If
    End If
    Next


    For Each hf In oSec.Footers
    'don't add linked ranges
    If hf.LinkToPrevious = False Or oSec.Index = 1 Then
    'don't add hidden ranges, unless specified
    If bAddHeadersFootersOnlyIfShowing And hf.Exists _
    Or bAddHeadersFootersOnlyIfShowing = False Then
    colRet.Add hf.Range.Duplicate
    End If
    End If
    Next
    Next
    l_exit:
    Set fGetStoryRanges = colRet
    Exit Function
    l_err:
    'any errors, blackbox and return an empty collection
    Set colRet = New Collection
    Resume l_exit
    End Function
    [/VBA]

    For the OP - for your purposes, you could comment out the block which returns ranges not in the header/footer -- but I leave that in for this sample code, so others may see the parts of the story ranges collection which works, and the ones that don't

  15. #35
    VBAX Regular
    Joined
    Nov 2011
    Posts
    71
    Location
    Thanks Frosty!

  16. #36
    VBAX Regular
    Joined
    Nov 2011
    Posts
    71
    Location

    Arrow

    Hi guys,

    OK, after testing the different loops in my code, I have finally picked up macropod's first option, as it is easier to integrate within my code. Now, I did find lots of valuable information in all your suggestions, so thank you very much everyone for sharing on this topic! Frosty, your code is amazing indeed! fumei, you spent lots of time trying to educate me, and I really appreciate it! I know it was not an easy task ;-)

    macropod, the only major point I changed in your code was adding Frosty's suggestion "If .LinkToPrevious = False Or Sctn.Index = 1 Then", which seems to do the trick for the first section... ;-)

    Now, I still have a minor issue to solve.
    For my own purpose, I adapted the "find and replace" part, so I had to add first another loop, to make sure all my "tags" can be replaced before processing them. This is the part where I need further help:

    Dim TempStart As Integer
    Dim r, fnd As Range
    
    Set r = HdFt.Range
    Set fnd = HdFt.Range
    With fnd.Find
                    .Execute (Tag1)
                    TempStart = fnd.End
    End With
    Is there a way to know whether .Find found something, in which case I would update TempStart; if nothing is found, I don't want to update it...
    Last edited by glencoe; 02-07-2014 at 05:40 AM.

  17. #37
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    You should be able to use either .execute (which returns true if it's found) or .Found. Read up on help on the find object as well as the execute method. They tell you what they can do. This will also help you learn other items too.

    for section never... You already have that answer it's the .index property of the section object (which you're already using to make sure you process the first section's headers/footers (my addition to your code)

  18. #38
    VBAX Regular
    Joined
    Nov 2011
    Posts
    71
    Location
    Frosty,

    I actually tried adding this to the loop:

    With fnd.Find
         .Execute (Tag1)
         if .Execute = True then
              TempStart = fnd.End
         End if
    End With
    but this actually executes the search again! So I do need to read more about that indeed. Thanks for the tips, I will check them. I guess that .Found may probably work better (and is safer as well).

    As for my other issue, I found indeed that the .index property is showing the section number, so I deleted this part from my last post as I managed to solve it. But thanks for catching and confirming it anyway!

  19. #39
    VBAX Regular
    Joined
    Nov 2011
    Posts
    71
    Location
    Confirmed: this is my "final" code regarding all the issues I posted on this thread. As a note, Tag1 is given by the user in a textbox:

    Dim oSection As Section
    Dim HdFt As HeaderFooter
    Dim r, fnd As Range
    Dim Tag1 as string
    
    With ActiveDocument
                For Each oSection In .Sections
                    For Each HdFt In oSection.Headers
                        With HdFt
                            DoEvents
                            If .LinkToPrevious = False Or oSection.Index = 1 Then
                                HdFt.Range.Select
                                
                                'Find 1st Tag
                                Set r = HdFt.Range
                                Set fnd = HdFt.Range
                                With fnd.Find
                                    .Execute (Tag1)
                                    If .Found = True Then
                                        TempStart = fnd.End
                                    End If
                                End With
                                
                                'Do whatever else is required...
    
                            End if    
                        End With
                    Next HdFt
                Next oSection
    End With

  20. #40
    VBAX Master
    Joined
    Feb 2011
    Posts
    1,480
    Location
    I'm not sure that you need do events.

    Also, I really don't like multiple declares in a single line, at least one of the reasons you've demonstrated:
    dim r, fnd as range
    does not declare both items as a range. R is declared as a variant. You end up setting it to a range later, but this is probably not what you intended.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •