Collaborative editing makes writing documents within a workgroup easier, but then you have to clean up the mess of highlights and edits. Visual Basic for Applications can help make the job easier.
Many companies use collaboration tools to create documentation
that reflects the knowledge and abilities of a team, often in a
short timeframe. Everyone works with a single document, marking it
up with their personal highlighting, notes, and edits.
Unfortunately, the resulting mess can be difficult to clean up,
especially if you want to retain some of the edits, accept others,
and delete still others. Performing the task by hand isn't
impossible, but it's time consuming and may be error prone.
Unfortunately, without a carefully created macro, using automation
might destroy the very information you want to keep.
Fortunately, Microsoft Office provides great programmatic access
to edits on a page. All you need to know is what to look for and
what you want as output from the automation.
ADVERTISEMENT
There's three steps. First, consider what to do with all the
highlights. (Some might be important, so deleting all of them isn't
a good idea. Second, decide what to do with the actual edits. You
may decide to accept all the edits, or perform the task manually;
but in some cases, you can use a reviewer's name or other flag to
determine whether to remove, leave, or accept the edit. Third, if
your company uses the Word annotation feature, you need to clean up
the annotations you no longer need.
Removing Unneeded Highlights
If the document's authors don't use Word's revision marking, they need to mark "whose text is whose" in some other way. Typically, each author uses a different color. To remove the highlights that are no longer necessary, we expect each member of the collaborative
team to use a separate color, or for each kind of highlight in the document to be color-highlighted. Unless the
color has a specific meaning, you can't remove it using automation,
which means you'll send a lot of time deciding whether to keep the
highlight manually.
Deciding on an editing technique at the outset saves a lot of
time. Listing 1 demonstrates how to locate and remove a particular
highlight from a Word document, without disturbing other highlights
the document might contain.
Listing 1: Removing Highlights from a Word
Document
Public Sub RemoveHighlight()
' Make sure you can access the pane properly.
Application.ActiveWindow.View = wdNormalView
' Holds the current pane.
Dim CurrPane As Pane
' Access the test document pane.
Set CurrPane = Application.ActiveWindow.ActivePane
' Go to the beginning of the document.
CurrPane.Selection.GoTo wdGoToLine, wdGoToFirst
' Create a form for getting the color choice.
Dim GetColor As ColorChoice
Set GetColor = New ColorChoice
' Show the form.
GetColor.Show
' Determine the return value. If the user cancelled, exit the Sub.
If Not GetColor.Submitted Then
MsgBox "Form Cancelled"
Exit Sub
End If
' Creates a search for the word.
Dim DoSearch As Find
Set DoSearch = CurrPane.Selection.Find
' Perform the search.
With DoSearch
' Clear any existing formatting information.
.ClearFormatting
.Highlight = True
.MatchCase = False
.Wrap = wdFindContinue
' Continue until there is nothing else to search.
While DoSearch.Execute()
' Remove the highlight as needed.
With CurrPane.Selection.FormattedText
If .HighlightColorIndex = GetColor.SelectedColor Then
.HighlightColorIndex = wdNoHighlight
End If
End With
' Move to the next character.
CurrPane.Selection.Move Count:=1
Wend
End With
' Go to the beginning of the document.
CurrPane.Selection.GoTo wdGoToLine, wdGoToFirst
End Sub
The code must make a few changes to the user settings to ensure
the highlights are removed accurately. The first change is to
modify the view to the Normal View. These other views, such as
Outline View, can present problems when you look for a particular
kind of formatting. Next, the code creates the CurrPane object,
which points to the current pane. It uses this object to move the
cursor to the beginning of the document to make it easier to
search. Theoretically, you don't have to make this change, but it's
easier when you do.
Now that the environment is prepared, the code displays a dialog
box containing the 15 standard highlight colors. The user selects
the color of choice and either submits the selection or cancels. If
the user clicks Cancel, the macro ends.
It's interesting to note that the code uses a standard Word
search to locate the highlight. The next task the code performs is
to create a search; notice that the ClearFormatting() method
ensures old formatting selections are removed. The DoSearch object
can locate a highlight, but it can't search for a particular kind
of highlight. Because the search criteria only includes
highlighting, every call to DoSearch.Execute()is guaranteed to
locate a highlight in the document until the entire document is
searched. The search process automatically selects the entire
highlight.
To determine whether the current highlight is the right color,
the code relies on the HighlightColorIndex property. It compares
this value with the GetColor.SelectedColor property (the return
value from the dialog box). When the two values match, the code
sets the current selection to wdNoHighlight, which clears the
highlight.
The search would end immediately after the first highlight
matched highlight. The selected text doesn't contain a highlight
and the code hasn't told DoSearch to look in the rest of the
document. The way around this problem is to move the cursor to the
next character in the document and then perform the next
DoSearch.Execute() call. When the loop finally fails, all of the
highlights of the selected color are removed. The code places the
cursor at the beginning of the document.
Accepting, Rejecting, or Leaving Specific
Edits
Word's tracking feature is amazing, because it keeps track of
everyone who edits the document and precisely what changes they
made. Unfortunately, it's difficult to access this information. The
only way to work with edits, for the most part, is to check them
out one at a time. Unfortunately, you can make errors working with
revision marks this way, especially if, for example, you want to
track down changes made after a certain time and date. Listing 2
shows one way to track various changes and choose to accept or
reject just the changes you want.
Listing 2: Accepting or Rejecting a Single Change
Type
Public Sub CheckEdits()
' Make sure you can access the pane properly.
Application.ActiveWindow.View = wdNormalView
' Holds the current pane.
Dim CurrPane As Pane
' Access the test document pane.
Set CurrPane = Application.ActiveWindow.ActivePane
' Go to the beginning of the document.
CurrPane.Selection.GoTo wdGoToLine, wdGoToFirst
' Create a RevisionChoice dialog box.
Dim RevTarget As RevisionChoice
Set RevTarget = New RevisionChoice
' Get the target revision.
RevTarget.Show
' Determine the return value. If the user cancelled, exit the Sub.
If Not RevTarget.Submitted Then
MsgBox "Form Cancelled"
Exit Sub
End If
' Create a Revision object.
Dim ThisRev As Revision
' Get the next Revision.
Set ThisRev = CurrPane.Selection.NextRevision
' Handle each revision in a loop.
While Not ThisRev Is Nothing
' Make sure this is the right kind of edit.
If ThisRev.Type = RevTarget.ChangeType Then
' If this is a formatting change. verify it is the correct
' type.
If RevTarget.ChangeType = wdRevisionProperty Then
If InStr(1, _
ThisRev.FormatDescription, _
RevTarget.FormatChange, _
vbTextCompare) > 0 Then
' Perform the correct action.
If RevTarget.AcceptChange Then
ThisRev.Accept
Else
ThisRev.Reject
End If
End If
Else
' Perform the correct action.
If RevTarget.AcceptChange Then
ThisRev.Accept
Else
ThisRev.Reject
End If
End If
End If
' Get the next Revision.
Set ThisRev = CurrPane.Selection.NextRevision
Wend
End Sub
The code begins by creating CurrPane again. It sets up the pane,
as in Listing 1, with the display set to Normal View and the cursor
at the beginning of the text. The code displays a dialog box that
lets the user choose which edits to accept or reject. In this case,
the example concentrates on insertions, deletions, replacements,
format changes, and style changes, but you can modify any change
and even tie it to a particular author if you wish.
This time the code doesn't rely on a search to find the target
edit: it uses a special Revision object. To find a revision with
the current document, you must make sure that none of the text is
selected. The CurrPane.Selection.NextRevision() method loads
ThisRev with the current revision. If there aren't any revisions
(or not any more in the current document), then ThisRev will equal
Nothing. Consequently, you can perform this check in a loop and
locate every revision in the document.
All the information the code needs is in one of the ThisRev
properties. The example code shows several, but not all of these
properties. The first check you perform depends on the kind of
revision mark you want to control. In this example, the focus is on
a specific type of edit, so the code focuses on the ChangeType
property. Most changes are straightforward, but formatting changes
aren't. To determine whether a change is the right type, you must
first look for the wdRevisionProperty ChangeType. Unfortunately,
this can include any property change, not just character
formatting, so the code narrows the search by checking the
ThisRev.FormatDescription property. This property is a string that
describes the format changes, so you can create an InStr() function
setup that locates a particular formatting change such as bold or
italic print.
Accepting or rejecting a change is relatively easy once you
determine the action the user wants to take. Simply use the
Accept() or Reject() method as shown in the code.
You can even use automation to fix errors. For example, someone
might use the strikethrough font to delete text, rather than
actually delete it. On screen, the changes look similar enough that
you could miss one and fixing such an error by hand would be time
consuming. Using automation would let you convert the
strikethroughs to deleted text in a matter of moments.
Removing Annotation
Word's annotation feature (or comments, depending on the version
of Office you use) lets you highlight a specific area of text in
the document, and comment on it without changing the document
formatting or flow. Reading the comment is as easy as hovering the
mouse over it or viewing it in the Reviewing Pane.
However, cleaning up after someone who uses the annotation
feature isn't easy. Normally, you have to remove annotation
individually. Listing 3 shows a way to remove one reviewer at a
time.
Listing 3: Removing Unneeded Annotation
Public Sub RemoveAnnotation()
' Get the reviewer's name.
Dim RevName As String
RevName = InputBox("Type the name of the reviewer", _
"Remove Reviewer Comments")
' Create an individual comment.
Dim ThisComment As Comment
' Process the comments one at a time.
For Each ThisComment In Application.ActiveDocument.Comments
' When the comment author and the requested name match,
' delete the comment.
If ThisComment.Author = RevName Then
ThisComment.Delete
End If
Next
End Sub
This code is actually relatively simple compared to the other
examples in this article. The comments don't require any type of
special search, because Office compiles them into a Comments
collection. You can even use a For Each... Next loop to process
them.
The code begins by getting the reviewer name using an
InputBox(). There isn't a good reason to use anything more complex
in this case.
Once the code has the name, it starts processing the comments in
a loop. During each pass of the loop, the code checks the reviewer
name against the Comment object Author property. When the two
match, a simple call to Delete() removes the comment. You can also
use an alternative strategy of checking the reviewer initials
against the ThisComment.Initial property.
The Bottom Line
Many Office users struggle through hours of mundane and
frustrating work cleaning up revision marks in their documents and
hoping that nothing gets changed incorrectly in the interim. Even
though Office applications, such as Word, don't make the process
any easier, they do provide the tools needed to automate the clean
up process given a little input.
You could easily script this process based on standard
company guidelines and reduce the cleanup process to answering a
few questions. With a little more work, you could create a wizard
that would take care of all the required inputs and keep the level
of required user interaction to a minimum. The result is that
cleanup takes seconds, not hours, and is always done
perfectly.