<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_Writer" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
REM ===			The ScriptForge library and its associated libraries are part of the LibreOffice project.				===
REM	===						The SFDocuments library is one of the associated libraries.									===
REM ===					Full documentation is available on https://help.libreoffice.org/								===
REM =======================================================================================================================

Option Compatible
Option ClassModule

Option Explicit

&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
&apos;&apos;&apos;	SF_Writer
&apos;&apos;&apos;	=========
&apos;&apos;&apos;
&apos;&apos;&apos;		The SFDocuments library gathers a number of methods and properties making easy
&apos;&apos;&apos;		managing and manipulating LibreOffice documents
&apos;&apos;&apos;
&apos;&apos;&apos;		Some methods are generic for all types of documents: they are combined in the SF_Document module.
&apos;&apos;&apos;		Specific properties and methods are implemented in the concerned subclass(es) SF_Calc, SF_Writer, SF_Base, ...
&apos;&apos;&apos;
&apos;&apos;&apos;		To workaround the absence of class inheritance in LibreOffice Basic, some redundancy is necessary
&apos;&apos;&apos;		Each subclass MUST implement also the generic methods and properties, even if they only call
&apos;&apos;&apos;		the parent methods and properties.
&apos;&apos;&apos;		They should also duplicate some generic private members as a subset of their own set of members
&apos;&apos;&apos;
&apos;&apos;&apos;		The SF_Writer module is focused on selecting, reading, inserting, modifying texts and values
&apos;&apos;&apos;		on well-identified and predefined places in the document.
&apos;&apos;&apos;		Usually such customization of the document starts from a predefined template.
&apos;&apos;&apos;		Multiple customizations are also known as mail merging.
&apos;&apos;&apos;
&apos;&apos;&apos;		As a consequence, focus is not on text formatting, except by the application of styles
&apos;&apos;&apos;		onto the targeted text fragments.
&apos;&apos;&apos;
&apos;&apos;&apos;		The positions in the text where customization can take place easily are:
&apos;&apos;&apos;			- the start and end positions of the text body
&apos;&apos;&apos;			- the start and end positions of text frames
&apos;&apos;&apos;			- bookmarks
&apos;&apos;&apos;			- text fields
&apos;&apos;&apos;			- the start and end positions of document sections
&apos;&apos;&apos;			- writer tables and table cells
&apos;&apos;&apos;			- the area currently selected by the user, i.e. the &quot;visible&quot; selection
&apos;&apos;&apos;
&apos;&apos;&apos;		The current module is closely related to the &quot;UI&quot; service of the ScriptForge library
&apos;&apos;&apos;
&apos;&apos;&apos;		Service invocation examples:
&apos;&apos;&apos;		1) From the UI service
&apos;&apos;&apos;			Dim ui As Object, oDoc As Object
&apos;&apos;&apos;			Set ui = CreateScriptService(&quot;UI&quot;)
&apos;&apos;&apos;			Set oDoc = ui.CreateDocument(&quot;Writer&quot;, ...)
&apos;&apos;&apos;				&apos; or Set oDoc = ui.OpenDocument(&quot;C:\Me\MyFile.odt&quot;)
&apos;&apos;&apos;		2) Directly if the document is already opened
&apos;&apos;&apos;			Dim oDoc As Object
&apos;&apos;&apos;			Set oDoc = CreateScriptService(&quot;SFDocuments.Writer&quot;, ThisComponent)	&apos;	Default = ActiveWindow
&apos;&apos;&apos;				&apos; or Set oDoc = CreateScriptService(&quot;SFDocuments.Writer&quot;, &quot;Untitled 1&quot;)	&apos;	Untitled 1 is presumed a Writer document
&apos;&apos;&apos;			&apos; The substring &quot;SFDocuments.&quot; in the service name is optional
&apos;&apos;&apos;
&apos;&apos;&apos;		Definitions:
&apos;&apos;&apos;			Many methods require a &quot;TextRange&quot; as argument.
&apos;&apos;&apos;			A textrange is a string describing the scope on which to apply the method.
&apos;&apos;&apos;			Such a textrange corresponds either with a single insertion point or with a (text) interval between 2 insertion points.
&apos;&apos;&apos;			Multiple textranges are not supported in this context.
&apos;&apos;&apos;
&apos;&apos;&apos;			TextRange: a string containing one of next variants :
&apos;&apos;&apos;			(names may be surrounded with single or double quotes)
&apos;&apos;&apos;				&quot;~&quot; or &quot;SELECTION&quot; or &quot;SEL&quot; = current selection (if multiple selections, its 1st component)
&apos;&apos;&apos;				&quot;BODY&quot; = the main text of the actual document instance
&apos;&apos;&apos;				&quot;FRAME!name&quot; = the text contained in a text frame
&apos;&apos;&apos;				&quot;BOOKMARK!name&quot; = the given bookmark, may be zero or more characters long
&apos;&apos;&apos;				&quot;FIELD!name&quot; = a user text field
&apos;&apos;&apos;				&quot;SECTION!name&quot; = the text contained in a section
&apos;&apos;&apos;				&quot;TABLE!name!&quot; = the whole cellrange of a table
&apos;&apos;&apos;				&quot;TABLE!name!cellrange&quot; = a cell (cellrange = &quot;B3&quot;) or a range of cells (&quot;A2:B3&quot;)
&apos;&apos;&apos;				&quot;WORD+3&quot; = 3 words after the current selection
&apos;&apos;&apos;				&quot;SENTENCE-1&quot; = the sentence before the current selection
&apos;&apos;&apos;				&quot;PARAGRAPH&quot; or &quot;§&quot; = the paragraph containing the current selection (0 is the default)
&apos;&apos;&apos;			optionally combined with next control character:
&apos;&apos;&apos;				&quot;|&quot;: start or end of string
&apos;&apos;&apos;						&quot;|~&quot; = the point immediately before the current visible selection (starting point)
&apos;&apos;&apos;						&quot;~|&quot; = the point immediately after the current visible selection (ending point)
&apos;&apos;&apos;						&quot;~&quot;, &quot;|~|&quot; = the full visible selection
&apos;&apos;&apos;
&apos;&apos;&apos;
&apos;&apos;&apos;		Detailed user documentation:
&apos;&apos;&apos;			https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_writer.html?DbPAR=BASIC
&apos;&apos;&apos;
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;

REM ================================================================== EXCEPTIONS

Private Const WRITERFORMNOTFOUNDERROR	=	&quot;WRITERFORMNOTFOUNDERROR&quot;
Private Const WRITERRANGEERROR			=	&quot;WRITERRANGEERROR&quot;

REM ============================================================= PRIVATE MEMBERS

Private [Me]					As Object
Private [_Parent]				As Object
Private [_Super]				As Object		&apos;	Document superclass, which the current instance is a subclass of
Private ObjectType				As String		&apos;	Must be WRITER
Private ServiceName				As String

&apos;	Window component
Private _Component				As Object		&apos;	com.sun.star.lang.XComponent

&apos;	Text Range
Type _TextRange
	RangeString					As String		&apos;	The input string
	Target						As String		&apos;	Selection or Body or Frame or ...
	TargetName					As String		&apos;	Name of Frame or Table or ...
	TargetCell					As String		&apos;	Cell
	TargetObject				As Object		&apos;	Field, TableCell, Section, ... object
	Offset						As Long			&apos;	Number of items to right (+) or to left (-)
	StartPoint					As Boolean		&apos;	When True, vertical bar before target
	EndPoint					As Boolean		&apos;	When True, vertical bar after target
	Anchor						As Object		&apos;	com.sun.star.text.XTextRange
	Text						As Object		&apos;	com.sun.star.text.XText
	Cursor						As Object		&apos;	com.sun.star.text.XTextCursor
	Location					As String		&apos;	BODY or FOOTNOTE or HEADER/FOOTER ...
End Type

REM ============================================================ MODULE CONSTANTS

Const ISDOCFORM = 1				&apos;	Form is stored in a Writer document

REM ====================================================== CONSTRUCTOR/DESTRUCTOR

REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
	Set [Me] = Nothing
	Set [_Parent] = Nothing
	Set [_Super] = Nothing
	ObjectType = &quot;WRITER&quot;
	ServiceName = &quot;SFDocuments.Writer&quot;
	Set _Component = Nothing
End Sub		&apos;	SFDocuments.SF_Writer Constructor

REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
	Call Class_Initialize()
End Sub		&apos;	SFDocuments.SF_Writer Destructor

REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
	If Not IsNull([_Super]) Then Set [_Super] = [_Super].Dispose()
	Call Class_Terminate()
	Set Dispose = Nothing
End Function	&apos;	SFDocuments.SF_Writer Explicit Destructor

REM ================================================================== PROPERTIES

REM -----------------------------------------------------------------------------
Property Get Bookmarks() As Variant
&apos;&apos;&apos;	Return the list of currently available bookmarks as a zero-based array
	Bookmarks = _PropertyGet(&quot;Bookmarks&quot;)
End Property	&apos;	SFDocuments.SF_Writer.Bookmarks (get)

REM -----------------------------------------------------------------------------
Property Get CurrentSelection() As Variant
&apos;&apos;&apos;	Return the list of currently available CurrentSelection as a zero-based array
	CurrentSelection = _PropertyGet(&quot;CurrentSelection&quot;)
End Property	&apos;	SFDocuments.SF_Writer.CurrentSelection (get)

REM -----------------------------------------------------------------------------
Property Let CurrentSelection(Optional ByVal pvSelection As Variant)
&apos;&apos;&apos;	Set the selection to a single or a multiple range
&apos;&apos;&apos;	The argument can be:
&apos;&apos;&apos;		- a string (a textrange)
&apos;&apos;&apos;		- a com.sun.star.text.XTextRange object
&apos;&apos;&apos;		- a collection of com.sun.star.text.XTextRange objects 

Dim vSelection As Variant			&apos;	Alias of pvSelection
Dim oSelection As Object			&apos;	com.sun.star.text.XTextRange
Dim sType As String					&apos;	session.UnoObjectType()
Dim oSess As Object					:	Set oSess = ScriptForge.SF_Session
Dim i As Long

Const cstThisSub = &quot;SFDocuments.Writer.setCurrentSelection&quot;
Const cstSubArgs = &quot;Selection&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch

Check:
	If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
		If Not _IsStillAlive(True) Then GoTo Finally
		If Not ScriptForge.SF_Utils._Validate(pvSelection, &quot;Selection&quot;, Array(V_STRING, ScriptForge.V_Object)) Then GoTo Finally
	End If

Try:
	vSelection = pvSelection	&apos;	Necessary to avoid the &quot;Object variable not set&quot; error
	With _Component.CurrentController
		If VarType(vSelection)  = V_STRING Then
			Set oSelection = _ParseRange(vSelection).Cursor
			If Not IsNull(oSelection) Then .select(oSelection)
		Else
			sType = oSess.UnoObjectType(vSelection)
			Select Case sType
				Case &quot;SwXTextRanges&quot;					&apos;	Argument is a multiple selection
					For i = 0 To vSelection.Count - 1
						If oSess.UnoObjectType(vSelection.getByIndex(i)) &lt;&gt; &quot;SwXTextRange&quot; Then GoTo Catch		&apos;	Do nothing
					Next i
					.select(vSelection)
				Case &quot;SwXTextRange&quot;, &quot;SwXTextCursor&quot;, &quot;SwXTextTableCursor&quot;	&apos;	Argument is a simple selection (anchor/cursor)
					.select(vSelection)
				Case Else
			End Select
		End If
	End With

Finally:
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Property
Catch:
	GoTo Finally
End Property	&apos;	SFDocuments.SF_Writer.CurrentSelection (let)

REM -----------------------------------------------------------------------------
Property Get Fields() As Variant
&apos;&apos;&apos;	Return the list of currently available fields as a zero-based array
&apos;&apos;&apos;	Are considered only next field-types:
&apos;&apos;&apos;		- user fields:		com.sun.star.text.textfield.User
&apos;&apos;&apos;		- variable fields:	com.sun.star.text.textfield.SetExpression
	Fields = _PropertyGet(&quot;Fields&quot;)
End Property	&apos;	SFDocuments.SF_Writer.Fields (get)

REM -----------------------------------------------------------------------------
Property Get Frames() As Variant
&apos;&apos;&apos;	Return the list of currently available frames as a zero-based array
	Frames = _PropertyGet(&quot;Frames&quot;)
End Property	&apos;	SFDocuments.SF_Writer.Frames (get)

REM ===================================================================== METHODS

REM -----------------------------------------------------------------------------
Public Function Forms(Optional ByVal Form As Variant) As Variant
&apos;&apos;&apos;	Return either
&apos;&apos;&apos;		- the list of the Forms contained in the form document
&apos;&apos;&apos;		- a SFDocuments.Form object based on its name or its index
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Form: a form stored in the document given by its name or its index
&apos;&apos;&apos;			When absent, the list of available forms is returned
&apos;&apos;&apos;			To get the first (unique ?) form stored in the form document, set Form = 0
&apos;&apos;&apos;	Exceptions:
&apos;&apos;&apos;		WRITERFORMNOTFOUNDERROR		Form not found
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		A zero-based array of strings if Form is absent
&apos;&apos;&apos;		An instance of the SF_Form class if Form exists
&apos;&apos;&apos;	Example:
&apos;&apos;&apos;			Dim myForm As Object, myList As Variant
&apos;&apos;&apos;				myList = oDoc.Forms()
&apos;&apos;&apos;				Set myForm = oDoc.Forms(&quot;myForm&quot;)

Dim oForm As Object					&apos;	The new Form class instance
Dim oMainForm As Object				&apos;	com.sun.star.comp.sdb.Content
Dim oXForm As Object				&apos;	com.sun.star.form.XForm
Dim vFormNames As Variant			&apos;	Array of form names
Dim oForms As Object				&apos;	Forms collection
Const cstDrawPage = 0				&apos;	Only 1 drawpage in a Writer document

Const cstThisSub = &quot;SFDocuments.Writer.Forms&quot;
Const cstSubArgs = &quot;[Form=&quot;&quot;&quot;&quot;]&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch

Check:
	If IsMissing(Form) Or IsEmpty(Form) Then Form = &quot;&quot;
	If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
		If Not _IsStillAlive() Then GoTo Finally
		If Not ScriptForge.SF_Utils._Validate(Form, &quot;Form&quot;, Array(V_STRING, ScriptForge.V_NUMERIC)) Then GoTo Finally
	End If

Try:
	&apos;	Start from the document component and go down to forms
	Set oForms = _Component.DrawPages(cstDrawPage).Forms
	vFormNames = oForms.getElementNames()

	If Len(Form) = 0 Then	&apos;	Return the list of valid form names
		Forms = vFormNames
	Else
		If VarType(Form) = V_STRING Then	&apos;	Find the form by name
			If Not ScriptForge.SF_Array.Contains(vFormNames, Form, CaseSensitive := True) Then GoTo CatchNotFound
			Set oXForm = oForms.getByName(Form)
		Else								&apos;	Find the form by index
			If Form &lt; 0 Or Form &gt;= oForms.Count Then GoTo CatchNotFound
			Set oXForm = oForms.getByIndex(Form)
		End If
		&apos;	Create the new Form class instance
		Set oForm = SF_Register._NewForm(oXForm)
		With oForm
			Set .[_Parent] = [Me]
			._FormType = ISDOCFORM
			Set ._Component = _Component
			._Initialize()
		End With
		Set Forms = oForm
	End If

Finally:
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
CatchNotFound:
	ScriptForge.SF_Exception.RaiseFatal(WRITERFORMNOTFOUNDERROR, Form, _FileIdent())
End Function	&apos;	SFDocuments.SF_Writer.Forms

REM -----------------------------------------------------------------------------
Public Function GetProperty(Optional ByVal PropertyName As Variant _
								) As Variant
&apos;&apos;&apos;	Return the actual value of the given property
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		PropertyName: the name of the property as a string
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		The actual value of the property
&apos;&apos;&apos;	Exceptions:
&apos;&apos;&apos;		ARGUMENTERROR		The property does not exist

Const cstThisSub = &quot;SFDocuments.Writer.GetProperty&quot;
Const cstSubArgs = &quot;&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	GetProperty = Null

Check:
	If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
		If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
	End If

Try:
	&apos;	Superclass or subclass property ?
	If ScriptForge.SF_Array.Contains([_Super].Properties(), PropertyName) Then
		GetProperty = [_Super].GetProperty(PropertyName)
	Else
		GetProperty = _PropertyGet(PropertyName)
	End If

Finally:
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFDocuments.SF_Writer.GetProperty

REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos;	Return the list of public methods of the Writer service as an array

	Methods = Array( _
					&quot;Forms&quot; _
					, &quot;PrintOut&quot; _
					)

End Function	&apos;	SFDocuments.SF_Writer.Methods

REM -----------------------------------------------------------------------------
Public Function PrintOut(Optional ByVal Pages As Variant _
							, Optional ByVal Copies As Variant _
							, Optional ByVal PrintBackground As Variant _
							, Optional ByVal PrintBlankPages As Variant _
							, Optional ByVal PrintEvenPages As Variant _
							, Optional ByVal PrintOddPages As Variant _
							, Optional ByVal PrintImages As Variant _
							) As Boolean
&apos;&apos;&apos; Send the content of the document to the printer.
&apos;&apos;&apos;	The printer might be defined previously by default, by the user or by the SetPrinter() method
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		Pages: the pages to print as a string, like in the user interface. Example: &quot;1-4;10;15-18&quot;. Default = all pages
&apos;&apos;&apos;		Copies: the number of copies
&apos;&apos;&apos;		PrintBackground: print the background image when True (default)
&apos;&apos;&apos;		PrintBlankPages: when False (default), omit empty pages
&apos;&apos;&apos;		PrintEvenPages: print the left pages when True (default)
&apos;&apos;&apos;		PrintOddPages: print the right pages when True (default)
&apos;&apos;&apos;		PrintImages: print the graphic objects when True (default)
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		True when successful
&apos;&apos;&apos;	Examples:
&apos;&apos;&apos;		oDoc.PrintOut(&quot;1-4;10;15-18&quot;, Copies := 2, PrintImages := False)

Dim bPrint As Boolean				&apos;	Return value
Dim vPrintOptions As Variant		&apos;	com.sun.star.text.DocumentSettings

Const cstThisSub = &quot;SFDocuments.Writer.PrintOut&quot;
Const cstSubArgs = &quot;[Pages=&quot;&quot;&quot;&quot;], [Copies=1], [PrintBackground=True], [PrintBlankPages=False], [PrintEvenPages=True]&quot; _
						&amp; &quot;, [PrintOddPages=True], [PrintImages=True]&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	bPrint = False

Check:
	If IsMissing(Pages) Or IsEmpty(Pages) Then Pages = &quot;&quot;
	If IsMissing(Copies) Or IsEmpty(Copies) Then Copies = 1
	If IsMissing(PrintBackground) Or IsEmpty(PrintBackground) Then PrintBackground = True
	If IsMissing(PrintBlankPages) Or IsEmpty(PrintBlankPages) Then PrintBlankPages = False
	If IsMissing(PrintEvenPages) Or IsEmpty(PrintEvenPages) Then PrintEvenPages = True
	If IsMissing(PrintOddPages) Or IsEmpty(PrintOddPages) Then PrintOddPages = True
	If IsMissing(PrintImages) Or IsEmpty(PrintImages) Then PrintImages = True
	
	If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
		If Not _IsStillAlive() Then GoTo Finally
		If Not ScriptForge.SF_Utils._Validate(Pages, &quot;Pages&quot;, V_STRING) Then GoTo Finally
		If Not ScriptForge.SF_Utils._Validate(Copies, &quot;Copies&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
		If Not ScriptForge.SF_Utils._Validate(PrintBackground, &quot;PrintBackground&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
		If Not ScriptForge.SF_Utils._Validate(PrintBlankPages, &quot;PrintBlankPages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
		If Not ScriptForge.SF_Utils._Validate(PrintEvenPages, &quot;PrintEvenPages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
		If Not ScriptForge.SF_Utils._Validate(PrintOddPages, &quot;PrintOddPages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
		If Not ScriptForge.SF_Utils._Validate(PrintImages, &quot;PrintImages&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
	End If

Try:
	vPrintOptions = _Component.createInstance(&quot;com.sun.star.text.DocumentSettings&quot;)
	With vPrintOptions
		.PrintPageBackground = PrintBackground
		.PrintEmptyPages = PrintBlankPages
		.PrintLeftPages = PrintEvenPages
		.PrintRightPages = PrintOddPages
		.PrintGraphics = PrintImages
		.PrintDrawings = PrintImages
	End With

	bPrint = [_Super].PrintOut(Pages, Copies, _Component)

Finally:
	PrintOut = bPrint
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function   &apos;   SFDocuments.SF_Writer.PrintOut

REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos;	Return the list or properties of the Writer class as an array

	Properties = Array( _
					&quot;Bookmarks&quot; _
					, &quot;CurrentSelection&quot; _
					, &quot;CustomProperties&quot; _
					, &quot;Description&quot; _
					, &quot;DocumentProperties&quot; _
					, &quot;DocumentType&quot; _
					, &quot;ExportFilters&quot; _
					, &quot;Fields&quot; _
					, &quot;FileSystem&quot; _
					, &quot;Frames&quot; _
					, &quot;ImportFilters&quot; _
					, &quot;IsAlive&quot; _
					, &quot;IsBase&quot; _
					, &quot;IsCalc&quot; _
					, &quot;IsDraw&quot; _
					, &quot;IsFormDocument&quot; _
					, &quot;IsImpress&quot; _
					, &quot;IsMath&quot; _
					, &quot;IsWriter&quot; _
					, &quot;Keywords&quot; _
					, &quot;MenuHeaders&quot; _
					, &quot;Readonly&quot; _
					, &quot;StyleFamilies&quot; _
					, &quot;Subject&quot; _
					, &quot;Title&quot; _
					, &quot;XComponent&quot; _
					, &quot;XDocumentSettings&quot; _
					)

End Function	&apos;	SFDocuments.SF_Writer.Properties

REM -----------------------------------------------------------------------------
Private Function SetProperty(Optional ByVal psProperty As String _
								, Optional ByVal pvValue As Variant _
								) As Boolean
&apos;&apos;&apos;	Set the new value of the named property
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		psProperty: the name of the property
&apos;&apos;&apos;		pvValue: the new value of the given property
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		True if successful

Dim bSet As Boolean							&apos;	Return value
Static oSession As Object					&apos;	Alias of SF_Session
Dim cstThisSub As String
Const cstSubArgs = &quot;Value&quot;

	If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
	bSet = False

	cstThisSub = &quot;SFDocuments.Writer.set&quot; &amp; psProperty
	If IsMissing(pvValue) Then pvValue = Empty
	&apos;ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)	&apos;	Validation done in Property Lets

	If IsNull(oSession) Then Set oSession = ScriptForge.SF_Services.CreateScriptService(&quot;Session&quot;)
	bSet = True
	Select Case UCase(psProperty)
		Case UCase(&quot;CustomProperties&quot;)
			CustomProperties = pvValue
		Case UCase(&quot;Description&quot;)
			Description = pvValue
		Case UCase(&quot;Keywords&quot;)
			Keywords = pvValue
		Case UCase(&quot;Subject&quot;)
			Subject = pvValue
		Case UCase(&quot;Title&quot;)
			Title = pvValue
		Case Else
			bSet = False
	End Select

Finally:
	SetProperty = bSet
	&apos;ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
Catch:
	GoTo Finally
End Function	&apos;	SFDocuments.SF_Writer.SetProperty

REM ======================================================= SUPERCLASS PROPERTIES

REM -----------------------------------------------------------------------------
Property Get CustomProperties() As Variant
	CustomProperties = [_Super].GetProperty(&quot;CustomProperties&quot;)
End Property	&apos;	SFDocuments.SF_Writer.CustomProperties

REM -----------------------------------------------------------------------------
Property Let CustomProperties(Optional ByVal pvCustomProperties As Variant)
	[_Super].CustomProperties = pvCustomProperties
End Property	&apos;	SFDocuments.SF_Writer.CustomProperties

REM -----------------------------------------------------------------------------
Property Get Description() As Variant
	Description = [_Super].GetProperty(&quot;Description&quot;)
End Property	&apos;	SFDocuments.SF_Writer.Description

REM -----------------------------------------------------------------------------
Property Let Description(Optional ByVal pvDescription As Variant)
	[_Super].Description = pvDescription
End Property	&apos;	SFDocuments.SF_Writer.Description

REM -----------------------------------------------------------------------------
Property Get DocumentProperties() As Variant
	DocumentProperties = [_Super].GetProperty(&quot;DocumentProperties&quot;)
End Property	&apos;	SFDocuments.SF_Writer.DocumentProperties

REM -----------------------------------------------------------------------------
Property Get DocumentType() As String
	DocumentType = [_Super].GetProperty(&quot;DocumentType&quot;)
End Property	&apos;	SFDocuments.SF_Writer.DocumentType

REM -----------------------------------------------------------------------------
Property Get ExportFilters() As Variant
	ExportFilters = [_Super].GetProperty(&quot;ExportFilters&quot;)
End Property	&apos;	SFDocuments.SF_Writer.ExportFilters

REM -----------------------------------------------------------------------------
Property Get FileSystem() As String
	FileSystem = [_Super].GetProperty(&quot;FileSystem&quot;)
End Property	&apos;	SFDocuments.SF_Writer.FileSystem

REM -----------------------------------------------------------------------------
Property Get ImportFilters() As Variant
	ImportFilters = [_Super].GetProperty(&quot;ImportFilters&quot;)
End Property	&apos;	SFDocuments.SF_Writer.ImportFilters

REM -----------------------------------------------------------------------------
Property Get IsAlive() As Boolean
	IsAlive = [_Super].GetProperty(&quot;IsAlive&quot;)
End Property	&apos;	SFDocuments.SF_Writer.IsAlive

REM -----------------------------------------------------------------------------
Property Get IsBase() As Boolean
	IsBase = [_Super].GetProperty(&quot;IsBase&quot;)
End Property	&apos;	SFDocuments.SF_Writer.IsBase

REM -----------------------------------------------------------------------------
Property Get IsCalc() As Boolean
	IsCalc = [_Super].GetProperty(&quot;IsCalc&quot;)
End Property	&apos;	SFDocuments.SF_Writer.IsCalc

REM -----------------------------------------------------------------------------
Property Get IsDraw() As Boolean
	IsDraw = [_Super].GetProperty(&quot;IsDraw&quot;)
End Property	&apos;	SFDocuments.SF_Writer.IsDraw

REM -----------------------------------------------------------------------------
Property Get IsFormDocument() As Boolean
	IsFormDocument = [_Super].GetProperty(&quot;IsFormDocument&quot;)
End Property	&apos;	SFDocuments.SF_Writer.IsFormDocument

REM -----------------------------------------------------------------------------
Property Get IsImpress() As Boolean
	IsImpress = [_Super].GetProperty(&quot;IsImpress&quot;)
End Property	&apos;	SFDocuments.SF_Writer.IsImpress

REM -----------------------------------------------------------------------------
Property Get IsMath() As Boolean
	IsMath = [_Super].GetProperty(&quot;IsMath&quot;)
End Property	&apos;	SFDocuments.SF_Writer.IsMath

REM -----------------------------------------------------------------------------
Property Get IsWriter() As Boolean
	IsWriter = [_Super].GetProperty(&quot;IsWriter&quot;)
End Property	&apos;	SFDocuments.SF_Writer.IsWriter

REM -----------------------------------------------------------------------------
Property Get Keywords() As Variant
	Keywords = [_Super].GetProperty(&quot;Keywords&quot;)
End Property	&apos;	SFDocuments.SF_Writer.Keywords

REM -----------------------------------------------------------------------------
Property Let Keywords(Optional ByVal pvKeywords As Variant)
	[_Super].Keywords = pvKeywords
End Property	&apos;	SFDocuments.SF_Writer.Keywords

REM -----------------------------------------------------------------------------
Property Get MenuHeaders() As Variant
	MenuHeaders = [_Super].GetProperty(&quot;MenuHeaders&quot;)
End Property	&apos;	SFDocuments.SF_Writer.MenuHeaders

REM -----------------------------------------------------------------------------
Property Get Readonly() As Variant
	Readonly = [_Super].GetProperty(&quot;Readonly&quot;)
End Property	&apos;	SFDocuments.SF_Writer.Readonly

REM -----------------------------------------------------------------------------
Property Get StyleFamilies() As Variant
	StyleFamilies = [_Super].GetProperty(&quot;StyleFamilies&quot;)
End Property	&apos;	SFDocuments.SF_Writer.StyleFamilies

REM -----------------------------------------------------------------------------
Property Get Subject() As Variant
	Subject = [_Super].GetProperty(&quot;Subject&quot;)
End Property	&apos;	SFDocuments.SF_Writer.Subject

REM -----------------------------------------------------------------------------
Property Let Subject(Optional ByVal pvSubject As Variant)
	[_Super].Subject = pvSubject
End Property	&apos;	SFDocuments.SF_Writer.Subject

REM -----------------------------------------------------------------------------
Property Get Title() As Variant
	Title = [_Super].GetProperty(&quot;Title&quot;)
End Property	&apos;	SFDocuments.SF_Writer.Title

REM -----------------------------------------------------------------------------
Property Let Title(Optional ByVal pvTitle As Variant)
	[_Super].Title = pvTitle
End Property	&apos;	SFDocuments.SF_Writer.Title

REM -----------------------------------------------------------------------------
Property Get XComponent() As Variant
	XComponent = [_Super].GetProperty(&quot;XComponent&quot;)
End Property	&apos;	SFDocuments.SF_Writer.XComponent

REM -----------------------------------------------------------------------------
Property Get XDocumentSettings() As Variant
	XDocumentSettings = [_Super].GetProperty(&quot;XDocumentSettings&quot;)
End Property	&apos;	SFDocuments.SF_Writer.XDocumentSettings

REM ========================================================== SUPERCLASS METHODS

REM -----------------------------------------------------------------------------
Public Function Activate() As Boolean
	Activate = [_Super].Activate()
End Function    &apos;   SFDocuments.SF_Writer.Activate

REM -----------------------------------------------------------------------------
Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
	CloseDocument = [_Super].CloseDocument(SaveAsk)
End Function   &apos;   SFDocuments.SF_Writer.CloseDocument

REM -----------------------------------------------------------------------------
Public Function ContextMenus(Optional ByVal ContextMenuName As Variant _
								, Optional ByVal SubmenuChar As Variant _
								) As Variant
	ContextMenus = [_Super].ContextMenus(ContextMenuName, SubmenuChar)
End Function	&apos;	SFDocuments.SF_Writer.ContextMenus

REM -----------------------------------------------------------------------------
Public Function CreateMenu(Optional ByVal MenuHeader As Variant _
								, Optional ByVal Before As Variant _
								, Optional ByVal SubmenuChar As Variant _
								) As Object
	Set CreateMenu = [_Super].CreateMenu(MenuHeader, Before, SubmenuChar)
End Function	&apos;	SFDocuments.SF_Writer.CreateMenu

REM -----------------------------------------------------------------------------
Public Sub DeleteStyles(Optional ByVal Family As Variant _
								, Optional ByRef StylesList As Variant _
								)
	[_Super].DeleteStyles(Family, StylesList)
End Sub			&apos;	SFDocuments.SF_Writer.DeleteStyles

REM -----------------------------------------------------------------------------
Public Sub Echo(Optional ByVal EchoOn As Variant _
						, Optional ByVal Hourglass As Variant _
						)
	[_Super].Echo(EchoOn, Hourglass)
End Sub		   &apos;   SFDocuments.SF_Writer.Echo

REM -----------------------------------------------------------------------------
Public Function ExportAsPDF(Optional ByVal FileName As Variant _
							, Optional ByVal Overwrite As Variant _
							, Optional ByVal Pages As Variant _
							, Optional ByVal Password As Variant _
							, Optional ByVal Watermark As Variant _
							) As Boolean
	ExportAsPDF = [_Super].ExportAsPDF(FileName, Overwrite, Pages, Password, Watermark)
End Function   &apos;   SFDocuments.SF_Writer.ExportAsPDF

REM -----------------------------------------------------------------------------
Public Sub ImportStylesFromFile(Optional FileName As Variant _
								, Optional ByRef Families As Variant _
								, Optional ByVal Overwrite As variant _
								) As Variant
	[_Super]._ImportStylesFromFile(FileName, Families, Overwrite)
End Sub	&apos;	SFDocuments.SF_Writer.ImportStylesFromFile

REM -----------------------------------------------------------------------------
Public Function RemoveMenu(Optional ByVal MenuHeader As Variant) As Boolean
	RemoveMenu = [_Super].RemoveMenu(MenuHeader)
End Function	&apos;	SFDocuments.SF_Writer.RemoveMenu

REM -----------------------------------------------------------------------------
Public Sub RunCommand(Optional ByVal Command As Variant _
									, ParamArray Args As Variant _
									)
	[_Super].RunCommand(Command, Args)
End Sub		  &apos;   SFDocuments.SF_Writer.RunCommand

REM -----------------------------------------------------------------------------
Public Function Save() As Boolean
	Save = [_Super].Save()
End Function   &apos;   SFDocuments.SF_Writer.Save

REM -----------------------------------------------------------------------------
Public Function SaveAs(Optional ByVal FileName As Variant _
							, Optional ByVal Overwrite As Variant _
							, Optional ByVal Password As Variant _
							, Optional ByVal FilterName As Variant _
							, Optional ByVal FilterOptions As Variant _
							) As Boolean
	SaveAs = [_Super].SaveAs(FileName, Overwrite, Password, FilterName, FilterOptions)
End Function   &apos;   SFDocuments.SF_Writer.SaveAs

REM -----------------------------------------------------------------------------
Public Function SaveCopyAs(Optional ByVal FileName As Variant _
							, Optional ByVal Overwrite As Variant _
							, Optional ByVal Password As Variant _
							, Optional ByVal FilterName As Variant _
							, Optional ByVal FilterOptions As Variant _
							) As Boolean
	SaveCopyAs = [_Super].SaveCopyAs(FileName, Overwrite, Password, FilterName, FilterOptions)
End Function   &apos;   SFDocuments.SF_Writer.SaveCopyAs

REM -----------------------------------------------------------------------------
Public Function SetPrinter(Optional ByVal Printer As Variant _
							, Optional ByVal Orientation As Variant _
							, Optional ByVal PaperFormat As Variant _
							) As Boolean
	SetPrinter = [_Super].SetPrinter(Printer, Orientation, PaperFormat)
End Function	&apos;   SFDocuments.SF_Writer.SetPrinter

REM -----------------------------------------------------------------------------
Public Function Styles(Optional ByVal Family As Variant _
							, Optional ByVal NamePattern As variant _
							, Optional ByVal Used As variant _
							, Optional ByVal UserDefined As Variant _
							, Optional ByVal ParentStyle As Variant _
							, Optional ByVal Category As Variant _
							) As Variant
	Styles = [_Super].Styles(Family, NamePattern, Used, UserDefined, ParentStyle, Category)
End Function	&apos;   SFDocuments.SF_Writer.Styles

REM -----------------------------------------------------------------------------
Public Function Toolbars(Optional ByVal ToolbarName As Variant) As Variant
	Toolbars = [_Super].Toolbars(ToolbarName)
End Function	&apos;	SFDocuments.SF_Writer.Toolbars

REM -----------------------------------------------------------------------------
Public Function XStyle(Optional ByVal Family As Variant _
							, Optional ByVal StyleName As variant _
							) As Object
	Set XStyle = [_Super].XStyle(Family, StyleName)
End Function	&apos;	SFDocuments.SF_Writer.XStyle

REM =========================================================== PRIVATE FUNCTIONS

REM -----------------------------------------------------------------------------
Private Function _FileIdent() As String
&apos;&apos;&apos;	Returns a file identification from the information that is currently available
&apos;&apos;&apos;	Useful e.g. for display in error messages

	_FileIdent = [_Super]._FileIdent()

End Function	&apos;	SFDocuments.SF_Writer._FileIdent

REM -----------------------------------------------------------------------------
Private Function _IsStillAlive(Optional ByVal pbForUpdate As Boolean _
									, Optional ByVal pbError As Boolean _
									) As Boolean
&apos;&apos;&apos;	Returns True if the document has not been closed manually or incidentally since the last use
&apos;&apos;&apos;	If dead the actual instance is disposed. The execution is cancelled when pbError = True (default)
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		pbForUpdate: if True (default = False), check additionally if document is open for editing
&apos;&apos;&apos;		pbError: if True (default), raise a fatal error

Dim bAlive As Boolean			&apos;	Return value

	If IsMissing(pbForUpdate) Then pbForUpdate = False
	If IsMissing(pbError) Then pbError = True

Try:
	bAlive = [_Super]._IsStillAlive(pbForUpdate, pbError)

Finally:
	_IsStillAlive = bAlive
	Exit Function
End Function	&apos;	SFDocuments.SF_Writer._IsStillAlive

REM -----------------------------------------------------------------------------
Private Function _ParseRange(psTextRange As String) As Object
&apos;&apos;&apos;	Parse and validate a text range passed as a string
&apos;&apos;&apos;	Syntax to parse:
&apos;&apos;&apos;			[|]~ or &quot;SELECTION&quot; or &quot;SEL&quot;[|]
&apos;&apos;&apos;			[|]BODY[|]
&apos;&apos;&apos;			[|]FRAME!name[|]
&apos;&apos;&apos;			BOOKMARK!name
&apos;&apos;&apos;			FIELD!name
&apos;&apos;&apos;			[|]SECTION!name[|]
&apos;&apos;&apos;			TABLE!name!cell
&apos;&apos;&apos;			[|]WORD±n[|]
&apos;&apos;&apos;			[|]SENTENCE±n[|]
&apos;&apos;&apos;			[|]PARAGRAPH±n or §±n[|]
&apos;&apos;&apos;		A name must be surrounded with single or double quotes when it contains a space or a not alphanumeric character
&apos;&apos;&apos;	Returns:
&apos;&apos;&apos;		An object of type _TextRange
&apos;&apos;&apos;	Exceptions:
&apos;&apos;&apos;		WRITERRANGEERROR		&apos;	Text range could not be parsed to a valid location

Dim oTextRange As Object				&apos;	Return value
Dim bParsing As Boolean					&apos;	When True, parsing could identify the target
Dim lSelects As Long					&apos;	Number of items in the current selection
Dim sTarget As String					&apos;	Alias of _TextRange.Target
Dim sString As String					&apos;	Work variable
Dim sLeft1 As String					&apos;	The 1st character of sString
Dim sSign As String						&apos;	+ or -
Dim oColl As Object						&apos;	Collection of TargetObjects (bookmarks or frames or ...)
Dim oItem As Object						&apos;	An item in the oColl collection
Dim vNames As Variant					&apos;	Array of the available object names within a collection
Dim oStr As Object						:	Set oStr = ScriptForge.SF_String
Dim bMove As Boolean					&apos;	Return value of a cursor move
Dim i As Long

	&apos;	Reinitialize a new _TextRange object
	Set oTextRange = New _TextRange
	With oTextRange
		Set .TargetObject = Nothing
		.RangeString = &quot;&quot;		:	.Target = &quot;&quot;			:	.TargetName = &quot;&quot;	:	.TargetCell = &quot;&quot;
		.Offset = 0				:	.StartPoint = False		:	.EndPoint = False
		Set .Anchor = Nothing	:	Set .Text = Nothing		:	Set .Cursor = Nothing
		.Location = &quot;&quot;
	End With

	&apos;	Identify the type of range with adequate regular expressions
	With oTextRange
		.RangeString = psTextRange
		.StartPoint = ( Left(psTextRange, 1) = &quot;|&quot; )
		.EndPoint = ( Right(psTextRange, 1) = &quot;|&quot; )

		Select Case True
		&apos;	Parsing is done with regular expressions because names may really contain any character, including &quot;ç&quot;

			&apos;	Selection
			Case oStr.IsRegex(psTextRange, &quot;\|?\s*(~|SEL|SELECTION)\s*\|?&quot;)
				.Target = &quot;Selection&quot;
				If _Component.CurrentSelection.ImplementationName = &quot;SwXTextRanges&quot; Then
					lSelects = _Component.CurrentSelection.Count
					If lSelects &gt; 0 Then
						Set .Anchor = _Component.CurrentSelection.getByIndex(lSelects - 1)
						If .StartPoint And Not .EndPoint Then
							Set .Anchor = .Anchor.Start
						ElseIf Not .StartPoint And .EndPoint Then
							Set .Anchor = .Anchor.End
						End If
						Set .Text = .Anchor.Text
						Set .Cursor = .Text.createTextCursorByRange(.Anchor)
					End If
				End If
				If IsNull(.Cursor) Then .Location = _Component.CurrentSelection.ImplementationName

			&apos;	WORD, SENTENCE, PARAGRAPH
			Case oStr.IsRegex(psTextRange, &quot;\|?\s*(PARAGRAPH|§|SENTENCE|WORD)\s*([+-][0-9]+)?\s*\|?&quot;)
				If InStr(psTextRange, &quot;+&quot;) &gt; 0 Then
					sSign = &quot;+&quot;
				ElseIf InStr(psTextRange, &quot;-&quot;) &gt; 0 Then
					sSign= &quot;-&quot;
				End If
				If Len(sSign) &gt; 0 Then sTarget = Split(psTextRange, sSign)(0) Else sTarget = psTextRange
				If InStr(Iif(.StartPoint, 2, 1), sTarget, &quot;PARAGRAPH&quot;, 1) &gt; 0 Or InStr(Iif(.StartPoint, 2, 1), sTarget, &quot;§&quot;, 1) &gt; 0 Then
					.Target = &quot;Paragraph&quot;
				ElseIf InStr(Iif(.StartPoint, 2, 1), sTarget, &quot;SENTENCE&quot;, 1) &gt; 0 Then
					.Target = &quot;Sentence&quot;
				ElseIf InStr(Iif(.StartPoint, 2, 1), sTarget, &quot;WORD&quot;, 1) &gt; 0 Then
					.Target = &quot;Word&quot;
				End If
				
				&apos;	Identify the offset
				If Len(sSign) = 0 Then
					.Offset = 0
				Else
					sString = Split(psTextRange, sSign)(1)
					If .EndPoint Then sString = Left(sString, Len(sString) - 1)
					.Offset = CLng(sString) * Iif(sSign = &quot;+&quot;, 1, -1)
				End If

				&apos;	Build the cursor pointing at the current selection
				If _Component.CurrentSelection.ImplementationName = &quot;SwXTextRanges&quot; Then
					lSelects = _Component.CurrentSelection.Count
					If lSelects &gt; 0 Then
						Set .Anchor = _Component.CurrentSelection.getByIndex(lSelects - 1)
						Set .Text = .Anchor.Text
						Set .Cursor = .Text.createTextCursorByRange(.Anchor)
					End If
				End If
				If IsNull(.Cursor) Then
					.Location = _Component.CurrentSelection.ImplementationName
				Else
					&apos;	Move the cursor to the requested area
					With .Cursor
						Select Case oTextRange.Target
							Case &quot;Word&quot;
								bMove = .gotoStartOfWord(False)
								If bMove Then
									For i = 1 To Abs(oTextRange.Offset)
										If sSign = &quot;+&quot; Then bMove = .gotoNextWord(False) Else bMove = .gotoPreviousWord(False)
										If sSign = &quot;+&quot; Then
											If Not bMove Then Exit For
											If .isEndOfSentence() Then i = i - 1	&apos;	Loop to do once more
										Else
											bMove = .goLeft(1, False)	&apos;	Additional trial to bypass some locks (tabs, list items, ... ?)
											If Not bMove Then Exit For
										End If
									Next i
								End If
								&apos;	Cursor is always at the start of a word, move it when necessary
								If Not oTextRange.StartPoint And oTextRange.EndPoint Then
									.gotoEndOfWord(False)
								ElseIf oTextRange.StartPoint = oTextRange.EndPoint Then
									.gotoEndOfWord(True)
								End If
							Case &quot;Sentence&quot;
								bMove = .gotoStartOfSentence(False)
								If bMove Then
									For i = 1 To Abs(oTextRange.Offset)
										If sSign = &quot;+&quot; Then bMove = .gotoNextSentence(False) Else bMove = .gotoPreviousSentence(False)
										If sSign = &quot;+&quot; Then
											If .isEndOfParagraph() Then bMove = .goRight(1, False)
										Else
											bMove = .goLeft(1, False)	&apos;	Additional trial to bypass some locks (tabs, list items, ... ?)
											If .isStartOfParagraph() Then bMove = .goLeft(1, False)
										End If
										If Not bMove Then Exit For
									Next i
								End If
								&apos;	Cursor is always at the start of a sentence, move it when necessary
								If Not oTextRange.StartPoint And oTextRange.EndPoint Then
									.gotoEndOfSentence(False)
								ElseIf oTextRange.StartPoint = oTextRange.EndPoint Then
									.gotoEndOfSentence(True)
								End If
							Case &quot;Paragraph&quot;
								bMove = .gotoStartOfParagraph(False)
								If bMove Then
									For i = 1 To Abs(oTextRange.Offset)
										If sSign = &quot;+&quot; Then bMove = .gotoNextParagraph(False) Else bMove = .gotoPreviousParagraph(False)
										If sSign = &quot;+&quot; Then
											If .isEndOfParagraph() Then bMove = .goRight(1, False)
										Else
											bMove = .goLeft(1, False)	&apos;	Additional trial to bypass some locks (tabs, list items, ... ?)
											If .isStartOfParagraph() Then bMove = .goLeft(1, False)
										End If
										If Not bMove Then Exit For
									Next i
								End If
								&apos;	Cursor is always at the start of a Paragraph, move it when necessary
								If Not oTextRange.StartPoint And oTextRange.EndPoint Then
									.gotoEndOfParagraph(False)
								ElseIf oTextRange.StartPoint = oTextRange.EndPoint Then
									.gotoEndOfParagraph(True)
								End If
						End Select
					End With
				End If

			&apos;	Bookmarks, Fields, Frames, Sections
			Case oStr.IsRegex(psTextRange, &quot;\|?\s*(BOOKMARK|FIELD|FRAME|SECTION)!([\w\s]+|&apos;[^&apos;]+&apos;|&quot;&quot;[^&quot;&quot;]+&quot;&quot;)\|?&quot;)
				sTarget = Split(psTextRange, &quot;!&quot;)(0)
				If InStr(Iif(.StartPoint, 2, 1), sTarget, &quot;BOOKMARK&quot;, 1) &gt; 0 Then
					.Target = &quot;Bookmark&quot;
				ElseIf InStr(Iif(.StartPoint, 2, 1), sTarget, &quot;FIELD&quot;, 1) &gt; 0 Then
					.Target = &quot;Field&quot;
				ElseIf InStr(Iif(.StartPoint, 2, 1), sTarget, &quot;FRAME&quot;, 1) &gt; 0 Then
					.Target = &quot;Frame&quot;
				ElseIf InStr(Iif(.StartPoint, 2, 1), sTarget, &quot;SECTION&quot;, 1) &gt; 0 Then
					.Target = &quot;Section&quot;
				End If

				&apos;	Identify section or frame or bookmark or field by its name
				sString = Split(psTextRange, &quot;!&quot;)(1)
				If .EndPoint Then sString = Left(sString, Len(sString) - 1)
				sLeft1 = Left(sString, 1)
				If (sLeft1 = &quot;&quot;&quot;&quot; Or sLeft1 = &quot;&apos;&quot;) And Len(sString) &gt; 2 Then .TargetName = Trim(Mid(sString, 2, Len(sString) - 2)) Else .TargetName = Trim(sString)
				Select Case .Target
					Case &quot;Bookmark&quot;		:	Set oColl = _Component.getBookmarks()
					Case &quot;Field&quot;		:	Set oColl = _Component.getTextFieldMasters()
											.TargetName = &quot;com.sun.star.text.fieldmaster.User.&quot; &amp; .TargetName
											If Not oColl.hasByName(.TargetName) Then .TargetName = Replace(.TargetName, &quot;.User.&quot;, &quot;.SetExpression.&quot;)
					Case &quot;Frame&quot;		:	Set oColl = _Component.getTextFrames()
					Case &quot;Section&quot;		:	Set oColl = _Component.getTextSections()
				End Select
				If .Target = &quot;Field&quot; Then vNames = Fields() Else vNames =  oColl.getElementNames()
				If Not ScriptForge.SF_Utils._Validate(.TargetName, .Target, V_STRING, vNames, True) Then GoTo Finally
				Set .TargetObject = oColl.getByName(.TargetName)

				&apos;	Set text, anchor and cursor: order varies depending on target
				Select Case .Target
					Case &quot;Bookmark&quot;, &quot;Field&quot;, &quot;Section&quot;
						If .Target = &quot;Field&quot; Then Set .Anchor = .TargetObject.DependentTextFields(0).Anchor Else Set .Anchor = .TargetObject.Anchor
						If .StartPoint And Not .EndPoint Then
							Set .Anchor = .Anchor.Start
						ElseIf Not .StartPoint And .EndPoint Then
							Set .Anchor = .Anchor.End
						End If
						Set .Text = .Anchor.Text
						Set .Cursor = .Text.createTextCursorByRange(.Anchor)
					Case &quot;Frame&quot;
						Set .Text = .TargetObject.Start.Text
						Set .Anchor = .Text.Anchor
						Set .Cursor = .Text.createTextCursor()
						If .StartPoint And Not .EndPoint Then
							.Cursor.gotoStart(False)
						ElseIf Not .StartPoint And .EndPoint Then
							.Cursor.gotoEnd(False)
						Else
							.Cursor.gotoStart(False)
							.Cursor.gotoEnd(True)
						End If
					Case Else
				End Select

			&apos;	Body
			Case oStr.IsRegex(psTextRange, &quot;\|?\s*BODY\s*\|?&quot;)
				Set .Text = _Component.Text
				Set .Anchor = .Text.Start
				Set .Cursor = .Text.createTextCursor()
				If .StartPoint And Not .EndPoint Then
					.Cursor.gotoStart(False)
				ElseIf Not .StartPoint And .EndPoint Then
					Set .Anchor = .Text.End
					.Cursor.gotoEnd(False)
				Else
					.Cursor.gotoStart(False)
					.Cursor.gotoEnd(True)
				End If

			&apos;	Table cell				
			Case oStr.IsRegex(psTextRange, &quot;\|?\s*TABLE!([\w\s]+|&apos;[^&apos;]+&apos;|&quot;&quot;[^&quot;&quot;]+&quot;&quot;)![\s]*[A-Za-z]+[1-9][0-9]*\s*\|?&quot;)
				.Target = &quot;TableCell&quot;
				&apos;	Identify table by its name
				sString = Split(psTextRange, &quot;!&quot;)(1)
				sLeft1 = Left(sString, 1)
				If (sLeft1 = &quot;&quot;&quot;&quot; Or sLeft1 = &quot;&apos;&quot;) And Len(sString) &gt; 2 Then .TargetName = Trim(Mid(sString, 2, Len(sString) - 2)) Else .TargetName = Trim(sString)
				Set oColl = _Component.getTextTables()
				vNames =  oColl.getElementNames()
				If Not ScriptForge.SF_Utils._Validate(.TargetName, .Target, V_STRING, vNames, True) Then GoTo Finally
				Set oItem = oColl.getByName(.TargetName)
				.TargetCell = Split(psTextRange, &quot;!&quot;)(2)
				&apos;	Set text, anchor and cursor
				Set .TargetObject = oItem.getCellByName(.TargetCell)
				If IsNull(.TargetObject) Then GoTo CatchRange	&apos;	The given range is out of the scope of the table
				Set .Text = .TargetObject.Text
				Set .Anchor = .Text.Start
				Set .Cursor = .Text.createTextCursor()
				If .StartPoint And Not .EndPoint Then
					.Cursor.gotoStart(False)
				ElseIf Not .StartPoint And .EndPoint Then
					Set .Anchor = .Text.End
					.Cursor.gotoEnd(False)
				Else
					.Cursor.gotoStart(False)
					.Cursor.gotoEnd(True)
				End If

			Case Else
				GoTo CatchRange
		End Select

		&apos;	Determine Location if not yet done
		If .Location = &quot;&quot; And Not IsNull(.Text) Then
			Select Case .Text.ImplementationName
				Case &quot;SwXBodyText&quot;		:	.Location = &quot;Body&quot;
				Case &quot;SwXTextFrame&quot;		:	.Location = &quot;Frame&quot;
				Case &quot;SwXCell&quot;			:	.Location = &quot;Cell&quot;
				Case &quot;SwXHeadFootText&quot;	:	.Location = &quot;Header/Footer&quot;
				Case &quot;SwXFootnote&quot;		:	.Location = &quot;Footnote/Endnote&quot;
				Case &quot;SwXShape&quot;			:	.Location = &quot;Shape&quot;
				Case Else				:	.Location = .Text.ImplementationName
			End Select
		End If

	End With

Finally:
	Set _ParseRange = oTextRange
	Exit Function
CatchError:
	ScriptForge.SF_Exception.Clear()
CatchRange:
	ScriptForge.SF_Exception.RaiseFatal(WRITERRANGEERROR, &quot;TextRange&quot;, psTextRange _
				, &quot;Document&quot;, [_Super]._FileIdent())
	GoTo Finally
End Function	&apos;	SFDocuments.SF_Writer._ParseRange

REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String _
								, Optional ByVal pvArg As Variant _
								) As Variant
&apos;&apos;&apos;	Return the value of the named property
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;		psProperty: the name of the property

Dim oFieldMasters As Object		&apos;	SwXTextFieldMasters
Dim vMasters As Variant			&apos;	Array of SwXTextFieldMasters
Dim oMaster As Object			&apos;	A single SwXTextFieldMasters
Dim sField As String			&apos;	A text field full name
Dim vFieldNames As Variant		&apos;	Array of field names as strings
Dim cstThisSub As String
Const cstSubArgs = &quot;&quot;

	_PropertyGet = False

	cstThisSub = &quot;SFDocuments.Writer.get&quot; &amp; psProperty
	ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
	If Not _IsStillAlive() Then GoTo Finally

	Select Case UCase(psProperty)
		Case UCase(&quot;Bookmarks&quot;)
			_PropertyGet = _Component.getBookmarks().getElementNames()
		Case UCase(&quot;CurrentSelection&quot;)
			_PropertyGet = _Component.CurrentSelection
		Case UCase(&quot;Fields&quot;)
			vFieldNames = Array()
			Set oFieldMasters = _Component.getTextFieldMasters()
			vMasters = oFieldMasters.getElementNames()
			For Each sField In vMasters
				If ScriptForge.SF_String.StartsWith(sField, &quot;com.sun.star.text.fieldmaster.User&quot;) Then
					Set oMaster = oFieldMasters.getByName(sField)
					vFieldNames = ScriptForge.SF_Array.InsertSorted(vFieldNames, oMaster.Name, CaseSensitive := True)
				ElseIf ScriptForge.SF_String.StartsWith(sField, &quot;com.sun.star.text.fieldmaster.SetExpression&quot;) Then
					Set oMaster = oFieldMasters.getByName(sField)
					If oMaster.SubType = com.sun.star.text.SetVariableType.VAR Then
						vFieldNames = ScriptForge.SF_Array.InsertSorted(vFieldNames, oMaster.Name, CaseSensitive := True)
					End If
				End If
			Next sField
			_PropertyGet = vFieldNames
		Case UCase(&quot;Frames&quot;)
			_PropertyGet = _Component.getTextFrames().getElementNames()
		Case Else
			_PropertyGet = Null
	End Select

Finally:
	ScriptForge.SF_Utils._ExitFunction(cstThisSub)
	Exit Function
End Function	&apos;	SFDocuments.SF_Writer._PropertyGet

REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos;	Convert the SF_Writer instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos;	Args:
&apos;&apos;&apos;	Return:
&apos;&apos;&apos;		&quot;[DOCUMENT]: Type/File&quot;

	_Repr = &quot;[Writer]: &quot; &amp; [_Super]._FileIdent()

End Function	&apos;	SFDocuments.SF_Writer._Repr

REM ============================================ END OF SFDOCUMENTS.SF_WRITER
</script:module>