View Single Post
 
Old 03-29-2022, 02:28 PM
Macromate Macromate is offline Windows 10 Office 2021
Novice
 
Join Date: Mar 2022
Posts: 3
Macromate is on a distinguished road
Default

Hi Macropod,

If its not too much trouble, could you perhaps guide me on the fastest of way of making the code below work? I'm happy to strip down some functionality (since the area of the code that was showing the compile error allows for custom extracts (vs standard extracts) of comments and track changes. At this point, I'll sacrifice some 'add-on' bells and whistles to just be able to use the code to extract comments/track changes (with the formatting, context etc) to help me with my work.

Looking forward to hearing back from you.

Best,
Macromate

Code:
'============================================================================
'****************************************************************************
'************************  SmartExtract  ********************************
'****************************************************************************
'============================================================================

Sub wrkSmartExtract()
'=================================================================================================
'Extracts Comments and revisions from a source document
'Release 12 Nov 2015 Martin Coomber documentproductivity.blogspot.co.nz
'Finds the property containing the name of the source
'Source must be open, the tries to find the page number in the current paragraph
'Then goes to source and then to page
'UPDATED May - Added ability to get extract type
'=================================================================================================
    Dim dSrcDoc As Document
    Dim dExtractDoc As Document
    Dim iCnt As Integer
    Dim rRev As Revision
    Dim cCmt As Comment
    Dim bResetTrackChg As Boolean
 
    Dim iChgArray() As Long 'Col 1=Para Num, Col 2=Type(1=Rev,2=Cmt), 3=Index, 4=Start Pos, 5 = length (highlight)
    Dim iParaNum As Long
    Dim iType As Long
    Dim iIndex As Long
    Dim bMinorRevChg As Boolean
    
    Dim tExtTbl As Table
    Dim iTblRow As Integer
    Dim rTblRow As Row
    Dim bAddTableRow As Boolean
    
    Dim sAuthor As String
    Dim rChgRng As Range
    Dim sChgHdr As String
    Dim sChgText As String
    Dim iChgCnt As Integer
    Dim iMinorRevLen As Integer
    Dim iPageFormatLen As Integer

    Dim sCtxHdr As String
    Dim rCtxRng As Range
    Dim iCtxTblRow As Integer
    Dim sCtxRowCell1Text As String
    Dim bCtxWholePara As Boolean
    
    Dim bExtractComments As Boolean
    Dim bExtractRevisions As Boolean
    Dim bExtractHighlights As Boolean
    Dim sExtractAuthors As String
    Dim iHighlightCnt As Integer
    
    Set dSrcDoc = ActiveDocument
        
    'Added call to get extract type
    Call wrkGetExtractType(sExtractAuthors, bExtractComments, bExtractRevisions, bExtractHighlights, iHighlightCnt)
    If sExtractAuthors = "No Extract" Then Exit Sub
    
    'Here if valid
    Application.ScreenUpdating = False
    bResetTrackChg = False
    
    'Need to set this off so the cut and paste gets carries teh inserts and deletions
    If ActiveDocument.TrackRevisions = True Then
        ActiveDocument.TrackRevisions = False
        bResetTrackChg = True
    End If
    
    If dSrcDoc.Range.Information(wdNumberOfPagesInDocument) >= 100 Then
        iPageFormatLen = 3
    ElseIf dSrcDoc.Range.Information(wdNumberOfPagesInDocument) >= 10 Then
        iPageFormatLen = 2
    Else: iPageFormatLen = 1
    End If
         
    'Load the comments and revisons into the arrary, then sort into order in document
    ReDim iChgArray((dSrcDoc.Comments.Count + dSrcDoc.Revisions.Count + iHighlightCnt), 5)
    Call wrkPrepChgArray(dSrcDoc, sExtractAuthors, bExtractComments, bExtractRevisions, bExtractHighlights, iChgCnt, iChgArray())
    
    'Add New Document and insert the header infromation
    Set dExtractDoc = Documents.Add
    dExtractDoc.PageSetup.Orientation = wdOrientLandscape
    sChgHdr = "Comments extracted from:  " & dSrcDoc.Name & vbCr
    dExtractDoc.Range.Select
    Selection.InsertBefore (sChgHdr)
    Selection.Collapse (wdCollapseEnd)

    'Insert a 5-column table for the comments
    With dExtractDoc
        Set tExtTbl = .Tables.Add _
             (Range:=Selection.Range, numrows:=iChgCnt + 1, NumColumns:=5)
    End With
    'Now prepare the table for the revisions to be added into
    Call wrkSetupTable(tExtTbl)

    'Main routing
    iParaNum = 0
    iTblRow = 0
    iMinorRevLen = 6
    bCtxWholePara = True
    
    For iCnt = 1 To iChgCnt ' for each change
        'get the array values
        StatusBar = "Processing Extract " & iCnt & " of " & iChgCnt
        If iChgArray(iCnt, 1) = 0 Then Exit For 'got to the last row
        iType = iChgArray(iCnt, 2)
        iIndex = iChgArray(iCnt, 3)
        bAddTableRow = True
        sAuthor = ""
        
        If iType = 1 Then Set rRev = dSrcDoc.Revisions(iIndex)
        If iType = 2 Then Set cCmt = dSrcDoc.Comments(iIndex)
        
        'If this is a new paragrah in the sorted array, get the context of the change or comment
        If iParaNum <> iChgArray(iCnt, 1) Then
            iParaNum = iChgArray(iCnt, 1)
            bCtxWholePara = True
            bMinorRevChg = False
            If iType = 1 Then rRev.Range.Select
            If iType = 2 Then cCmt.Scope.Select
            If iType = 3 Then
                dSrcDoc.Range(iChgArray(iCnt, 4), iChgArray(iCnt, 4) + iChgArray(iCnt, 5)).Select
                
            End If
            'Get the contex
            sCtxHdr = "Page " & wrkPadLeftSpaces(Selection.Information(wdActiveEndPageNumber), iPageFormatLen) & ": Line " & wrkPadLeftSpaces(Selection.Information(wdFirstCharacterLineNumber), 2)
            If Selection.Information(wdWithInTable) Then
                iCtxTblRow = Selection.Information(wdStartOfRangeRowNumber)
                 sCtxRowCell1Text = wrkGetCtxRowCell1Text(iCtxTblRow)
                If Len(sCtxRowCell1Text) > 20 Then sCtxRowCell1Text = Left(sCtxRowCell1Text, 20) & "..."
                sCtxHdr = sCtxHdr & "  Table Row: " & sCtxRowCell1Text
                Set rCtxRng = Selection.Cells(1).Range
            Else
                Set rCtxRng = wrkGetParaBasedCtxRng(dSrcDoc, Selection.Range, bCtxWholePara)
            End If
        End If ' New Para
        
        'now process revisions
        Select Case iType
        Case 1 'revision
            With rRev
                sAuthor = .Author
                If Len(.Range.Text) <= iMinorRevLen Then 'is this a minor change?
                    If bMinorRevChg = False Then 'Initial Minor Change
                        bMinorRevChg = True
                        sChgHdr = "Minor Revision:"
                        Call wrkGetMinorChg(dSrcDoc, iChgArray(), iCnt, iChgCnt, iMinorRevLen, sChgText)
                    Else
                        bAddTableRow = False ' second minor change found
                    End If ' first minor change for para
                Else 'Major Change found
                    If .Type = wdRevisionInsert Then
                        sChgHdr = "Inserted:"
                    Else
                        sChgHdr = "Deleted:"
                    End If
                    sChgText = .Range.Text
                End If 'Major Change found
            End With 'rRev
        Case 2  'now process comments
            With cCmt
                sAuthor = .Author
                sChgHdr = "Comment " & .Initial & .Index & ":"
                sChgText = .Range.Text
            End With
        Case 3
            If iCnt > 1 Then
                If iChgArray(iCnt - 1, 4) = iChgArray(iCnt, 4) Then bAddTableRow = False 'Skip Highlight on inserted
            End If ' test if not first row
            sChgHdr = "Highlighted Text:"
            dSrcDoc.Range(iChgArray(iCnt, 4), iChgArray(iCnt, 4) + iChgArray(iCnt, 5)).Select
            sChgText = Selection.Range.Text
            
        End Select
        
        'If a row in the results table is to be added - wont add of not first minor change
        If bAddTableRow Then
            iTblRow = iTblRow + 1
            'Prepare the table entry
            With tExtTbl.Rows(iTblRow + 1)
                .Cells(1).Range.Text = iTblRow
                
                '--- Cell 2 ---
                Call wrkSelectCtxRange(rCtxRng, dSrcDoc, iParaNum)
                .Cells(2).Range.Paste
                If Not bCtxWholePara Then .Cells(2).Range.InsertBefore "     ..."
                .Cells(2).Range.InsertBefore sCtxHdr & vbCr
                'now remove bullets and lists and underline
                If .Cells(2).Range.Paragraphs(1).Range.ListFormat.ListType <> wdListNoNumbering Then _
                        .Cells(2).Range.Paragraphs(1).Range.ListFormat.RemoveNumbers NumberType:=wdNumberParagraph
                If .Cells(2).Range.Paragraphs(1).Range.HighlightColorIndex <> wdNoHighlight Then _
                        .Cells(2).Range.Paragraphs(1).Range.HighlightColorIndex = wdNoHighlight
                
                .Cells(2).Range.Paragraphs(1).Range.Font.Underline = wdUnderlineSingle
                '--- Cell 3 ---
                .Cells(3).Range.Text = sChgHdr & vbCr & sChgText
                .Cells(3).Range.Paragraphs(1).Range.Font.Underline = wdUnderlineSingle
                '--- Cell 4 ---
                .Cells(4).Range.Text = sAuthor
             End With
        End If 'adding table Row
    Next iCnt
    
    dSrcDoc.Activate
    Selection.HomeKey Unit:=wdStory
    ActiveWindow.View.ShowRevisionsAndComments = True
    
    If bResetTrackChg Then ActiveDocument.TrackRevisions = True
    dExtractDoc.Activate
        
    iCnt = 0 'Remove blank rows in the talble
    Do While tExtTbl.Rows.Last.Cells(1).Range.Characters.Count <= 1
        'until first non null row found
        tExtTbl.Rows.Last.Delete
        iCnt = iCnt + 1
        StatusBar = "Blank Table Row" & iCnt
    Loop
        
    'Remove source formatting in context col
    StatusBar = "Formatting Extract"
    tExtTbl.Columns(1).Select
    Selection.ParagraphFormat.Alignment = wdAlignParagraphCenter
    tExtTbl.Columns(2).Select
    With Selection
        .ParagraphFormat.Alignment = wdAlignParagraphLeft
        .Font.Size = 9
        .Font.Bold = False
        .ParagraphFormat.SpaceBefore = 0
        .ParagraphFormat.SpaceBefore = 0
    End With
    tExtTbl.Rows(1).Range.Font.Bold = True
    
    'Mark scope of comments and then delete them
    For Each cCmt In dExtractDoc.Comments
        cCmt.Scope.HighlightColorIndex = wdGray25
    Next cCmt
    Do While dExtractDoc.Comments.Count >= 1
        dExtractDoc.Comments(1).Delete
    Loop
    Call wrkAcceptAllFormatChanges("No Prompt")
    
    'Done
    Application.ScreenUpdating = True
    dExtractDoc.CustomDocumentProperties.Add Name:="dpSmartExtractSource", LinkToContent:=False, Type:=msoPropertyTypeString, Value:=dSrcDoc.Name
    Selection.HomeKey Unit:=wdStory

    MsgBox tExtTbl.Rows.Count - 1 & " entries written", , "SmartExtract"

End Sub
Function wrkPadLeftSpaces(vSource As Variant, iPadLength As Integer) As String
    wrkPadLeftSpaces = Right((Space(iPadLength) & vSource), iPadLength)
End Function
Function wrkGetCtxRowCell1Text(iCtxTblRow As Integer) As String
    'Separate routine so that if there are merged cells in the table, no error is generated
    wrkGetCtxRowCell1Text = iCtxTblRow
    On Error Resume Next
    wrkGetCtxRowCell1Text = wrkGetCellText(Selection.Tables(1).Rows(iCtxTblRow).Cells(1).Range)
End Function
Function wrkGetParaBasedCtxRng(dSrcDoc As Document, rChgRng, bCtxWholePara As Boolean) As Range
'=================================================================================================
'Ensures that there is at least 150 characters of context
'Release 12 Nov 2015 Martin Coomber documentproductivity.blogspot.co.nz
'Keeps adding paragraphs to the context until there are at least 150 characters in the context
' Assumes not in a table
'=================================================================================================
    Dim iStartPara As Long
    Dim iEndPara As Long
    Dim iChgStart As Long
    Dim iStartCtx As Long
    Dim iMinCtx As Long
    Dim iMaxCtx As Long
    Dim iReposCtx As Long
    
    
    iMinCtx = 30 ' min words in context
    iMaxCtx = 80 ' max words
    
    'set the start point for the change
    iChgStart = ActiveDocument.Range(0, rChgRng.Start).Words.Count
    
    'now get the paragraph range that the change occurs in
    Set wrkGetParaBasedCtxRng = rChgRng
    wrkGetParaBasedCtxRng.Select
    iStartPara = wrkGetParaNumSelection
    iEndPara = wrkGetParaNumSelection("End")
    
    'Now select the paragraph range
    wrkGetParaBasedCtxRng.SetRange Start:=dSrcDoc.Paragraphs(iStartPara).Range.Start, End:=dSrcDoc.Paragraphs(iEndPara).Range.End
    iStartCtx = ActiveDocument.Range(0, wrkGetParaBasedCtxRng.Start).Words.Count
    
    'now loop adding paragraphs
    Do While iStartPara > 1 And (iChgStart - iStartCtx) < iMinCtx
       If dSrcDoc.Paragraphs(iStartPara - 1).Range.Information(wdWithInTable) Then Exit Do
       iStartPara = iStartPara - 1
       wrkGetParaBasedCtxRng.SetRange Start:=dSrcDoc.Paragraphs(iStartPara).Range.Start, End:=wrkGetParaBasedCtxRng.End
       iStartCtx = ActiveDocument.Range(0, wrkGetParaBasedCtxRng.Start).Words.Count
    Loop
    If (iChgStart - iStartCtx) > iMaxCtx Then
        iReposCtx = (iChgStart - iMaxCtx) - iStartCtx
        wrkGetParaBasedCtxRng.MoveStart Unit:=wdWord, Count:=iReposCtx
         bCtxWholePara = False
    End If
End Function

Private Sub wrkGetMinorChg(dSrcDoc As Document, iChgArray() As Long, iCnt As Integer, iChgCnt As Integer, _
                            iMinorRevLen As Integer, sChgText As String)
'=================================================================================================
'Reads all changes for the same para and builds a string of minor changes
'Release 12 Nov 2015 Martin Coomber documentproductivity.blogspot.co.nz
'=================================================================================================
    Dim iNext As Long
    Dim iCurPara As Long
    Dim rChgRng As Range
       
    'First minor change
    iNext = iCnt
    iCurPara = iChgArray(iNext, 1)
    sChgText = dSrcDoc.Revisions(iChgArray(iNext, 3)).Range.Text
    
    iNext = iNext + 1
    Do
        If iNext > iChgCnt Then Exit Do ' - exits to handle last change
        If iChgArray(iNext, 1) <> iCurPara Then Exit Do 'next parra found - exits to handle last para in doc
        If iChgArray(iNext, 5) <= iMinorRevLen And iChgArray(iNext, 2) = 1 Then 'minor revision
            sChgText = sChgText & vbCr & dSrcDoc.Revisions(iChgArray(iNext, 3)).Range.Text
        End If
        iNext = iNext + 1
    Loop

End Sub

Private Sub wrkSelectCtxRange(rCtx As Range, dDoc As Document, iPara As Long)
'=================================================================================================
'Gets the range of the context
'Release 12 Nov 2015 Martin Coomber documentproductivity.blogspot.co.nz
'Has complex logic to handle changes arising from whole table row deleted
'=================================================================================================
    On Error GoTo CopyError
    rCtx.Copy
    Exit Sub ' simple copy worked fine - main flow
    'If the Ctx range cannot be copied - Cused by:1-whole table row deleted
CopyError:
    iPara = iPara - 1 ' error found - get the prev para
    Resume TryPrevPara
TryPrevPara:
    On Error GoTo CopyError
    dDoc.Paragraphs(iPara).Range.Copy
End Sub
Private Sub wrkSetupTable(tTable As Table)
'=================================================================================================
'Sets up the table where the extracts are loaded
'Release 12 Nov 2015 Martin Coomber documentproductivity.blogspot.co.nz
'=================================================================================================
    With tTable
        If .Style <> "Table Grid" Then
            .Style = "Table Grid"
        End If
        .Rows.AllowBreakAcrossPages = False
        .Range.Style = wdStyleNormal
        .Range.Font.Size = 9
        .AllowAutoFit = False
        .PreferredWidthType = wdPreferredWidthPercent
        .PreferredWidth = 100
        .Columns.PreferredWidthType = wdPreferredWidthPercent
        .Columns(1).PreferredWidth = 5
        .Columns(2).PreferredWidth = 40
        .Columns(3).PreferredWidth = 30
        .Columns(4).PreferredWidth = 10
        .Columns(5).PreferredWidth = 15
        .Rows(1).HeadingFormat = True
        If .Rows(1).Shading.BackgroundPatternColor = wdColorAutomatic Then
             .Rows(1).Shading.BackgroundPatternColor = wdColorGray10
        End If
    End With

    'Insert table headings
    With tTable.Rows(1)
        .Range.Font.Bold = True
        .Cells(1).Range.Text = "Item"
        .Cells(2).Range.Text = "Context"
        .Cells(3).Range.Text = "Comment or Revision"
        .Cells(4).Range.Text = "Author"
        .Cells(5).Range.Text = "Action"
   End With
End Sub
Private Sub wrkPrepChgArray(dDoc As Document, sExtractAuthors As String, bExtractComments As Boolean, _
                          bExtractRevisions As Boolean, bExtractHighlights As Boolean, iChgCnt As Integer, iChgArray() As Long)
'=================================================================================================
'Loads an arrary of changes - revisions, then comments, then sorts them into order in document
'Release 12 Nov 2015 Martin Coomber documentproductivity.blogspot.co.nz
'Skips all revisions except insertions and deletions
'Skips Table of contents changes
'UPDATED May 15 - to include flags for each type of extract
'=================================================================================================
    Dim rRev As Revision
    Dim cCmt As Comment
    Dim iParaNum As Long
    Dim bIncludeItem As Boolean
    Dim iCharNum As Long
    Dim sChgText As String
    Dim iPrevHighlightChar As Long
    Dim rHighlightRng As Range
    Dim iHighlightPrevStart As Long
       
    'Found instances of deleted revisions not seen in the UI haning around in the document - skip them
    On Error GoTo SkipDeletedRevisions
    iChgCnt = 0
    If bExtractRevisions Then
        For Each rRev In dDoc.Revisions
            With rRev
                bIncludeItem = False
                'Only include insertions and deletions
                If .Type = wdRevisionInsert Or .Type = wdRevisionDelete Then bIncludeItem = True
                'Exclude Author if not wanted
                If bIncludeItem Then
                    If sExtractAuthors <> "ALL" Then
                        If InStr(sExtractAuthors, .Author) = 0 Then bIncludeItem = False
                    End If
                End If
                
                'Skip contents changes
                If bIncludeItem Then 'First para may not be TOC in some scenarios
                    If InStr(.Range.Paragraphs(1).Style, "TOC") > 0 Then bIncludeItem = False
                End If
                If bIncludeItem And .Range.Paragraphs.Count >= 2 Then 'First para may not be TOC in some scenarios
                    If InStr(.Range.Paragraphs(2).Style, "TOC") > 0 Then bIncludeItem = False
                End If
                
                If bIncludeItem Then
                    iChgCnt = iChgCnt + 1
                    StatusBar = "Preparing Revsions. Item " & iChgCnt
    
                    .Range.Select
                    iParaNum = wrkGetParaNumSelection
                    iCharNum = Selection.Start
                    iChgArray(iChgCnt, 1) = iParaNum
                    iChgArray(iChgCnt, 2) = 1
                    iChgArray(iChgCnt, 3) = .Index
                    iChgArray(iChgCnt, 4) = iCharNum
                    iChgArray(iChgCnt, 5) = Len(.Range.Text)
                End If
            End With
        Next rRev
    End If
SkipDeletedRevisions:
    
    If bExtractComments Then
        For Each cCmt In dDoc.Comments
            With cCmt
                bIncludeItem = True
                If sExtractAuthors <> "ALL" Then
                    If InStr(sExtractAuthors, .Author) = 0 Then
                        bIncludeItem = False
                    End If
                End If
                If bIncludeItem Then
                    iChgCnt = iChgCnt + 1
                    StatusBar = "Preparing Comments, Item " & iChgCnt
                    .Scope.Select
                    iParaNum = wrkGetParaNumSelection
                    iCharNum = Selection.Start
                    iChgArray(iChgCnt, 1) = iParaNum
                    iChgArray(iChgCnt, 2) = 2
                    iChgArray(iChgCnt, 3) = .Index
                    iChgArray(iChgCnt, 4) = iCharNum
                End If
            End With
        Next cCmt
    End If
   
    If bExtractHighlights Then
        Set rHighlightRng = dDoc.Range
        rHighlightRng.Find.Highlight = True
        rHighlightRng.Find.Forward = True
        
        Do While rHighlightRng.Find.Execute
            If rHighlightRng.Start = iHighlightPrevStart Then Exit Do
            iHighlightPrevStart = rHighlightRng.Start
            rHighlightRng.Select
           
            iChgCnt = iChgCnt + 1
            StatusBar = "Preparing Highlights, Item " & iChgCnt
            iCharNum = Selection.Start
            iParaNum = wrkGetParaNumSelection
            iChgArray(iChgCnt, 1) = iParaNum
            iChgArray(iChgCnt, 2) = 3
            iChgArray(iChgCnt, 3) = 0
            iChgArray(iChgCnt, 4) = iCharNum
            iChgArray(iChgCnt, 5) = Len(Selection.Range.Text)
        Loop

    End If 'Extract Highlights
    
    iChgArray = wrkBubbleSort(iChgArray, 4, "Ascending", iChgCnt)
End Sub

Sub wrkGetExtractType(sExtractAuthors As String, bExtractComments As Boolean, _
                                            bExtractRevisions As Boolean, bExtractHighlights As Boolean, iHighlightCnt As Integer)
'=================================================================================================
'Determines what type of extract is needed - standard or custom
'Release 12 Nov 2015 Martin Coomber documentproductivity.blogspot.co.nz
'Sets a boolen for each type (cmt, rev, highlight) and a list of authors to extect (or All)
'Skips Table of contents changes
'=================================================================================================
    Dim rHighlightRng As Range
    Dim iHighlightPrevStart As Long
    Dim sInputVal As String
    Dim rRev As Revision
    Dim cCmt As Comment
    Dim iCnt As Integer
    Dim sRevAuthors(15) As String  'First 14 authors from 1-15
    Dim iRevCount(15, 2) As Integer '1=Comment Counts, 2= Revison Counts per author
    Dim i As Integer
    Dim iAuthorIndex As Integer 'current author
    Dim iAuthorMaxIndex As Integer ' Number of authors in doc
    Dim sAuthors As String 'String containing the names of the authors to extract
    Dim sAuthorIndex As String 'String showing the authors and comment and revision counts for each
    
    'Application.Sc5reenUpdating = False

    StatusBar = "Preparing revision statistcs"
    
    
    'First count the highlighed sections
    Set rHighlightRng = ActiveDocument.Range
    rHighlightRng.Find.Highlight = True
    rHighlightRng.Find.Forward = True
   
   
    Do While rHighlightRng.Find.Execute
        If rHighlightRng.Start = iHighlightPrevStart Then Exit Do
        iHighlightPrevStart = rHighlightRng.Start
        iHighlightCnt = iHighlightCnt + 1
        iHighlightPrevStart = rHighlightRng.Start
    Loop
    If iHighlightCnt > 0 Then
        bExtractHighlights = True
    Else
        bExtractHighlights = False
    End If
    'Assume otyher types are extected
    bExtractComments = True
    bExtractRevisions = True
    'bExtractHighlights = False
    sExtractAuthors = "ALL"
    
    sInputVal = wrkGetInput("The document contains:" & vbNewLine & vbNewLine & _
                            "     Comments: " & ActiveDocument.Comments.Count & vbNewLine & _
                            "     Revisions   : " & ActiveDocument.Revisions.Count & vbNewLine & _
                            "     Highlights : " & iHighlightCnt & vbNewLine & vbNewLine & _
                            "Perform Standard (full extract) or Custom extract? S/C", "SmartExtract", "S", "S|C", True)
    If sInputVal = "" Then
        sExtractAuthors = "No Extract"
        Exit Sub
    End If
    'Exit if Standard extract - the attribures are
    If sInputVal = "S" Then Exit Sub
    
    'here if custom extract
    iAuthorMaxIndex = 0
    iCnt = 0
    'Now count the  comments by author
    For Each cCmt In ActiveDocument.Comments
        With cCmt
            iCnt = iCnt + 1
            StatusBar = "Checking Comments. Item " & iCnt
            
            iAuthorIndex = 0
            For i = 1 To UBound(sRevAuthors)
                If sRevAuthors(i) = "" Then Exit For
                If sRevAuthors(i) = .Author Then
                    iAuthorIndex = i
                    Exit For
                End If
            Next i
            If iAuthorIndex = 0 And iAuthorMaxIndex < UBound(sRevAuthors) Then
                iAuthorMaxIndex = iAuthorMaxIndex + 1
                iAuthorIndex = iAuthorMaxIndex
                sRevAuthors(iAuthorIndex) = .Author
            End If
            If iAuthorIndex > 0 Then iRevCount(iAuthorIndex, 1) = iRevCount(iAuthorIndex, 1) + 1
        End With
    Next cCmt
    'Now count the revisions
    ' in some large documents  there may be deleted revisions - unclear why these are there - not seen in the UI
    On Error GoTo SkipDeletedRevisions
    iCnt = 0
    For Each rRev In ActiveDocument.Revisions
        With rRev
            'Only include insertions and deletions
            If .Type = wdRevisionInsert Or .Type = wdRevisionDelete Then
                iCnt = iCnt + 1
                StatusBar = "Checking Revsions. Item " & iCnt
                
                iAuthorIndex = 0
                For i = 1 To UBound(sRevAuthors)
                    If sRevAuthors(i) = "" Then Exit For
                    If sRevAuthors(i) = .Author Then
                        iAuthorIndex = i
                        Exit For
                    End If
                Next i
                If iAuthorIndex = 0 And iAuthorMaxIndex < UBound(sRevAuthors) Then
                    iAuthorMaxIndex = iAuthorMaxIndex + 1
                    iAuthorIndex = iAuthorMaxIndex
                    sRevAuthors(iAuthorIndex) = .Author
                End If
                If iAuthorIndex > 0 Then iRevCount(iAuthorIndex, 2) = iRevCount(iAuthorIndex, 2) + 1
              End If
        End With
    Next rRev
SkipDeletedRevisions:

    'Now build a string to show what authors are in the document
    sAuthors = ""
    For i = 1 To iAuthorMaxIndex
        If i > 1 Then sAuthors = sAuthors & vbNewLine
         sAuthors = sAuthors & " " & i & " " & sRevAuthors(i) & " - Cmts: " & iRevCount(i, 1) & " Revs: " & iRevCount(i, 2)
    Next i
    sExtractAuthors = ""
    sInputVal = wrkGetInput("The following authors are have made revisions: " & vbNewLine & vbNewLine & _
                                sAuthors & vbNewLine & vbNewLine & _
                            "Enter the number of each to extract separated by commas. Leave blank for all.", "SmartExtract", "", "", True)
    
    If sInputVal = "" Then
        sExtractAuthors = "ALL"
    Else
        sInputVal = "," & sInputVal & ","
        sExtractAuthors = "|"
        'Now get the names of the authors whose numbers had been entered
        For i = 1 To iAuthorMaxIndex
            sAuthorIndex = "," & i & ","
            If InStr(sInputVal, sAuthorIndex) > 0 Then
                sExtractAuthors = sExtractAuthors & sRevAuthors(i) & "|"
            End If
        Next i
    End If
    
    'Check if comments are extracted - decided to always ask for these even if there are none
    sInputVal = wrkGetInput("Extract Comments? Y/N", "SmartExtract", "Y", "Y|N", True)
    If sInputVal = "" Then
        sExtractAuthors = "No Extract"
        Exit Sub
    End If
    If sInputVal = "N" Then bExtractComments = False
    
    sInputVal = wrkGetInput("Extract Revisions? Y/N", "SmartExtract", "Y", "Y|N", True)
    If sInputVal = "" Then
        sExtractAuthors = "No Extract"
        Exit Sub
    End If
    If sInputVal = "N" Then bExtractRevisions = False
    
    'Only offer Highlight counts if there are any
    If bExtractHighlights Then
        sInputVal = wrkGetInput("Extract highlighted sections? Y/N", "SmartExtract", "Y", "Y|N", True)
        If sInputVal = "" Then
            sExtractAuthors = "No Extract"
            Exit Sub
        End If
        If sInputVal = "N" Then bExtractHighlights = False
    End If
    
    If Not bExtractComments And Not bExtractRevisions And Not bExtractHighlights Then
        sExtractAuthors = "No Extract"
        Exit Sub
    End If
    
    Application.ScreenUpdating = True
    
End Sub
    
Function wrkBubbleSort(InputArray As Variant, Optional SortColumn As Integer = 1, _
                          Optional SortOrder As String = "Ascending", _
                          Optional intMaxRows As Integer = 0) As Variant
'=============================================================================================
' Sort a 2-Dimension Array (Credit: Rajan Verma + DocumentProductivity)
' Parameter Info
' InputArray  : Array you want to Sort
' SortColumn  : on Which column you want to sort
' SortOrder   : xlAscending , xlDescending
' intMaxRows  : if >0 will sort only rows 1-MaxRow.  Leaves null rows untouched
'=============================================================================================
    Dim intFirst As Integer
    Dim intLast  As Integer
    Dim intFirstCol As Integer
    Dim intLastCol  As Integer
    Dim sngTemp     As Single
    Dim lngLoop1    As Integer
    Dim i           As Integer
    Dim j           As Integer
    Dim blnFlag     As Boolean
    Dim blnSort     As Boolean
    
    If Not IsArray(InputArray) Then
        blnFlag = True
        GoTo ExitEarly:
    End If
    
    intFirst = LBound(InputArray, 1)
    If intMaxRows > 0 Then
        intLast = intMaxRows
    Else
        intLast = UBound(InputArray, 1)
    End If
    intFirstCol = LBound(InputArray, 2)
    intLastCol = UBound(InputArray, 2)
    StatusBar = "Sorting..."
    For i = intFirst To intLast - 1

        For lngLoop1 = i + 1 To intLast
            If SortOrder = "Ascending" Then
                If InputArray(i, SortColumn) > InputArray(lngLoop1, SortColumn) Then blnSort = True
            Else
                If InputArray(i, SortColumn) < InputArray(lngLoop1, SortColumn) Then blnSort = True
            End If
                If blnSort Then
                    For j = intFirstCol To intLastCol
                        sngTemp = InputArray(lngLoop1, j)
                        InputArray(lngLoop1, j) = InputArray(i, j)
                        InputArray(i, j) = sngTemp
                    Next j
                End If
            blnSort = False
        Next lngLoop1
    Next i
    wrkBubbleSort = InputArray
ExitEarly:
    If blnFlag Then wrkBubbleSort = Null
End Function

'=================================================================================================
'========= Small routines =========================================================================
'=================================================================================================

Sub wrkAcceptAllFormatChanges(sPrompt As String)
'=================================================================================================
'Accepts all format changes in a document
'Release 12 Nov 2015 Martin Coomber documentproductivity.blogspot.co.nz
'Used a standalone routine and also as part of SmartExtract to clean up the extracted text
'================================================================================================
    Dim rRev As Revision
    Dim iCnt As Long
    Dim sInputVal As String
    Dim iRevCnt As Integer
    Dim iRev As Integer
    Dim bAcceptRev As Boolean

    
    If sPrompt = "Prompt" Then
        If ActiveDocument.Revisions.Count = 0 Then
            MsgBox "There are no changes in this document to accept"
            Exit Sub
        Else
            sInputVal = wrkGetInput("Do You want to Accept all Formatting Changes? Y/N", _
                                    "Accept Formatting Changes", "Y", "Y|N", True)
            If sInputVal <> "Y" Then
                Exit Sub
            End If
        End If
    End If ' Propmt
    'here if valid
    'Need to skip deleted revisions that hang around in some large documents
On Error GoTo SkipDeletedRevisions
    iRevCnt = ActiveDocument.Revisions.Count
    For Each rRev In ActiveDocument.Revisions
        iRev = iRev + 1
        StatusBar = "Checking revision " & iRev & " of " & iRevCnt
        bAcceptRev = False
        With rRev
            If Not bAcceptRev And .Range.Paragraphs.Count >= 2 Then ' First parara
                If InStr(.Range.Paragraphs(2).Style, "TOC") > 0 Then bAcceptRev = True
            End If
            If Not bAcceptRev And (.Type = wdRevisionProperty Or _
                                    .Type = wdRevisionTableProperty Or _
                                    .Type = wdRevisionParagraphProperty) Then bAcceptRev = True
            If bAcceptRev Then
                rRev.Accept
                iCnt = iCnt + 1
            End If
        End With
    Next rRev
SkipDeletedRevisions:
     If sPrompt = "Prompt" Then MsgBox iCnt & " Formatting changes were accepted"
 End Sub

'============================================================================
'****************************************************************************
'************************  Smart Bookmark  ********************************
'****************************************************************************
'============================================================================
Sub dpSmartBookmark()
'=================================================================================================
'First use drops a bookmark, second use returns to the initial bookmark
'Release 13 Apr 2016 Martin Coomber documentproductivity.blogspot.co.nz
'If the intitial bookmark isnt returned to after 5 mins, a new return location will be started
'If double pressed, got to top of doc
'Goes to the SmartExtract source location if used in a smart extract cell
'assgined to Ctl+`
'=================================================================================================
    Dim nTimerDiff As Single
        
    'First check if the Goto call is inside a smartextract document. If so, goto the page
    If wrkDocPropExists("dpSmartExtractSource") Then 'Current document was created by SmartExtract,
        'Go to correct page in the source document
        Call wrkGotoSmartExtract
        Exit Sub
    End If
    
    nTimerDiff = Timer - glbSmtBmkLast
    
    If ActiveDocument.Bookmarks.Exists("dpTempGoto") = True Then
        If nTimerDiff > 900 Then 'After 5 mins begin a return location
            ActiveDocument.Bookmarks("dpTempGoto").Delete
            ActiveDocument.Bookmarks.Add Name:="dpTempGoto", Range:=Selection.Range
            StatusBar = "Bookmark Dropped"
            glbSmtBmkLast = Timer
        ElseIf nTimerDiff > 1 Then 'single press with existing bookmark means return
            Selection.GoTo what:=wdGoToBookmark, Name:="dpTempGoto"
            ActiveDocument.Bookmarks("dpTempGoto").Delete
            StatusBar = "Returned to Bookmark"
        Else 'Double press
            ActiveDocument.Bookmarks("dpTempGoto").Delete
            ' Got to TOC or top of document
            If ActiveDocument.TablesOfContents.Count >= 1 Then
                Selection.HomeKey Unit:=wdStory
                Selection.GoTo what:=wdGoToField, Which:=wdGoToNext, Count:=1, Name:="TOC"
                StatusBar = "Moved to Table of Contents"
            Else
                Selection.HomeKey Unit:=wdStory
                StatusBar = "Moved to Beginning"
            End If
        End If
    Else
        ActiveDocument.Bookmarks.Add Name:="dpTempGoto", Range:=Selection.Range
        StatusBar = "Bookmark Dropped"
        glbSmtBmkLast = Timer
    End If

End Sub
Private Sub wrkGotoSmartExtract()
'=================================================================================================
'Goes to the correct page in the source document for SmartExtract
'Release 13 Apr 2016 Martin Coomber documentproductivity.blogspot.co.nz
'Finds the property containing the name of the source
'Source must be open, the tries to find the page number in the current paragraph
'Then goes to source and then to page
'=================================================================================================
    Dim sSrcName As String
    Dim sHeaderText As String
    Dim bDocumentFound As Boolean
    Dim dDoc As Document
    Dim sPageNum As String
    
    sHeaderText = "Comments extracted from:  "
    bDocumentFound = False
    
    'The name of the soruce document is stored in this propert
    If wrkDocPropExists("dpSmartExtractSource") Then
        'get the page number
        If Left(Selection.Range.Paragraphs(1).Range.Text, 5) = "Page " And _
            InStr(Selection.Range.Paragraphs(1).Range.Text, ":") Then
            sPageNum = Mid(Selection.Range.Paragraphs(1).Range.Text, 6, InStr(Selection.Range.Paragraphs(1).Range.Text, ":") - 6)
        End If
        
        'Now check that the document is open
        sSrcName = ActiveDocument.CustomDocumentProperties("dpSmartExtractSource").Value
        For Each dDoc In Documents
            If dDoc.Name = sSrcName Then
                bDocumentFound = True
                Exit For
            End If
        Next dDoc
    End If
    
    'if document is found then go to the relevant page, if not error.
    If bDocumentFound Then
        dDoc.Activate
        If Val(sPageNum) > 0 Then Selection.GoTo what:=wdGoToPage, Which:=wdGoToAbsolute, Count:=Val(sPageNum)
    Else
        MsgBox "The following SmartExtact source is not open." & vbCr & sSrcName, , "SmartExtract"
    End If
End Sub