VBCommons/word/ex_Word.bas

227 lines
7.3 KiB
QBasic
Raw Normal View History

2024-06-07 20:46:40 +03:00
Attribute VB_Name = "ex_Word"
'================ Word helper functions =============
' Shared module version: 20220911
' Tested in: TestWord
' Depends on:
' Required reference:
Option Private Module
Option Explicit
Public Function WordIntersectRanges(rng1 As Word.Range, rng2 As Word.Range) As Word.Range
If rng1.Document <> rng2.Document Then _
Exit Function
If rng1.Start >= rng2.End Or rng2.Start >= rng1.End Then _
Exit Function
If rng1.Start >= rng2.Start Then
If rng2.End > rng1.Start Then _
Set WordIntersectRanges = rng1.Document.Range(rng1.Start, IIf(rng1.End > rng2.End, rng2.End, rng1.End))
Else
If rng1.End > rng2.Start Then _
Set WordIntersectRanges = rng1.Document.Range(rng2.Start, IIf(rng1.End > rng2.End, rng2.End, rng1.End))
End If
End Function
Public Function WordPutText(sText$, iDoc As Word.Document, nWhere&, Optional aStyle$ = vbNullString) As Word.Range
Set WordPutText = iDoc.Range(nWhere, nWhere)
With WordPutText
Call .InsertAfter(sText)
If aStyle <> vbNullString Then _
.Style = aStyle
End With
End Function
Public Function WordAppendTo(sText$, ByRef rWhere As Word.Range, Optional aStyle$ = vbNullString) As Word.Range
Const ASCII_NEWLINE = 13
If rWhere.Characters.Count > 0 Then _
If AscW(rWhere.Characters.Last) = ASCII_NEWLINE Then _
Call rWhere.MoveEnd(wdCharacter, -1)
Call rWhere.InsertAfter(sText)
Dim insertedRng As Word.Range: Set insertedRng = rWhere.Duplicate
insertedRng.Start = rWhere.End - VBA.Len(sText)
If aStyle <> vbNullString Then _
insertedRng.Style = aStyle
Set WordAppendTo = insertedRng
End Function
Public Function WordAddLine(sText$, rWhere As Word.Range, Optional aStyle$ = vbNullString) As Word.Range
Dim nEnd&: nEnd = rWhere.End
If rWhere.Tables.Count > 0 Then
If rWhere.Cells.Count > 0 Then
Dim theLastCell As Word.Cell: Set theLastCell = rWhere.Cells(rWhere.Cells.Count)
If nEnd >= theLastCell.Range.End - 1 Then
Set WordAddLine = AddLineLastInCell(sText, theLastCell, aStyle)
GoTo SAFE_EXIT
End If
End If
End If
Dim nParaEnd&: nParaEnd = rWhere.Paragraphs.Last.Range.End
If rWhere.End = rWhere.Document.Range.End Then
Call rWhere.InsertAfter(vbNewLine)
Set WordAddLine = WordPutText(sText, rWhere.Document, rWhere.End - 1, aStyle)
Call WordAddLine.MoveEnd(wdCharacter, 1)
GoTo SAFE_EXIT
End If
If nEnd <> nParaEnd Then
If rWhere.Next(wdCharacter, 1).End = nParaEnd Then
Call rWhere.MoveEnd(wdCharacter, 1)
Else
Call rWhere.InsertAfter(vbNewLine)
End If
End If
Set WordAddLine = WordPutText(sText & vbNewLine, rWhere.Document, rWhere.End, aStyle)
SAFE_EXIT:
rWhere.End = nEnd
End Function
Public Function WordFindAndReplace(iDoc As Word.Document, findText$, ReplaceText$, _
Optional mCase As Boolean = False, _
Optional wildCard As Boolean = False, _
Optional wholeWord As Boolean = True) As Long
Dim findRange As Word.Range: Set findRange = iDoc.Range
Dim nResult&: nResult = 0
With findRange.Find
.Text = findText
.MatchCase = mCase
.MatchWholeWord = wholeWord
.MatchWildcards = wildCard
.Replacement.Text = ReplaceText
.Format = True
.Font.Hidden = False
Do While .Execute(Replace:=1)
nResult = nResult + 1
Call findRange.Collapse(Direction:=wdCollapseEnd)
Loop
End With
WordFindAndReplace = nResult
End Function
Public Function WordDeleteHyperlinks(iDoc As Word.Document) As Long
On Error Resume Next
WordDeleteHyperlinks = 0
Do Until iDoc.Hyperlinks.Count = 0
Call iDoc.Hyperlinks(1).Delete
WordDeleteHyperlinks = WordDeleteHyperlinks + 1
Loop
End Function
Public Function WordStyleExists(iDoc As Word.Document, target$) As Boolean
WordStyleExists = True
On Error GoTo RET_FALSE
Dim aStyle As Word.Style: Set aStyle = iDoc.Styles(target)
Exit Function
RET_FALSE:
WordStyleExists = False
End Function
' Requires: wordApp should be Application, responsible for both documents (if any or both are open)
Public Function WordCopyStyle(wordApp As Word.Application, sSource$, sDestination$, sStyle$) As Boolean
WordCopyStyle = True
On Error GoTo RETURN_FALSE
Call wordApp.OrganizerCopy(sSource, sDestination, sStyle, wdOrganizerObjectStyles)
On Error GoTo 0
Exit Function
RETURN_FALSE:
WordCopyStyle = False
End Function
Public Function WordStyleIsUsed(iDoc As Word.Document, aStyle As Word.Style) As Boolean
On Error Resume Next
Dim findRange As Word.Range: Set findRange = iDoc.Range
With findRange.Find
.Text = vbNullString
.Format = True
.Style = aStyle
WordStyleIsUsed = .Execute
End With
End Function
Public Function WordAdjustRange(target As Word.Range) As Word.Range
Dim rExpansion As Word.Range: Set rExpansion = target.Duplicate
If Not rExpansion.Characters.First Like "[" & " " & Chr(160) & "]" Then
Call rExpansion.StartOf(wdWord, wdExtend)
Call rExpansion.MoveStartWhile("""'<27><><EFBFBD><EFBFBD>", wdBackward)
End If
If rExpansion.Start <> rExpansion.End Then _
Call rExpansion.EndOf(wdWord, wdExtend)
If Not rExpansion.Characters.Last Like "[" & " " & Chr(160) & "]" Then
Call rExpansion.MoveEndWhile("""'<27><><EFBFBD><EFBFBD>", wdForward)
Call rExpansion.MoveEndWhile(" " & Chr(160), wdForward)
End If
Set WordAdjustRange = rExpansion
End Function
Public Function AcceptAuthorsRevision(oAuthors As Collection, target As Word.Document) As Long
AcceptAuthorsRevision = 0
Dim itemChange As Word.Revision
For Each itemChange In target.Revisions
Dim sAuthor As Variant
For Each sAuthor In oAuthors
If sAuthor = itemChange.Author Then
Call itemChange.Accept
AcceptAuthorsRevision = AcceptAuthorsRevision + 1
GoTo NEXT_ITEM
End If
Next sAuthor
NEXT_ITEM:
Next itemChange
End Function
Public Function AcceptFormatRevision(iDoc As Word.Document) As Long
AcceptFormatRevision = 0
Dim itemChange As Word.Revision
Dim theType As WdRevisionType
For Each itemChange In iDoc.Revisions
theType = itemChange.Type
If theType = wdRevisionParagraphProperty Or _
theType = wdRevisionStyle Or _
theType = wdRevisionProperty Then
itemChange.Accept
AcceptFormatRevision = AcceptFormatRevision + 1
End If
Next itemChange
End Function
Public Function StyleByName(sStyle$, iDoc As Word.Document) As Word.Style
On Error GoTo RETURN_NOTHING
Set StyleByName = iDoc.Styles(sStyle)
RETURN_NOTHING:
End Function
Public Function ExtractCommentText(target As Word.Range) As String
If target.Comments.Count <> 0 Then
ExtractCommentText = target.Comments(1).Range.Text
Exit Function
End If
Dim theDoc As Word.Document: Set theDoc = target.Document
Dim aComment As Word.Comment
For Each aComment In theDoc.Comments
If target.InRange(aComment.Scope) Then
ExtractCommentText = aComment.Range.Text
Exit Function
End If
Next aComment
ExtractCommentText = vbNullString
End Function
' =====
Private Function AddLineLastInCell(sText$, whereCell As Word.Cell, aStyle$) As Word.Range
Dim nWhere&: nWhere = whereCell.Range.End - 1
If whereCell.Range.Characters.Count > 1 Then
Call WordPutText(vbNewLine, whereCell.Range.Document, nWhere)
nWhere = nWhere + 1
End If
Set AddLineLastInCell = WordPutText(sText, whereCell.Range.Document, whereCell.Range.End - 1, aStyle)
End Function