summaryrefslogtreecommitdiff
path: root/wizards
diff options
context:
space:
mode:
authorJean-Pierre Ledure <jp@ledure.be>2020-11-05 16:28:52 +0100
committerJean-Pierre Ledure <jp@ledure.be>2020-11-05 16:28:52 +0100
commitcdedc00ff579980c73b3cdb5fee0c78c1e111361 (patch)
tree923d2d3158118133484befaa7fc74d5a5c5dfe9c /wizards
parent9597440731cad723434df0867dbe97506201df29 (diff)
ScriptForge - SFDocuments library
Additional "LibreOffice Macros & Dialogs" library Change-Id: I1eadae02d2bbd5d549d9a5bbcec2b83682c7c2ab
Diffstat (limited to 'wizards')
-rw-r--r--wizards/source/sfdocuments/SF_Base.xba464
-rw-r--r--wizards/source/sfdocuments/SF_Calc.xba2843
-rw-r--r--wizards/source/sfdocuments/SF_Document.xba1010
-rw-r--r--wizards/source/sfdocuments/SF_Register.xba198
-rw-r--r--wizards/source/sfdocuments/__License.xba26
-rw-r--r--wizards/source/sfdocuments/dialog.xlb3
-rw-r--r--wizards/source/sfdocuments/script.xlb9
7 files changed, 4553 insertions, 0 deletions
diff --git a/wizards/source/sfdocuments/SF_Base.xba b/wizards/source/sfdocuments/SF_Base.xba
new file mode 100644
index 000000000000..166b717919d3
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Base.xba
@@ -0,0 +1,464 @@
+<?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_Base" 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_Base
+&apos;&apos;&apos; =======
+&apos;&apos;&apos;
+&apos;&apos;&apos; The SFDocuments library gathers a number of methods and properties making easy
+&apos;&apos;&apos; the management and several manipulations of 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, ...
+&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_Base module is provided only to block parent properties that are NOT applicable to Base documents
+&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.CreateBaseDocument(&quot;C:\Me\MyFile.odb&quot;, ...)
+&apos;&apos;&apos; &apos; or Set oDoc = ui.OpenDocument(&quot;C:\Me\MyFile.odb&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.Base&quot;, &quot;MyFile.odb&quot;)
+&apos;&apos;&apos; &apos; The substring &quot;SFDocuments.&quot; in the service name is optional
+&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 DBCONNECTERROR = &quot;DBCONNECTERROR&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 BASE
+Private ServiceName As String
+
+&apos; Window component
+Private _Component As Object &apos; com.sun.star.comp.dba.ODatabaseDocument
+Private _DataSource As Object &apos; com.sun.star.comp.dba.ODatabaseSource
+Private _Database As Object &apos; SFDatabases.Database service instance
+
+REM ============================================================ MODULE CONSTANTS
+
+REM ===================================================== CONSTRUCTOR/DESCTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ Set [_Super] = Nothing
+ ObjectType = &quot;BASE&quot;
+ ServiceName = &quot;SFDocuments.Base&quot;
+ Set _Component = Nothing
+ Set _DataSource = Nothing
+ Set _Database = Nothing
+End Sub &apos; SFDocuments.SF_Base Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDocuments.SF_Base 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_Base Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
+&apos;&apos;&apos; The closure of a Base document requires the closures of
+&apos;&apos;&apos; 1) the connection =&gt; done in the CloseDatabase() method
+&apos;&apos;&apos; 2) the data source
+&apos;&apos;&apos; 3) the document itself =&gt; done in the superclass
+
+Const cstThisSub = &quot;SFDocuments.Base.CloseDocument&quot;
+Const cstSubArgs = &quot;[SaveAsk=True]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(SaveAsk) Or IsEmpty(SaveAsk) Then SaveAsk = True
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SaveAsk, &quot;SaveAsk&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ If Not IsNull(_Database) Then _Database.CloseDatabase()
+ If Not IsNull(_DataSource) Then _DataSource.dispose()
+ CloseDocument = [_Super].CloseDocument(SaveAsk)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Base.CloseDocument
+
+REM -----------------------------------------------------------------------------
+Public Function GetDatabase(Optional ByVal User As Variant _
+ , Optional ByVal Password As Variant _
+ ) As Object
+&apos;&apos;&apos; Returns a Database instance (service = SFDatabases.Database) giving access
+&apos;&apos;&apos; to the execution of SQL commands on the database defined and/or stored in
+&apos;&apos;&apos; the actual Base document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; User, Password: the login parameters as strings. Defaults = &quot;&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A SFDatabases.Database instance or Nothing
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myDb As Object
+&apos;&apos;&apos; Set myDb = oDoc.GetDatabase()
+
+Const cstThisSub = &quot;SFDocuments.Base.GetDatabase&quot;
+Const cstSubArgs = &quot;[User=&quot;&quot;&quot;&quot;], [Password=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set GetDatabase = Nothing
+
+Check:
+ If IsMissing(User) Or IsEmpty(User) Then User = &quot;&quot;
+ If IsMissing(Password) Or IsEmpty(Password) Then Password = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(User, &quot;User&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Password, &quot;Password&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If IsNull(_Database) Then &apos; 1st connection from the current document instance
+ If IsNull(_DataSource) Then GoTo CatchConnect
+ Set _Database = ScriptForge.SF_Services.CreateScriptService(&quot;SFDatabases.DatabaseFromDocument&quot; _
+ , _DataSource, User, Password)
+ If IsNull(_Database) Then GoTo CatchConnect
+ _Database._Location = [_Super]._WindowFileName
+ EndIf
+
+Finally:
+ Set GetDatabase = _Database
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchConnect:
+ ScriptForge.SF_Exception.RaiseFatal(DBCONNECTERROR, &quot;User&quot;, User, &quot;Password&quot;, Password, [_Super]._FileIdent())
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Base.GetDatabase
+
+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.Base.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_Base.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Model service as an array
+
+ Methods = Array( _
+ &quot;Activate&quot; _
+ , &quot;CloseDocument&quot; _
+ , &quot;GetDatabase&quot; _
+ , &quot;RunCommand&quot; _
+ , &quot;Save&quot; _
+ , &quot;SaveAs&quot; _
+ , &quot;SaveCopyAs&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Base.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Timer class as an array
+
+ Properties = Array( _
+ &quot;DocumentType&quot; _
+ , &quot;IsBase&quot; _
+ , &quot;IsCalc&quot; _
+ , &quot;IsDraw &quot; _
+ , &quot;IsImpress&quot; _
+ , &quot;IsMath&quot; _
+ , &quot;IsWriter&quot; _
+ , &quot;XComponent&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Base.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function SetProperty(Optional ByVal PropertyName As Variant _
+ , Optional ByRef Value As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Set a new value to the given property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; PropertyName: the name of the property as a string
+&apos;&apos;&apos; Value: its new value
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; ARGUMENTERROR The property does not exist
+
+Const cstThisSub = &quot;SFDocuments.Base.SetProperty&quot;
+Const cstSubArgs = &quot;PropertyName, Value&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ SetProperty = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ End If
+
+Try:
+ Select Case UCase(PropertyName)
+ Case Else
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Documents.SetProperty
+
+REM ======================================================= SUPERCLASS PROPERTIES
+
+REM -----------------------------------------------------------------------------
+&apos;Property Get CustomProperties() As Variant
+&apos; CustomProperties = [_Super].GetProperty(&quot;CustomProperties&quot;)
+&apos;End Property &apos; SFDocuments.SF_Base.CustomProperties
+
+REM -----------------------------------------------------------------------------
+&apos;Property Let CustomProperties(Optional ByVal pvCustomProperties As Variant)
+&apos; [_Super].CustomProperties = pvCustomProperties
+&apos;End Property &apos; SFDocuments.SF_Base.CustomProperties
+
+REM -----------------------------------------------------------------------------
+&apos;Property Get Description() As Variant
+&apos; Description = [_Super].GetProperty(&quot;Description&quot;)
+&apos;End Property &apos; SFDocuments.SF_Base.Description
+
+REM -----------------------------------------------------------------------------
+&apos;Property Let Description(Optional ByVal pvDescription As Variant)
+&apos; [_Super].Description = pvDescription
+&apos;End Property &apos; SFDocuments.SF_Base.Description
+
+REM -----------------------------------------------------------------------------
+&apos;Property Get DocumentProperties() As Variant
+&apos; DocumentProperties = [_Super].GetProperty(&quot;DocumentProperties&quot;)
+&apos;End Property &apos; SFDocuments.SF_Base.DocumentProperties
+
+REM -----------------------------------------------------------------------------
+Property Get DocumentType() As String
+ DocumentType = [_Super].GetProperty(&quot;DocumentType&quot;)
+End Property &apos; SFDocuments.SF_Base.DocumentType
+
+REM -----------------------------------------------------------------------------
+Property Get IsBase() As Boolean
+ IsBase = [_Super].GetProperty(&quot;IsBase&quot;)
+End Property &apos; SFDocuments.SF_Base.IsBase
+
+REM -----------------------------------------------------------------------------
+Property Get IsCalc() As Boolean
+ IsCalc = [_Super].GetProperty(&quot;IsCalc&quot;)
+End Property &apos; SFDocuments.SF_Base.IsCalc
+
+REM -----------------------------------------------------------------------------
+Property Get IsDraw() As Boolean
+ IsDraw = [_Super].GetProperty(&quot;IsDraw&quot;)
+End Property &apos; SFDocuments.SF_Base.IsDraw
+
+REM -----------------------------------------------------------------------------
+Property Get IsImpress() As Boolean
+ IsImpress = [_Super].GetProperty(&quot;IsImpress&quot;)
+End Property &apos; SFDocuments.SF_Base.IsImpress
+
+REM -----------------------------------------------------------------------------
+Property Get IsMath() As Boolean
+ IsMath = [_Super].GetProperty(&quot;IsMath&quot;)
+End Property &apos; SFDocuments.SF_Base.IsMath
+
+REM -----------------------------------------------------------------------------
+Property Get IsWriter() As Boolean
+ IsWriter = [_Super].GetProperty(&quot;IsWriter&quot;)
+End Property &apos; SFDocuments.SF_Base.IsWriter
+
+REM -----------------------------------------------------------------------------
+&apos;Property Get Keywords() As Variant
+&apos; Keywords = [_Super].GetProperty(&quot;Keywords&quot;)
+&apos;End Property &apos; SFDocuments.SF_Base.Keywords
+
+REM -----------------------------------------------------------------------------
+&apos;Property Let Keywords(Optional ByVal pvKeywords As Variant)
+&apos; [_Super].Keywords = pvKeywords
+&apos;End Property &apos; SFDocuments.SF_Base.Keywords
+
+REM -----------------------------------------------------------------------------
+&apos;Property Get Readonly() As Variant
+&apos; Readonly = [_Super].GetProperty(&quot;Readonly&quot;)
+&apos;End Property &apos; SFDocuments.SF_Base.Readonly
+
+REM -----------------------------------------------------------------------------
+&apos;Property Get Subject() As Variant
+&apos; Subject = [_Super].GetProperty(&quot;Subject&quot;)
+&apos;End Property &apos; SFDocuments.SF_Base.Subject
+
+REM -----------------------------------------------------------------------------
+&apos;Property Let Subject(Optional ByVal pvSubject As Variant)
+&apos; [_Super].Subject = pvSubject
+&apos;End Property &apos; SFDocuments.SF_Base.Subject
+
+REM -----------------------------------------------------------------------------
+&apos;Property Get Title() As Variant
+&apos; Title = [_Super].GetProperty(&quot;Title&quot;)
+&apos;End Property &apos; SFDocuments.SF_Base.Title
+
+REM -----------------------------------------------------------------------------
+&apos;Property Let Title(Optional ByVal pvTitle As Variant)
+&apos; [_Super].Title = pvTitle
+&apos;End Property &apos; SFDocuments.SF_Base.Title
+
+REM -----------------------------------------------------------------------------
+Property Get XComponent() As Variant
+ XComponent = [_Super].GetProperty(&quot;XComponent&quot;)
+End Property &apos; SFDocuments.SF_Base.XComponent
+
+REM ========================================================== SUPERCLASS METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Activate() As Boolean
+ Activate = [_Super].Activate()
+End Function &apos; SFDocuments.SF_Base.Activate
+
+REM -----------------------------------------------------------------------------
+Public Sub RunCommand(Optional ByVal Command As Variant)
+ [_Super].RunCommand(Command)
+End Sub &apos; SFDocuments.SF_Base.RunCommand
+
+REM -----------------------------------------------------------------------------
+Public Function Save() As Boolean
+ Save = [_Super].Save()
+End Function &apos; SFDocuments.SF_Base.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_Base.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_Base.SaveCopyAs
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+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 oProperties As Object &apos; Document or Custom properties
+Dim vLastCell As Variant &apos; Coordinates of last used cell in a sheet
+Dim oSelect As Object &apos; Current selection
+Dim vRanges As Variant &apos; List of selected ranges
+Dim i As Long
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ _PropertyGet = False
+
+ cstThisSub = &quot;SFDocuments.SF_Base.get&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+
+ Select Case psProperty
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFDocuments.SF_Base._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the SF_Base instance to a readable string, typically for debugging purposes (DebugPrint ...)
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Return:
+&apos;&apos;&apos; &quot;[Base]: Type/File&quot;
+
+ _Repr = &quot;[Base]: &quot; &amp; [_Super]._FileIdent()
+
+End Function &apos; SFDocuments.SF_Base._Repr
+
+REM ============================================ END OF SFDOCUMENTS.SF_BASE
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdocuments/SF_Calc.xba b/wizards/source/sfdocuments/SF_Calc.xba
new file mode 100644
index 000000000000..5c897e2dbd14
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Calc.xba
@@ -0,0 +1,2843 @@
+<?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_Calc" 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_Calc
+&apos;&apos;&apos; =======
+&apos;&apos;&apos;
+&apos;&apos;&apos; The SFDocuments library gathers a number of methods and properties making easy
+&apos;&apos;&apos; the management and several manipulations of 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, ...
+&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_Calc module is focused on :
+&apos;&apos;&apos; - management (copy, insert, move, ...) of sheets within a Calc document
+&apos;&apos;&apos; - exchange of data between Basic data structures and Calc ranges of values
+&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;Calc&quot;, ...)
+&apos;&apos;&apos; &apos; or Set oDoc = ui.OpenDocument(&quot;C:\Me\MyFile.ods&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.Calc&quot;, &quot;Untitled 1&quot;) &apos; Default = ActiveWindow
+&apos;&apos;&apos; &apos; or Set oDoc = CreateScriptService(&quot;SFDocuments.Calc&quot;, &quot;Untitled 1&quot;) &apos; Untitled 1 is presumed a Calc 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;Sheet&quot; or a &quot;Range&quot; as argument. (NB: a single cell is considered as a special case of a Range)
+&apos;&apos;&apos; Usually, within a specific Calc instance, sheets and ranges are given as a string: &quot;SheetX&quot; and &quot;D2:F6&quot;
+&apos;&apos;&apos; Multiple ranges are not supported in this context.
+&apos;&apos;&apos; Additionally, the .Sheet and .Range methods return a reference that may be used
+&apos;&apos;&apos; as argument of a method called from another instance of the Calc service
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim oDocA As Object : Set oDocA = ui.OpenDocument(&quot;C:\FileA.ods&quot;, Hidden := True, ReadOnly := True)
+&apos;&apos;&apos; Dim oDocB As Object : Set oDocB = ui.OpenDocument(&quot;C:\FileB.ods&quot;)
+&apos;&apos;&apos; oDocB.CopyToRange(oDocA.Range(&quot;SheetX.D4:F8&quot;), &quot;D2:F6&quot;) &apos; CopyToRange(source, target)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Sheet: the sheet name as a string or an object produced by .Sheet()
+&apos;&apos;&apos; &quot;~&quot; = current sheet
+&apos;&apos;&apos; Range: a string designating a set of contiguous cells located in a sheet of the current instance
+&apos;&apos;&apos; &quot;~&quot; = current selection (if multiple selections, its 1st component)
+&apos;&apos;&apos; or an object produced by .Range()
+&apos;&apos;&apos; The sheet name is optional (default = active sheet). Surrounding quotes and $ signs are optional
+&apos;&apos;&apos; ~.~, ~ The current selection in the active sheet
+&apos;&apos;&apos; &apos;$SheetX&apos;.D2 or $D$2 A single cell
+&apos;&apos;&apos; &apos;$SheetX&apos;.D2:F6, D2:D10 Multiple cells
+&apos;&apos;&apos; &apos;$SheetX&apos;.A:A or 3:5 All cells in the same column or row up to the last active cell
+&apos;&apos;&apos; SheetX.* All cells up to the last active cell
+&apos;&apos;&apos; myRange A range name at spreadsheet level
+&apos;&apos;&apos; ~.yourRange, SheetX.someRange A range name at sheet level
+&apos;&apos;&apos; myDoc.Range(&quot;SheetX.D2:F6&quot;)
+&apos;&apos;&apos; A range within the sheet SheetX in file associated with the myDoc Calc instance
+&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 UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot;
+Private Const BASEDOCUMENTOPENERROR = &quot;BASEDOCUMENTOPENERROR&quot;
+Private Const CALCADDRESSERROR = &quot;CALCADDRESSERROR&quot;
+Private Const DUPLICATESHEETERROR = &quot;DUPLICATESHEETERROR&quot;
+Private Const OFFSETADDRESSERROR = &quot;OFFSETADDRESSERROR&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 CALC
+Private ServiceName As String
+
+&apos; Window component
+Private _Component As Object &apos; com.sun.star.lang.XComponent
+
+Type _Address
+ ObjectType As String &apos; Must be &quot;SF_CalcReference&quot;
+ RawAddress As String
+ Component As Object &apos; com.sun.star.lang.XComponent
+ SheetName As String
+ SheetIndex As Integer
+ RangeName As String
+ Height As Long
+ Width As Long
+ XSpreadSheet As Object &apos; com.sun.star.sheet.XSpreadsheet
+ XCellRange As Object &apos; com.sun.star.table.XCellRange
+End Type
+
+REM ============================================================ MODULE CONSTANTS
+
+Private Const cstSHEET = 1
+Private Const cstRANGE = 2
+
+Private Const MAXCOLS = 2^10 &apos; Max number of colums in a sheet
+Private Const MAXROWS = 2^20 &apos; Max number of rows in a sheet
+
+Private Const CALCREFERENCE = &quot;SF_CalcReference&quot; &apos; Object type of _Address
+
+REM ===================================================== CONSTRUCTOR/DESCTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ Set [_Super] = Nothing
+ ObjectType = &quot;CALC&quot;
+ ServiceName = &quot;SFDocuments.Calc&quot;
+ Set _Component = Nothing
+End Sub &apos; SFDocuments.SF_Calc Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDocuments.SF_Calc 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_Calc Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get CurrentSelection() As Variant
+&apos;&apos;&apos; Returns as a string the currently selected range or as an array the list of the currently selected ranges
+ CurrentSelection = _PropertyGet(&quot;CurrentSelection&quot;)
+End Property &apos; SFDocuments.SF_Calc.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 is a string or an array of strings
+
+Dim sRange As String &apos; A single selection
+Dim oCellRanges As Object &apos; com.sun.star.sheet.SheetCellRanges
+Dim vRangeAddresses As Variant &apos; Array of com.sun.star.table.CellRangeAddress
+Dim i As Long
+Const cstThisSub = &quot;SFDocuments.Calc.setCurrentSelection&quot;
+Const cstSubArgs = &quot;Selection&quot;
+
+ On Local Error GoTo Catch
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If IsArray(pvSelection) Then
+ If Not ScriptForge.SF_Utils._ValidateArray(pvSelection, &quot;pvSelection&quot;, 1, V_STRING, True) Then GoTo Finally
+ Else
+ If Not ScriptForge.SF_Utils._Validate(pvSelection, &quot;pvSelection&quot;, V_STRING) Then GoTo Finally
+ End If
+ End If
+
+Try:
+ If IsArray(pvSelection) Then
+ Set oCellRanges = _Component.createInstance(&quot;com.sun.star.sheet.SheetCellRanges&quot;)
+ vRangeAddresses = Array()
+ ReDim vRangeAddresses(0 To UBound(pvSelection))
+ For i = 0 To UBound(pvSelection)
+ vRangeAddresses(i) = Range(pvSelection(i)).XCellRange.RangeAddress
+ Next i
+ oCellRanges.addRangeAddresses(vRangeAddresses, False)
+ _Component.CurrentController.select(oCellRanges)
+ Else
+ _Component.CurrentController.select(_ParseAddress(pvSelection).XCellRange)
+ End If
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Property
+Catch:
+ GoTo Finally
+End Property &apos; SFDocuments.SF_Calc.CurrentSelection (let)
+
+REM -----------------------------------------------------------------------------
+Property Get Height(Optional ByVal RangeName As Variant) As Long
+&apos;&apos;&apos; Returns the height in # of rows of the given range
+ Height = _PropertyGet(&quot;Height&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.Height
+
+REM -----------------------------------------------------------------------------
+Property Get LastCell(Optional ByVal SheetName As Variant) As String
+&apos;&apos;&apos; Returns the last used cell in a given sheet
+ LastCell = _PropertyGet(&quot;LastCell&quot;, SheetName)
+End Property &apos; SFDocuments.SF_Calc.LastCell
+
+REM -----------------------------------------------------------------------------
+Property Get LastColumn(Optional ByVal SheetName As Variant) As Long
+&apos;&apos;&apos; Returns the last used column in a given sheet
+ LastColumn = _PropertyGet(&quot;LastColumn&quot;, SheetName)
+End Property &apos; SFDocuments.SF_Calc.LastColumn
+
+REM -----------------------------------------------------------------------------
+Property Get LastRow(Optional ByVal SheetName As Variant) As Long
+&apos;&apos;&apos; Returns the last used column in a given sheet
+ LastRow = _PropertyGet(&quot;LastRow&quot;, SheetName)
+End Property &apos; SFDocuments.SF_Calc.LastRow
+
+REM -----------------------------------------------------------------------------
+Property Get Range(Optional ByVal RangeName As Variant) As Variant
+&apos;&apos;&apos; Returns a (internal) range object
+ Range = _PropertyGet(&quot;Range&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.Range
+
+REM -----------------------------------------------------------------------------
+Property Get Sheet(Optional ByVal SheetName As Variant) As Variant
+&apos;&apos;&apos; Returns a (internal) sheet object
+ Sheet = _PropertyGet(&quot;Sheet&quot;, SheetName)
+End Property &apos; SFDocuments.SF_Calc.Sheet
+
+REM -----------------------------------------------------------------------------
+Property Get Sheets() As Variant
+&apos;&apos;&apos; Returns an array listing the existing sheet names
+ Sheets = _PropertyGet(&quot;Sheets&quot;)
+End Property &apos; SFDocuments.SF_Calc.Sheets
+
+REM -----------------------------------------------------------------------------
+Property Get Width(Optional ByVal RangeName As Variant) As Long
+&apos;&apos;&apos; Returns the width in # of columns of the given range
+ Width = _PropertyGet(&quot;Width&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.Width
+
+REM -----------------------------------------------------------------------------
+Property Get XCellRange(Optional ByVal RangeName As Variant) As Variant
+&apos;&apos;&apos; Returns a UNO object of type com.sun.star.Table.CellRange
+ XCellRange = _PropertyGet(&quot;XCellRange&quot;, RangeName)
+End Property &apos; SFDocuments.SF_Calc.XCellRange
+
+REM -----------------------------------------------------------------------------
+Property Get XSpreadsheet(Optional ByVal SheetName As Variant) As Variant
+&apos;&apos;&apos; Returns a UNO object of type com.sun.star.sheet.XSpreadsheet
+ XSpreadsheet = _PropertyGet(&quot;XSpreadsheet&quot;, SheetName)
+End Property &apos; SFDocuments.SF_Calc.XSpreadsheet
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Activate(Optional ByVal SheetName As Variant) As Boolean
+&apos;&apos;&apos; Make the current document or the given sheet active
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SheetName: Default = the Calc document as a whole
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the document or the sheet could be made active
+&apos;&apos;&apos; Otherwise, there is no change in the actual user interface
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.Activate(&quot;SheetX&quot;)
+
+Dim bActive As Boolean &apos; Return value
+Dim oSheet As Object &apos; Reference to sheet
+Const cstThisSub = &quot;SFDocuments.Calc.Activate&quot;
+Const cstSubArgs = &quot;[SheetName]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bActive = False
+
+Check:
+ If IsMissing(SheetName) Or IsEmpty(SheetName) Then SheetName = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , , True) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Sheet activation, to do only when meaningful, precedes document activation
+ If Len(SheetName) &gt; 0 Then
+ With _Component
+ Set oSheet = .getSheets.getByName(SheetName)
+ Set .CurrentController.ActiveSheet = oSheet
+ End With
+ End If
+ bActive = [_Super].Activate()
+
+Finally:
+ Activate = bActive
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.Activate
+
+REM -----------------------------------------------------------------------------
+Public Sub ClearAll(Optional ByVal Range As Variant) As String
+&apos;&apos;&apos; Clear entirely the given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the cell or the range as a string that should be cleared
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.ClearAll(&quot;SheetX&quot;) &apos; Clears the used area of the sheet
+
+Dim lClear As Long &apos; The elements to clear
+Dim oRange As Object &apos; Alias of Range
+Const cstThisSub = &quot;SFDocuments.Calc.ClearAll&quot;
+Const cstSubArgs = &quot;Range&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ With com.sun.star.sheet.CellFlags
+ lClear = 0 _
+ + .VALUE _
+ + .DATETIME _
+ + .STRING _
+ + .ANNOTATION _
+ + .FORMULA _
+ + .HARDATTR _
+ + .STYLES _
+ + .OBJECTS _
+ + .EDITATTR _
+ + .FORMATTED
+ Set oRange = _ParseAddress(Range)
+ oRange.XCellRange.clearContents(lClear)
+ End With
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; SF_Documents.SF_Calc.ClearAll
+
+REM -----------------------------------------------------------------------------
+Public Sub ClearFormats(Optional ByVal Range As Variant) As String
+&apos;&apos;&apos; Clear all the formatting elements of the given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the cell or the range as a string that should be cleared
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.ClearFormats(&quot;SheetX:A1:E100&quot;) &apos; Clear the formats of the given range
+
+Dim lClear As Long &apos; The elements to clear
+Dim oRange As Object &apos; Alias of Range
+Const cstThisSub = &quot;SFDocuments.Calc.ClearFormats&quot;
+Const cstSubArgs = &quot;Range&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ With com.sun.star.sheet.CellFlags
+ lClear = 0 _
+ + .HARDATTR _
+ + .STYLES _
+ + .EDITATTR _
+ + .FORMATTED
+ Set oRange = _ParseAddress(Range)
+ oRange.XCellRange.clearContents(lClear)
+ End With
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; SF_Documents.SF_Calc.ClearFormats
+
+REM -----------------------------------------------------------------------------
+Public Sub ClearValues(Optional ByVal Range As Variant) As String
+&apos;&apos;&apos; Clear values and formulas in the given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the cell or the range as a string that should be cleared
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.ClearValues(&quot;SheetX:*&quot;) &apos; Clears the used area of the sheet
+
+Dim lClear As Long &apos; The elements to clear
+Dim oRange As Object &apos; Alias of Range
+Const cstThisSub = &quot;SFDocuments.Calc.ClearValues&quot;
+Const cstSubArgs = &quot;Range&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ With com.sun.star.sheet.CellFlags
+ lClear = 0 _
+ + .VALUE _
+ + .DATETIME _
+ + .STRING _
+ + .FORMULA
+ Set oRange = _ParseAddress(Range)
+ oRange.XCellRange.clearContents(lClear)
+ End With
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; SF_Documents.SF_Calc.ClearValues
+
+REM -----------------------------------------------------------------------------
+Public Function CopySheet(Optional ByVal SheetName As Variant _
+ , Optional ByVal NewName As Variant _
+ , Optional ByVal BeforeSheet As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Copy a specified sheet before an existing sheet or at the end of the list of sheets
+&apos;&apos;&apos; The sheet to copy may be inside any open Calc document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SheetName: The name of the sheet to copy or its reference
+&apos;&apos;&apos; NewName: Must not exist
+&apos;&apos;&apos; BeforeSheet: The name (string) or index (numeric, starting from 1) of the sheet before which to insert
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the sheet could be copied successfully
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DUPLICATESHEETERROR A sheet with the given name exists already
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.CopySheet(&quot;SheetX&quot;, &quot;SheetY&quot;)
+&apos;&apos;&apos; &apos; Copy within the same document
+&apos;&apos;&apos; Dim oDocA As Object : Set oDocA = ui.OpenDocument(&quot;C:\Temp\FileA.ods&quot;, Hidden := True, ReadOnly := True)
+&apos;&apos;&apos; Dim oDocB As Object : Set oDocB = ui.OpenDocument(&quot;C:\Temp\FileB.ods&quot;)
+&apos;&apos;&apos; oDocB.CopySheet(oDocA.Sheet(&quot;SheetX&quot;), &quot;SheetY&quot;)
+&apos;&apos;&apos; &apos; Copy from 1 file to another and put the new sheet at the end
+
+Dim bCopy As Boolean &apos; Return value
+Dim oSheets As Object &apos; com.sun.star.sheet.XSpreadsheets
+Dim vSheets As Variant &apos; List of existing sheets
+Dim lSheetIndex As Long &apos; Index of a sheet
+Dim oSheet As Object &apos; Alias of SheetName as reference
+Dim lRandom As Long &apos; Output of random number generator
+Dim sRandom &apos; Random sheet name
+Const cstThisSub = &quot;SFDocuments.Calc.CopySheet&quot;
+Const cstSubArgs = &quot;SheetName, NewName, [BeforeSheet=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCopy = False
+
+Check:
+ If IsMissing(BeforeSheet) Or IsEmpty(BeforeSheet) Then BeforeSheet = 32768
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True, , , True) Then GoTo Finally
+ If Not _ValidateSheet(NewName, &quot;NewName&quot;, True) Then GoTo Finally
+ If Not _ValidateSheet(BeforeSheet, &quot;BeforeSheet&quot;, , True, , True) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Determine the index of the sheet before which to insert the copy
+ Set oSheets = _Component.getSheets
+ vSheets = oSheets.getElementNames()
+ If VarType(BeforeSheet) = V_STRING Then
+ lSheetIndex = ScriptForge.SF_Array.IndexOf(vSheets, BeforeSheet)
+ Else
+ lSheetIndex = BeforeSheet - 1
+ If lSheetIndex &lt; 0 Then lSheetIndex = 0
+ If lSheetIndex &gt; UBound(vSheets) Then lSheetIndex = UBound(vSheets) + 1
+ End If
+
+ &apos; Copy sheet inside the same document OR import from another document
+ If VarType(SheetName) = V_STRING Then
+ _Component.getSheets.copyByName(SheetName, NewName, lSheetIndex)
+ Else
+ Set oSheet = SheetName
+ With oSheet
+ &apos; If a sheet with same name as input exists in the target sheet, rename it first with a random name
+ sRandom = &quot;&quot;
+ If ScriptForge.SF_Array.Contains(vSheets, .SheetName) Then
+ lRandom = ScriptForge.SF_Session.ExecuteCalcFunction(&quot;RANDBETWEEN&quot;, 1, 9999999)
+ sRandom = &quot;SF_&quot; &amp; Right(&quot;0000000&quot; &amp; lRandom, 7)
+ oSheets.getByName(.SheetName).setName(sRandom)
+ End If
+ &apos; Import i.o. Copy
+ oSheets.importSheet(oSheet.Component, .SheetName, lSheetIndex)
+ &apos; Rename to new sheet name
+ oSheets.getByName(.SheetName).setName(NewName)
+ &apos; Reset random name
+ If Len(sRandom) &gt; 0 Then oSheets.getByName(srandom).setName(.SheetName)
+ End With
+ End If
+ bCopy = True
+
+Finally:
+ CopySheet = bCopy
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchDuplicate:
+ ScriptForge.SF_Exception.RaiseFatal(DUPLICATESHEETERROR, &quot;NewName&quot;, NewName, &quot;Document&quot;, [_Super]._FileIdent())
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.CopySheet
+
+REM -----------------------------------------------------------------------------
+Public Function CopySheetFromFile(Optional ByVal FileName As Variant _
+ , Optional ByVal SheetName As Variant _
+ , Optional ByVal NewName As Variant _
+ , Optional ByVal BeforeSheet As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Copy a specified sheet before an existing sheet or at the end of the list of sheets
+&apos;&apos;&apos; The sheet to copy is located inside any closed Calc document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file to open. It must follow the SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; The file must not be protected with a password
+&apos;&apos;&apos; SheetName: The name of the sheet to copy or its reference
+&apos;&apos;&apos; NewName: Must not exist
+&apos;&apos;&apos; BeforeSheet: The name (string) or index (numeric, starting from 1) of the sheet before which to insert
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the sheet could be created
+&apos;&apos;&apos; The created sheet is blank when the input file is not a Calc file
+&apos;&apos;&apos; The created sheet contains an error message when the input sheet was not found
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DUPLICATESHEETERROR A sheet with the given name exists already
+&apos;&apos;&apos; UNKNOWNFILEERROR The input file is unknown
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.CopySheetFromFile(&quot;C:\MyFile.ods&quot;, &quot;SheetX&quot;, &quot;SheetY&quot;, 3)
+
+Dim bCopy As Boolean &apos; Return value
+Dim oSheet As Object &apos; com.sun.star.sheet.XSpreadsheet
+Dim sFileName As String &apos; URL alias of FileName
+Dim FSO As Object &apos; SF_FileSystem
+Const cstThisSub = &quot;SFDocuments.Calc.CopySheetFromFile&quot;
+Const cstSubArgs = &quot;FileName, SheetName, NewName, [BeforeSheet=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCopy = False
+
+Check:
+ If IsMissing(BeforeSheet) Or IsEmpty(BeforeSheet) Then BeforeSheet = 32768
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SheetName, &quot;SheetName&quot;, V_STRING) Then GoTo Finally
+ If Not _ValidateSheet(NewName, &quot;NewName&quot;, True) Then GoTo Finally
+ If Not _ValidateSheet(BeforeSheet, &quot;BeforeSheet&quot;, , True, , True) Then GoTo Finally
+ End If
+
+Try:
+ Set FSO = ScriptForge.SF_FileSystem
+ &apos; Does the input file exist ?
+ If Not FSO.FileExists(FileName) Then GoTo CatchNotExists
+ sFileName = FSO._ConvertToUrl(FileName)
+
+ &apos; Insert a blank new sheet and import sheet from file va link setting and deletion
+ If Not InsertSheet(Newname, BeforeSheet) Then GoTo Finally
+ Set oSheet = _Component.getSheets.getByName(NewName)
+ With oSheet
+ .link(sFileName,SheetName, &quot;&quot;, &quot;&quot;, com.sun.star.sheet.SheetLinkMode.NORMAL)
+ .LinkMode = com.sun.star.sheet.SheetLinkMode.NONE
+ .LinkURL = &quot;&quot;
+ End With
+ bCopy = True
+
+Finally:
+ CopySheetFromFile = bCopy
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ ScriptForge.SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.CopySheetFromFile
+
+REM -----------------------------------------------------------------------------
+Public Function CopyToCell(Optional ByVal SourceRange As Variant _
+ , Optional ByVal DestinationCell As Variant _
+ ) As String
+&apos;&apos;&apos; Copy a specified source range to a destination range or cell
+&apos;&apos;&apos; The source range may belong to another open document
+&apos;&apos;&apos; The method imitates the behaviour of a Copy/Paste from a range to a single cell
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SourceRange: the source range as a string if it belongs to the same document
+&apos;&apos;&apos; or as a reference if it belongs to another open Calc document
+&apos;&apos;&apos; DestinationCell: the destination of the copied range of cells, as a string
+&apos;&apos;&apos; If given as range, the destination will be reduced to its top-left cell
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the modified range of cells
+&apos;&apos;&apos; The modified area depends only on the size of the source area
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.CopyToCell(&quot;SheetX.A1:F10&quot;, &quot;SheetY.C5&quot;)
+&apos;&apos;&apos; &apos; Copy within the same document
+&apos;&apos;&apos; Dim oDocA As Object : Set oDocA = ui.OpenDocument(&quot;C:\Temp\FileA.ods&quot;, Hidden := True, ReadOnly := True)
+&apos;&apos;&apos; Dim oDocB As Object : Set oDocB = ui.OpenDocument(&quot;C:\Temp\FileB.ods&quot;)
+&apos;&apos;&apos; oDocB.CopyToCell(oDocA.Range(&quot;SheetX.A1:F10&quot;), &quot;SheetY.C5&quot;)
+&apos;&apos;&apos; &apos; Copy from 1 file to another
+
+Dim sCopy As String &apos; Return value
+Dim oSource As Object &apos; Alias of SourceRange to avoid &quot;Object variable not set&quot; run-time error
+Dim oSourceAddress As Object &apos; com.sun.star.table.CellRangeAddress
+Dim oDestRange As Object &apos; Destination as a range
+Dim oDestAddress As Object &apos; com.sun.star.table.CellRangeAddress
+Dim oDestCell As Object &apos; com.sun.star.table.CellAddress
+Dim oSelect As Object &apos; Current selection in source
+Dim oClipboard As Object &apos; com.sun.star.datatransfer.XTransferable
+
+Const cstThisSub = &quot;SFDocuments.Calc.CopyToCell&quot;
+Const cstSubArgs = &quot;SourceRange, DestinationCell&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sCopy = &quot;&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SourceRange, &quot;SourceRange&quot;, Array(V_STRING, ScriptForge.V_OBJECT), , , CALCREFERENCE) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(DestinationCell, &quot;DestinationCell&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ If VarType(SourceRange) = V_STRING Then &apos; Same document - Use UNO copyRange method
+ Set oSourceAddress = _ParseAddress(SourceRange).XCellRange.RangeAddress
+ Set oDestRange = _ParseAddress(DestinationCell)
+ Set oDestAddress = oDestRange.XCellRange.RangeAddress
+ Set oDestCell = New com.sun.star.table.CellAddress
+ With oDestAddress
+ oDestCell.Sheet = .Sheet
+ oDestCell.Column = .StartColumn
+ oDestCell.Row = .StartRow
+ End With
+ oDestRange.XSpreadsheet.copyRange(oDestCell, oSourceAddress)
+ Else &apos; Use clipboard to copy - current selection in Source should be preserved
+ Set oSource = SourceRange
+ With oSource
+ &apos; Keep current selection in source document
+ Set oSelect = .Component.CurrentController.getSelection()
+ &apos; Select, copy the source range and paste in the top-left cell of the destination
+ .Component.CurrentController.select(.XCellRange)
+ Set oClipboard = .Component.CurrentController.getTransferable()
+ _Component.CurrentController.select(_Offset(DestinationCell, 0, 0, 1, 1).XCellRange)
+ _Component.CurrentController.insertTransferable(oClipBoard)
+ &apos; Restore previous selection in Source
+ _RestoreSelections(.Component, oSelect)
+ Set oSourceAddress = .XCellRange.RangeAddress
+ End With
+ End If
+
+ With oSourceAddress
+ sCopy = _Offset(DestinationCell, 0, 0, .EndRow - .StartRow + 1, .EndColumn - .StartColumn + 1).RangeName
+ End With
+
+Finally:
+ CopyToCell = sCopy
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.CopyToCell
+
+REM -----------------------------------------------------------------------------
+Public Function CopyToRange(Optional ByVal SourceRange As Variant _
+ , Optional ByVal DestinationRange As Variant _
+ ) As String
+&apos;&apos;&apos; Copy downwards and/or rightwards a specified source range to a destination range
+&apos;&apos;&apos; The source range may belong to another open document
+&apos;&apos;&apos; The method imitates the behaviour of a Copy/Paste from a range to a larger range
+&apos;&apos;&apos; If the height (resp. width) of the destination area is &gt; 1 row (resp. column)
+&apos;&apos;&apos; then the height (resp. width) of the source must be &lt;= the height (resp. width)
+&apos;&apos;&apos; of the destination. Otherwise nothing happens
+&apos;&apos;&apos; If the height (resp.width) of the destination is = 1 then the destination
+&apos;&apos;&apos; is expanded downwards (resp. rightwards) up to the height (resp. width)
+&apos;&apos;&apos; of the source range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SourceRange: the source range as a string if it belongs to the same document
+&apos;&apos;&apos; or as a reference if it belongs to another open Calc document
+&apos;&apos;&apos; DestinationRange: the destination of the copied range of cells, as a string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the modified range of cells
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.CopyToRange(&quot;SheetX.A1:F10&quot;, &quot;SheetY.C5:J5&quot;)
+&apos;&apos;&apos; &apos; Copy within the same document
+&apos;&apos;&apos; &apos; Returned range: $SheetY.$C$5:$J$14
+&apos;&apos;&apos; Dim oDocA As Object : Set oDocA = ui.OpenDocument(&quot;C:\Temp\FileA.ods&quot;, Hidden := True, ReadOnly := True)
+&apos;&apos;&apos; Dim oDocB As Object : Set oDocB = ui.OpenDocument(&quot;C:\Temp\FileB.ods&quot;)
+&apos;&apos;&apos; oDocB.CopyToRange(oDocA.Range(&quot;SheetX.A1:F10&quot;), &quot;SheetY.C5:J5&quot;)
+&apos;&apos;&apos; &apos; Copy from 1 file to another
+
+Dim sCopy As String &apos; Return value
+Dim oSource As Object &apos; Alias of SourceRange to avoid &quot;Object variable not set&quot; run-time error
+Dim oDestRange As Object &apos; Destination as a range
+Dim oDestCell As Object &apos; com.sun.star.table.CellAddress
+Dim oSelect As Object &apos; Current selection in source
+Dim oClipboard As Object &apos; com.sun.star.datatransfer.XTransferable
+Dim bSameDocument As Boolean &apos; True when source in same document as destination
+Dim lHeight As Long &apos; Height of destination
+Dim lWidth As Long &apos; Width of destination
+
+Const cstThisSub = &quot;SFDocuments.Calc.CopyToRange&quot;
+Const cstSubArgs = &quot;SourceRange, DestinationRange&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sCopy = &quot;&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SourceRange, &quot;SourceRange&quot;, Array(V_STRING, ScriptForge.V_OBJECT), , , CALCREFERENCE) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(DestinationRange, &quot;DestinationRange&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Copy done via clipboard
+
+ &apos; Check Height/Width destination = 1 or &gt; Height/Width of source
+ bSameDocument = ( VarType(SourceRange) = V_STRING )
+ If bSameDocument Then Set oSource = _ParseAddress(SourceRange) Else Set oSource = SourceRange
+ Set oDestRange = _ParseAddress(DestinationRange)
+ With oDestRange
+ lHeight = .Height
+ lWidth = .Width
+ If lHeight = 1 Then
+ lHeight = oSource.Height &apos; Future height
+ ElseIf lHeight &lt; oSource.Height Then
+ GoTo Finally
+ End If
+ If lWidth = 1 Then
+ lWidth = oSource.Width &apos; Future width
+ ElseIf lWidth &lt; oSource.Width Then
+ GoTo Finally
+ End If
+ End With
+
+ With oSource
+ &apos; Store actual selection in source
+ Set oSelect = .Component.CurrentController.getSelection()
+ &apos; Select, copy the source range and paste in the destination
+ .Component.CurrentController.select(.XCellRange)
+ Set oClipboard = .Component.CurrentController.getTransferable()
+ _Component.CurrentController.select(oDestRange.XCellRange)
+ _Component.CurrentController.insertTransferable(oClipBoard)
+ &apos; Restore selection in source
+ _RestoreSelections(.Component, oSelect)
+ End With
+
+ sCopy = _Offset(oDestRange, 0, 0, lHeight, lWidth).RangeName
+
+Finally:
+ CopyToRange = sCopy
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.CopyToRange
+
+REM -----------------------------------------------------------------------------
+Public Function DAvg(Optional ByVal Range As Variant) As Double
+&apos;&apos;&apos; Get the average of the numeric values stored in the given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the range as a string where to get the values from
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The average of the numeric values as a double
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Val = oDoc.DAvg(&quot;~.A1:A1000&quot;)
+
+Try:
+ DAvg = _DFunction(&quot;DAvg&quot;, Range)
+
+Finally:
+ Exit Function
+End Function &apos; SF_Documents.SF_Calc.DAvg
+
+REM -----------------------------------------------------------------------------
+Public Function DCount(Optional ByVal Range As Variant) As Long
+&apos;&apos;&apos; Get the number of numeric values stored in the given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the range as a string where to get the values from
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The number of numeric values a Long
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Val = oDoc.DCount(&quot;~.A1:A1000&quot;)
+
+Try:
+ DCount = _DFunction(&quot;DCount&quot;, Range)
+
+Finally:
+ Exit Function
+End Function &apos; SF_Documents.SF_Calc.DCount
+
+REM -----------------------------------------------------------------------------
+Public Function DMax(Optional ByVal Range As Variant) As Double
+&apos;&apos;&apos; Get the greatest of the numeric values stored in the given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the range as a string where to get the values from
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The greatest of the numeric values as a double
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Val = oDoc.DMax(&quot;~.A1:A1000&quot;)
+
+Try:
+ DMax = _DFunction(&quot;DMax&quot;, Range)
+
+Finally:
+ Exit Function
+End Function &apos; SF_Documents.SF_Calc.DMax
+
+REM -----------------------------------------------------------------------------
+Public Function DMin(Optional ByVal Range As Variant) As Double
+&apos;&apos;&apos; Get the smallest of the numeric values stored in the given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the range as a string where to get the values from
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The smallest of the numeric values as a double
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Val = oDoc.DMin(&quot;~.A1:A1000&quot;)
+
+Try:
+ DMin = _DFunction(&quot;DMin&quot;, Range)
+
+Finally:
+ Exit Function
+End Function &apos; SF_Documents.SF_Calc.DMin
+
+REM -----------------------------------------------------------------------------
+Public Function DSum(Optional ByVal Range As Variant) As Double
+&apos;&apos;&apos; Get sum of the numeric values stored in the given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the range as a string where to get the values from
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The sum of the numeric values as a double
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Val = oDoc.DSum(&quot;~.A1:A1000&quot;)
+
+Try:
+ DSum = _DFunction(&quot;DSum&quot;, Range)
+
+Finally:
+ Exit Function
+End Function &apos; SF_Documents.SF_Calc.DSum
+
+REM -----------------------------------------------------------------------------
+Function GetColumnName(Optional ByVal ColumnNumber As Variant) As String
+&apos;&apos;&apos; Convert a column number (range 1, 2,..1024) into its letter counterpart (range &apos;A&apos;, &apos;B&apos;,..&apos;AMJ&apos;).
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ColumnNumber: the column number, must be in the interval 1 ... 1024
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; a string representation of the column name, in range &apos;A&apos;..&apos;AMJ&apos;
+&apos;&apos;&apos; If ColumnNumber is not in the allowed range, returns a zero-length string
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox oDoc.GetColumnName(1022) &apos; &quot;AMH&quot;
+&apos;&apos;&apos; Adapted from a Python function by sundar nataraj
+&apos;&apos;&apos; http://stackoverflow.com/questions/23861680/convert-spreadsheet-number-to-column-letter
+
+Dim sCol As String &apos; Return value
+Const cstThisSub = &quot;SFDocuments.Calc.GetColumnName&quot;
+Const cstSubArgs = &quot;ColumnNumber&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sCol = &quot;&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(ColumnNumber, &quot;ColumnNumber&quot;, V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ If (ColumnNumber &gt; 0) And (ColumnNumber &lt;= MAXCOLS) Then sCol = _GetColumnName(ColumnNumber)
+
+Finally:
+ GetColumnName = sCol
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.GetColumnName
+
+REM -----------------------------------------------------------------------------
+Public Function GetFormula(Optional ByVal Range As Variant) As Variant
+&apos;&apos;&apos; Get the formula(e) stored in the given range of cells
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the range as a string where to get the formula from
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A scalar, a zero-based 1D array or a zero-based 2D array of strings
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Val = oDoc.GetFormula(&quot;~.A1:A1000&quot;)
+
+Dim vGet As Variant &apos; Return value
+Dim oAddress As Object &apos; Alias of Range
+Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
+Const cstThisSub = &quot;SFDocuments.Calc.GetFormula&quot;
+Const cstSubArgs = &quot;Range&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vGet = Empty
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Get the data
+ Set oAddress = _ParseAddress(Range)
+ vDataArray = oAddress.XCellRange.getFormulaArray()
+
+ &apos; Convert the data array to scalar, vector or array
+ vGet = _ConvertFromDataArray(vDataArray)
+
+Finally:
+ GetFormula = vGet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.GetFormula
+
+REM -----------------------------------------------------------------------------
+Public Function GetProperty(Optional ByVal PropertyName As Variant _
+ , Optional ObjectName 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; ObjectName: a sheet or range name
+&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.Calc.GetProperty&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+Check:
+ If IsMissing(ObjectName) Or IsEMpty(ObjectName) Then ObjectName = &quot;&quot;
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ If Not ScriptForge.SF_Utils._Validate(ObjectName, &quot;ObjectName&quot;, V_STRING) 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_Calc.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function GetValue(Optional ByVal Range As Variant) As Variant
+&apos;&apos;&apos; Get the value(s) stored in the given range of cells
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the range as a string where to get the value from
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A scalar, a zero-based 1D array or a zero-based 2D array of strings and doubles
+&apos;&apos;&apos; To convert doubles to dates, use the CDate builtin function
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; Val = oDoc.GetValue(&quot;~.A1:A1000&quot;)
+
+Dim vGet As Variant &apos; Return value
+Dim oAddress As Object &apos; Alias of Range
+Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
+Const cstThisSub = &quot;SFDocuments.Calc.GetValue&quot;
+Const cstSubArgs = &quot;Range&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vGet = Empty
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Get the data
+ Set oAddress = _ParseAddress(Range)
+ vDataArray = oAddress.XCellRange.getDataArray()
+
+ &apos; Convert the data array to scalar, vector or array
+ vGet = _ConvertFromDataArray(vDataArray)
+
+Finally:
+ GetValue = vGet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.GetValue
+
+REM -----------------------------------------------------------------------------
+Public Function ImportFromCSVFile(Optional ByVal FileName As Variant _
+ , Optional ByVal DestinationCell As Variant _
+ , Optional ByVal FilterOptions As Variant _
+ ) As String
+&apos;&apos;&apos; Import the content of a CSV-formatted text file starting from a given cell
+&apos;&apos;&apos; Beforehands the destination area will be cleared from any content and format
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file to open. It must follow the SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; DestinationCell: the destination of the copied range of cells, as a string
+&apos;&apos;&apos; If given as range, the destination will be reduced to its top-left cell
+&apos;&apos;&apos; FilterOptions: The arguments of the CSV input filter.
+&apos;&apos;&apos; Read https://wiki.openoffice.org/wiki/Documentation/DevGuide/Spreadsheets/Filter_Options#Filter_Options_for_the_CSV_Filter
+&apos;&apos;&apos; Default: input file encoding is UTF8
+&apos;&apos;&apos; separator = comma, semi-colon or tabulation
+&apos;&apos;&apos; string delimiter = double quote
+&apos;&apos;&apos; all lines are included
+&apos;&apos;&apos; quoted strings are formatted as texts
+&apos;&apos;&apos; special numbers are detected
+&apos;&apos;&apos; all columns are presumed texts
+&apos;&apos;&apos; language = english/US =&gt; decimal separator is &quot;.&quot;, thousands separator = &quot;,&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the modified range of cells
+&apos;&apos;&apos; The modified area depends only on the content of the source file
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DOCUMENTOPENERROR The csv file could not be opened
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.ImportFromCSVFile(&quot;C:\Temp\myCsvFile.csv&quot;, &quot;SheetY.C5&quot;)
+
+Dim sImport As String &apos; Return value
+Dim oUI As Object &apos; UI service
+Dim oSource As Object &apos; New Calc document with csv loaded
+Dim oSelect As Object &apos; Current selection in destination
+
+Const cstFilter = &quot;Text - txt - csv (StarCalc)&quot;
+Const cstFilterOptions = &quot;9/44/59/MRG,34,76,1,,1033,true,true&quot;
+Const cstThisSub = &quot;SFDocuments.Calc.ImportFromCSVFile&quot;
+Const cstSubArgs = &quot;FileName, DestinationCell, [FilterOptions]=&quot;&quot;9/44/59/MRG,34,76,1,,1033,true,true&quot;&quot;&quot;
+
+&apos; If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sImport = &quot;&quot;
+
+Check:
+ If IsMissing(FilterOptions) Or IsEmpty(FilterOptions) Then FilterOptions = cstFilterOptions
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(DestinationCell, &quot;DestinationCell&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Input file is loaded in an empty worksheet. Data are copied to destination cell
+ Set oUI = CreateScriptService(&quot;UI&quot;)
+ Set oSource = oUI.OpenDocument(FileName _
+ , ReadOnly := True _
+ , Hidden := True _
+ , FilterName := cstFilter _
+ , FilterOptions := FilterOptions _
+ )
+ &apos; Remember current selection and restore it after copy
+ Set oSelect = _Component.CurrentController.getSelection()
+ sImport = CopyToCell(oSource.Range(&quot;*&quot;), DestinationCell)
+ _RestoreSelections(_Component, oSelect)
+
+Finally:
+ If Not IsNull(oSource) Then oSource.CloseDocument(False)
+ ImportFromCSVFile = sImport
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.ImportFromCSVFile
+
+REM -----------------------------------------------------------------------------
+Public Sub ImportFromDatabase(Optional ByVal FileName As Variant _
+ , Optional ByVal RegistrationName As Variant _
+ , Optional ByVal DestinationCell As Variant _
+ , Optional ByVal SQLCommand As Variant _
+ , Optional ByVal DirectSQL As Variant _
+ )
+&apos;&apos;&apos; Import the content of a database table, query or resultset, i.e. the result of a SELECT SQL command,
+&apos;&apos;&apos; starting from a given cell
+&apos;&apos;&apos; Beforehands the destination area will be cleared from any content and format
+&apos;&apos;&apos; The modified area depends only on the content of the source data
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file to open. It must follow the SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; RegistrationName: the name of a registered database
+&apos;&apos;&apos; It is ignored if FileName &lt;&gt; &quot;&quot;
+&apos;&apos;&apos; DestinationCell: the destination of the copied range of cells, as a string
+&apos;&apos;&apos; If given as range, the destination will be reduced to its top-left cell
+&apos;&apos;&apos; SQLCommand: either a table or query name (without square brackets)
+&apos;&apos;&apos; or a full SQL commands where table and fieldnames are preferably surrounded with square brackets
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Implemented as a Sub because the doImport UNO method does not return any error
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; BASEDOCUMENTOPENERROR The database file could not be opened
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.ImportFromDatabase(&quot;C:\Temp\myDbFile.odb&quot;, , &quot;SheetY.C5&quot;, &quot;SELECT * FROM [Employees] ORDER BY [LastName]&quot;)
+
+Dim oDBContext As Object &apos; com.sun.star.sdb.DatabaseContext
+Dim oDatabase As Object &apos; SFDatabases.Database service
+Dim lCommandType As Long &apos; A com.sun.star.sheet.DataImportMode.xxx constant
+Dim oQuery As Object &apos; com.sun.star.ucb.XContent
+Dim bDirect As Boolean &apos; Alias of DirectSQL
+Dim oDestRange As Object &apos; Destination as a range
+Dim oDestAddress As Object &apos; com.sun.star.table.CellRangeAddress
+Dim oDestCell As Object &apos; com.sun.star.table.XCell
+Dim oSelect As Object &apos; Current selection in destination
+Dim vImportOptions As Variant &apos; Array of PropertyValues
+
+Const cstThisSub = &quot;SFDocuments.Calc.ImportFromDatabase&quot;
+Const cstSubArgs = &quot;[FileName=&quot;&quot;&quot;&quot;], [RegistrationName=&quot;&quot;&quot;&quot;], DestinationCell, SQLCommand, [DirectSQL=False]&quot;
+
+&apos; If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+
+ If IsMissing(FileName) Or IsEmpty(FileName) Then FileName = &quot;&quot;
+ If IsMissing(RegistrationName) Or IsEmpty(RegistrationName) Then RegistrationName = &quot;&quot;
+ If IsMissing(DirectSQL) Or IsEmpty(DirectSQL) Then DirectSQL = False
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._ValidateFile(FileName, &quot;FileName&quot;, , True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(DestinationCell, &quot;DestinationCell&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SQLCommand, &quot;SQLCommand&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(DirectSQL, &quot;DirectSQL&quot;, ScriptForge.V_BOOLEAN) Then GoTo Finally
+ End If
+
+ &apos; Check the existence of FileName
+ If Len(FileName) = 0 Then &apos; FileName has precedence over RegistrationName
+ If Len(RegistrationName) = 0 Then GoTo CatchError
+ Set oDBContext = ScriptForge.SF_Utils._GetUNOService(&quot;DatabaseContext&quot;)
+ If Not oDBContext.hasRegisteredDatabase(RegistrationName) Then GoTo CatchError
+ FileName = ScriptForge.SF_FileSystem._ConvertFromUrl(oDBContext.getDatabaseLocation(RegistrationName))
+ End If
+ If Not ScriptForge.SF_FileSystem.FileExists(FileName) Then GoTo CatchError
+
+Try:
+ &apos; Check command type
+ Set oDatabase = ScriptForge.SF_Services.CreateScriptService(&quot;SFDatabases.Database&quot;, FileName, , True) &apos; Read-only
+ If IsNull(oDatabase) Then GoTo CatchError
+ With oDatabase
+ If ScriptForge.SF_Array.Contains(.Tables, SQLCommand) Then
+ bDirect = True
+ lCommandType = com.sun.star.sheet.DataImportMode.TABLE
+ ElseIf ScriptForge.SF_Array.Contains(.Queries, SQLCommand) Then
+ Set oQuery = .XConnection.Queries.getByName(SQLCommand)
+ bDirect = Not oQuery.EscapeProcessing
+ lCommandType = com.sun.star.sheet.DataImportMode.QUERY
+ Else
+ bDirect = DirectSQL
+ lCommandType = com.sun.star.sheet.DataImportMode.SQL
+ SQLCommand = ._ReplaceSquareBrackets(SQLCommand)
+ End If
+ .CloseDatabase()
+ Set oDatabase = oDatabase.Dispose()
+ End With
+
+ &apos; Determine the destination cell as the top-left coordinates of the given range
+ Set oDestRange = _ParseAddress(DestinationCell)
+ Set oDestAddress = oDestRange.XCellRange.RangeAddress
+ Set oDestCell = oDestRange.XSpreadsheet.getCellByPosition(oDestAddress.StartColumn, oDestAddress.StartRow)
+
+ &apos; Remember current selection
+ Set oSelect = _Component.CurrentController.getSelection()
+ &apos; Import arguments
+ vImportOptions = Array(_
+ ScriptForge.SF_Utils._MakePropertyValue(&quot;DatabaseName&quot;, ScriptForge.SF_FileSystem._ConvertToUrl(FileName)) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;SourceObject&quot;, SQLCommand) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;SourceType&quot;, lCommandType) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;IsNative&quot;, bDirect) _
+ )
+ oDestCell.doImport(vImportOptions)
+ &apos; Restore selection after import_
+ _RestoreSelections(_Component, oSelect)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+CatchError:
+ SF_Exception.RaiseFatal(BASEDOCUMENTOPENERROR, &quot;FileName&quot;, FileName, &quot;RegistrationName&quot;, RegistrationName)
+ GoTo Finally
+End Sub &apos; SFDocuments.SF_Calc.ImportFromDatabase
+
+REM -----------------------------------------------------------------------------
+Public Function InsertSheet(Optional ByVal SheetName As Variant _
+ , Optional ByVal BeforeSheet As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Insert a new empty sheet before an existing sheet or at the end of the list of sheets
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SheetName: The name of the new sheet
+&apos;&apos;&apos; BeforeSheet: The name (string) or index (numeric, starting from 1) of the sheet before which to insert
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the sheet could be inserted successfully
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.InsertSheet(&quot;SheetX&quot;, &quot;SheetY&quot;)
+
+Dim bInsert As Boolean &apos; Return value
+Dim vSheets As Variant &apos; List of existing sheets
+Dim lSheetIndex As Long &apos; Index of a sheet
+Const cstThisSub = &quot;SFDocuments.Calc.InsertSheet&quot;
+Const cstSubArgs = &quot;SheetName, [BeforeSheet=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bInsert = False
+
+Check:
+ If IsMissing(BeforeSheet) Or IsEmpty(BeforeSheet) Then BeforeSheet = 32768
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, True) Then GoTo Finally
+ If Not _ValidateSheet(BeforeSheet, &quot;BeforeSheet&quot;, , True, , True) Then GoTo Finally
+ End If
+ vSheets = _Component.getSheets.getElementNames()
+
+Try:
+ If VarType(BeforeSheet) = V_STRING Then
+ lSheetIndex = ScriptForge.SF_Array.IndexOf(vSheets, BeforeSheet)
+ Else
+ lSheetIndex = BeforeSheet - 1
+ If lSheetIndex &lt; 0 Then lSheetIndex = 0
+ If lSheetIndex &gt; UBound(vSheets) Then lSheetIndex = UBound(vSheets) + 1
+ End If
+ _Component.getSheets.insertNewByName(SheetName, lSheetIndex)
+ bInsert = True
+
+Finally:
+ InsertSheet = binsert
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.InsertSheet
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Model service as an array
+
+ Methods = Array( _
+ &quot;Activate&quot; _
+ , &quot;ClearAll&quot; _
+ , &quot;ClearFormats&quot; _
+ , &quot;ClearValues&quot; _
+ , &quot;CloseDocument&quot; _
+ , &quot;CopySheet&quot; _
+ , &quot;CopySheetFromFile&quot; _
+ , &quot;CopyToCell&quot; _
+ , &quot;CopyToRange&quot; _
+ , &quot;DAvg&quot; _
+ , &quot;DCount&quot; _
+ , &quot;DMax&quot; _
+ , &quot;DMin&quot; _
+ , &quot;DSum&quot; _
+ , &quot;GetColumnName&quot; _
+ , &quot;GetFormula&quot; _
+ , &quot;GetValue&quot; _
+ , &quot;ImportFromCSVFile&quot; _
+ , &quot;ImportFromDatabase&quot; _
+ , &quot;InsertSheet&quot; _
+ , &quot;MoveRange&quot; _
+ , &quot;MoveSheet&quot; _
+ , &quot;Offset&quot; _
+ , &quot;RemoveSheet&quot; _
+ , &quot;RenameSheet&quot; _
+ , &quot;RunCommand&quot; _
+ , &quot;Save&quot; _
+ , &quot;SaveAs&quot; _
+ , &quot;SaveCopyAs&quot; _
+ , &quot;SetArray&quot; _
+ , &quot;SetCellStyle&quot; _
+ , &quot;SetFormula&quot; _
+ , &quot;SetValue&quot; _
+ , &quot;SortRange&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Calc.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function MoveRange(Optional ByVal Source As Variant _
+ , Optional ByVal Destination As Variant _
+ ) As String
+&apos;&apos;&apos; Move a specified source range to a destination range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Source: the source range of cells as a string
+&apos;&apos;&apos; Destination: the destination of the moved range of cells, as a string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the modified range of cells
+&apos;&apos;&apos; The modified area depends only on the size of the source area
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.MoveRange(&quot;SheetX.A1:F10&quot;, &quot;SheetY.C5&quot;)
+
+Dim sMove As String &apos; Return value
+Dim oSource As Object &apos; Alias of Source to avoid &quot;Object variable not set&quot; run-time error
+Dim oSourceAddress As Object &apos; com.sun.star.table.CellRangeAddress
+Dim oDestRange As Object &apos; Destination as a range
+Dim oDestAddress As Object &apos; com.sun.star.table.CellRangeAddress
+Dim oDestCell As Object &apos; com.sun.star.table.CellAddress
+Dim oSelect As Object &apos; Current selection in source
+Dim oClipboard As Object &apos; com.sun.star.datatransfer.XTransferable
+Dim oCellRanges As Object &apos; com.sun.star.sheet.SheetCellRanges
+Dim vRangeAddresses As Variant &apos; Array of com.sun.star.table.CellRangeAddress
+Dim i As Long
+
+Const cstThisSub = &quot;SFDocuments.Calc.MoveRange&quot;
+Const cstSubArgs = &quot;Source, Destination&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sMove = &quot;&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not _Validate(Source, &quot;Source&quot;, V_STRING) Then GoTo Finally
+ If Not _Validate(Destination, &quot;Destination&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oSourceAddress = _ParseAddress(Source).XCellRange.RangeAddress
+ Set oDestRange = _ParseAddress(Destination)
+ Set oDestAddress = oDestRange.XCellRange.RangeAddress
+ Set oDestCell = New com.sun.star.table.CellAddress
+ With oDestAddress
+ oDestCell.Sheet = .Sheet
+ oDestCell.Column = .StartColumn
+ oDestCell.Row = .StartRow
+ End With
+ oDestRange.XSpreadsheet.moveRange(oDestCell, oSourceAddress)
+
+ With oSourceAddress
+ sMove = _Offset(Destination, 0, 0, .EndRow - .StartRow + 1, .EndColumn - .StartColumn + 1).RangeName
+ End With
+
+Finally:
+ MoveRange = sMove
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.MoveRange
+
+REM -----------------------------------------------------------------------------
+Public Function MoveSheet(Optional ByVal SheetName As Variant _
+ , Optional ByVal BeforeSheet As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Move a sheet before an existing sheet or at the end of the list of sheets
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SheetName: The name of the sheet to move
+&apos;&apos;&apos; BeforeSheet: The name (string) or index (numeric, starting from 1) of the sheet before which to move the sheet
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the sheet could be moved successfully
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.MoveSheet(&quot;SheetX&quot;, &quot;SheetY&quot;)
+
+Dim bMove As Boolean &apos; Return value
+Dim vSheets As Variant &apos; List of existing sheets
+Dim lSheetIndex As Long &apos; Index of a sheet
+Const cstThisSub = &quot;SFDocuments.Calc.MoveSheet&quot;
+Const cstSubArgs = &quot;SheetName, [BeforeSheet=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bMove = False
+
+Check:
+ If IsMissing(BeforeSheet) Or IsEmpty(BeforeSheet) Then BeforeSheet = 32768
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
+ If Not _ValidateSheet(BeforeSheet, &quot;BeforeSheet&quot;, , True, , True) Then GoTo Finally
+ End If
+ vSheets = _Component.getSheets.getElementNames()
+
+Try:
+ If VarType(BeforeSheet) = V_STRING Then
+ lSheetIndex = ScriptForge.SF_Array.IndexOf(vSheets, BeforeSheet)
+ Else
+ lSheetIndex = BeforeSheet - 1
+ If lSheetIndex &lt; 0 Then lSheetIndex = 0
+ If lSheetIndex &gt; UBound(vSheets) Then lSheetIndex = UBound(vSheets) + 1
+ End If
+ _Component.getSheets.MoveByName(SheetName, lSheetIndex)
+ bMove = True
+
+Finally:
+ MoveSheet = bMove
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.MoveSheet
+
+REM -----------------------------------------------------------------------------
+Public Function Offset(Optional ByRef Range As Variant _
+ , Optional ByVal Rows As Variant _
+ , Optional ByVal Columns As Variant _
+ , Optional ByVal Height As Variant _
+ , Optional ByVal Width As Variant _
+ ) As String
+&apos;&apos;&apos; Returns a new range offset by a certain number of rows and columns from a given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the range, as a string, from which the function searches for the new range
+&apos;&apos;&apos; Rows : the number of rows by which the reference was corrected up (negative value) or down.
+&apos;&apos;&apos; Use 0 (default) to stay in the same row.
+&apos;&apos;&apos; Columns : the number of columns by which the reference was corrected to the left (negative value) or to the right.
+&apos;&apos;&apos; Use 0 (default) to stay in the same column
+&apos;&apos;&apos; Height : the vertical height for an area that starts at the new reference position.
+&apos;&apos;&apos; Default = no vertical resizing
+&apos;&apos;&apos; Width : the horizontal width for an area that starts at the new reference position.
+&apos;&apos;&apos; Default - no horizontal resizing
+&apos;&apos;&apos; Arguments Rows and Columns must not lead to zero or negative start row or column.
+&apos;&apos;&apos; Arguments Height and Width must not lead to zero or negative count of rows or columns.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A new range as a string
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; OFFSETADDRESSERROR The computed range of cells falls beyond the sheet boundaries
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.Offset(&quot;A1&quot;, 2, 2) &apos; &quot;&apos;SheetX&apos;.$C$3&quot; (A1 moved by two rows and two columns down)
+&apos;&apos;&apos; oDoc.Offset(&quot;A1&quot;, 2, 2, 5, 6) &apos; &quot;&apos;SheetX&apos;.$C$3:$H$7&quot;
+
+Dim sOffset As String &apos; Return value
+Dim oAddress As Object &apos; Alias of Range
+Const cstThisSub = &quot;SFDocuments.Calc.Offset&quot;
+Const cstSubArgs = &quot;Range, [Rows=0], [Columns=0], [Height], [Width]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sOffset = &quot;&quot;
+
+Check:
+ If IsMissing(Rows) Or IsEmpty(Rows) Then Rows = 0
+ If IsMissing(Columns) Or IsEmpty(Columns) Then Columns = 0
+ If IsMissing(Height) Or IsEmpty(Height) Then Height = 0
+ If IsMissing(Width) Or IsEmpty(Width) Then Width = 0
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Rows, &quot;Rows&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Columns, &quot;Columns&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Height, &quot;Height&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Width, &quot;Width&quot;, ScriptForge.V_NUMERIC) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Define the new range string
+ Set oAddress = _Offset(Range, Rows, Columns, Height, Width)
+ sOffset = oAddress.RangeName
+
+Finally:
+ Offset = sOffset
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.Offset
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Timer class as an array
+
+ Properties = Array( _
+ &quot;CurrentSelection&quot; _
+ , &quot;CustomProperties&quot; _
+ , &quot;Description&quot; _
+ , &quot;DocumentProperties&quot; _
+ , &quot;DocumentType&quot; _
+ , &quot;Height&quot; _
+ , &quot;IsBase&quot; _
+ , &quot;IsCalc&quot; _
+ , &quot;IsDraw &quot; _
+ , &quot;IsImpress&quot; _
+ , &quot;IsMath&quot; _
+ , &quot;IsWriter&quot; _
+ , &quot;Keywords&quot; _
+ , &quot;LastCell&quot; _
+ , &quot;LastColumn&quot; _
+ , &quot;LastRow&quot; _
+ , &quot;Range&quot; _
+ , &quot;Readonly&quot; _
+ , &quot;Sheet&quot; _
+ , &quot;Sheets&quot; _
+ , &quot;Subject&quot; _
+ , &quot;Title&quot; _
+ , &quot;Width&quot; _
+ , &quot;XCellRange&quot; _
+ , &quot;XComponent&quot; _
+ , &quot;XSpreadsheet&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Calc.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function RemoveSheet(Optional ByVal SheetName As Variant) As Boolean
+&apos;&apos;&apos; Remove an existing sheet from the document
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SheetName: The name of the sheet to remove
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the sheet could be removed successfully
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.RemoveSheet(&quot;SheetX&quot;)
+
+Dim bRemove As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDocuments.Calc.RemoveSheet&quot;
+Const cstSubArgs = &quot;SheetName&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bRemove = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
+ End If
+
+Try:
+ _Component.getSheets.RemoveByName(SheetName)
+ bRemove = True
+
+Finally:
+ RemoveSheet = bRemove
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.RemoveSheet
+
+REM -----------------------------------------------------------------------------
+Public Function RenameSheet(Optional ByVal SheetName As Variant _
+ , Optional ByVal NewName As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Rename a specified sheet
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SheetName: The name of the sheet to rename
+&apos;&apos;&apos; NewName: Must not exist
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the sheet could be renamed successfully
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DUPLICATESHEETERROR A sheet with the given name exists already
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.RenameSheet(&quot;SheetX&quot;, &quot;SheetY&quot;)
+
+Dim bRename As Boolean &apos; Return value
+Const cstThisSub = &quot;SFDocuments.Calc.RenameSheet&quot;
+Const cstSubArgs = &quot;SheetName, NewName&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bRename = False
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive(True) Then GoTo Finally
+ If Not _ValidateSheet(SheetName, &quot;SheetName&quot;, , True) Then GoTo Finally
+ If Not _ValidateSheet(NewName, &quot;NewName&quot;, True) Then GoTo Finally
+ End If
+
+Try:
+ _Component.getSheets.getByName(SheetName).setName(NewName)
+ bRename = True
+
+Finally:
+ RenameSheet = bRename
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc.RenameSheet
+
+REM -----------------------------------------------------------------------------
+Public Function SetArray(Optional ByVal TargetCell As Variant _
+ , Optional ByRef Value As Variant _
+ ) As String
+&apos;&apos;&apos; Set the given (array of) values starting from the target cell
+&apos;&apos;&apos; The updated area expands itself from the target cell or from the top-left corner of the given range
+&apos;&apos;&apos; as far as determined by the size of the input Value.
+&apos;&apos;&apos; Vectors are always expanded vertically
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; TargetCell : the cell or the range as a string that should receive a new value
+&apos;&apos;&apos; Value: a scalar, a vector or an array with the new values
+&apos;&apos;&apos; The new values should be strings, numeric values or dates. Other types empty the corresponding cell
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the updated range
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; OFFSETADDRESSERROR The computed range of cells falls beyond the sheet boundaries
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.SetArray(&quot;SheetX.A1&quot;, SF_Array.RangeInit(1, 1000))
+
+Dim sSet As String &apos; Return value
+Dim oSet As Object &apos; _Address alias of sSet
+Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
+Const cstThisSub = &quot;SFDocuments.Calc.SetArray&quot;
+Const cstSubArgs = &quot;TargetCell, Value&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sSet = &quot;&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(TargetCell, &quot;TargetCell&quot;, V_STRING) Then GoTo Finally
+ If IsArray(Value) Then
+ If Not ScriptForge.SF_Utils._ValidateArray(Value, &quot;Value&quot;) Then GoTo Finally
+ Else
+ If Not ScriptForge.SF_Utils._Validate(Value, &quot;Value&quot;) Then GoTo Finally
+ End If
+ End If
+
+Try:
+ &apos; Convert argument to data array and derive new range from its size
+ vDataArray = _ConvertToDataArray(Value)
+ If UBound(vDataArray) &lt; LBound(vDataArray) Then GoTo Finally
+ Set oSet = _Offset(TargetCell, 0, 0, plHeight := UBound(vDataArray) + 1, plWidth := UBound(vDataArray(0)) + 1) &apos; +1 : vDataArray is zero-based
+ With oSet
+ .XCellRange.setDataArray(vDataArray)
+ sSet = .RangeName
+ End With
+
+Finally:
+ SetArray = sSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.SetArray
+
+REM -----------------------------------------------------------------------------
+Public Function SetCellStyle(Optional ByVal TargetRange As Variant _
+ , Optional ByVal Style As Variant _
+ ) As String
+&apos;&apos;&apos; Apply the given cell style in the given range
+&apos;&apos;&apos; The full range is updated and the remainder of the sheet is left untouched
+&apos;&apos;&apos; If the cell style does not exist, an error is raised
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; TargetRange : the range as a string that should receive a new cell style
+&apos;&apos;&apos; Style: the style name as a string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the updated range
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.SetCellStyle(&quot;A1:F1&quot;, &quot;Heading 2&quot;)
+
+Dim sSet As String &apos; Return value
+Dim oAddress As _Address &apos; Alias of TargetRange
+Dim oStyleFamilies As Object &apos; com.sun.star.container.XNameAccess
+Dim vStyles As Variant &apos; Array of existing cell styles
+Const cstStyle = &quot;CellStyles&quot;
+Const cstThisSub = &quot;SFDocuments.Calc.SetCellStyle&quot;
+Const cstSubArgs = &quot;TargetRange, Style&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sSet = &quot;&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(TargetRange, &quot;TargetRange&quot;, V_STRING) Then GoTo Finally
+ Set oStyleFamilies = _Component.StyleFamilies
+ If oStyleFamilies.hasByName(cstStyle) Then vStyles = oStyleFamilies.getByName(cstStyle).getElementNames() Else vStyles = Array()
+ If Not ScriptForge.SF_Utils._Validate(Style, &quot;Style&quot;, V_STRING, vStyles) Then GoTo Finally
+ End If
+
+Try:
+ Set oAddress = _ParseAddress(TargetRange)
+ With oAddress
+ .XCellRange.CellStyle = Style
+ sSet = .RangeName
+ End With
+
+Finally:
+ SetCellStyle = sSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.SetCellStyle
+
+REM -----------------------------------------------------------------------------
+Public Function SetFormula(Optional ByVal TargetRange As Variant _
+ , Optional ByRef Formula As Variant _
+ ) As String
+&apos;&apos;&apos; Set the given (array of) formulae in the given range
+&apos;&apos;&apos; The full range is updated and the remainder of the sheet is left untouched
+&apos;&apos;&apos; If the given formula is a string:
+&apos;&apos;&apos; the unique formula is pasted across the whole range with adjustment of the relative references
+&apos;&apos;&apos; Otherwise
+&apos;&apos;&apos; If the size of Formula &lt; the size of Range, then the other cells are emptied
+&apos;&apos;&apos; If the size of Formula &gt; the size of Range, then Formula is only partially copied
+&apos;&apos;&apos; Vectors are always expanded vertically, except if the range has a height of exactly 1 row
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; TargetRange : the range as a string that should receive a new Formula
+&apos;&apos;&apos; Formula: a scalar, a vector or an array with the new formula(e) as strings for each cell of the range.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the updated range
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.SetFormula(&quot;A1&quot;, &quot;=A2&quot;)
+&apos;&apos;&apos; oDoc.SetFormula(&quot;A1:F1&quot;, Array(&quot;=A2&quot;, &quot;=B2&quot;, &quot;=C2+10&quot;)) &apos; Horizontal vector, partially empty
+&apos;&apos;&apos; oDoc.SetFormula(&quot;A1:D2&quot;, &quot;=E1&quot;) &apos; D2 contains the formula &quot;=H2&quot;
+
+Dim sSet As String &apos; Return value
+Dim oAddress As Object &apos; Alias of TargetRange
+Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
+Const cstThisSub = &quot;SFDocuments.Calc.SetFormula&quot;
+Const cstSubArgs = &quot;TargetRange, Formula&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sSet = &quot;&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(TargetRange, &quot;TargetRange&quot;, V_STRING) Then GoTo Finally
+ If IsArray(Formula) Then
+ If Not ScriptForge.SF_Utils._ValidateArray(Formula, &quot;Formula&quot;, 0, V_STRING) Then GoTo Finally
+ Else
+ If Not ScriptForge.SF_Utils._Validate(Formula, &quot;Formula&quot;, V_STRING) Then GoTo Finally
+ End If
+ End If
+
+Try:
+ Set oAddress = _ParseAddress(TargetRange)
+ With oAddress
+ If IsArray(Formula) Then
+ &apos; Convert to data array and limit its size to the size of the initial range
+ vDataArray = _ConvertToDataArray(Formula, .Height - 1, .Width - 1)
+ If UBound(vDataArray) &lt; LBound(vDataArray) Then GoTo Finally
+ .XCellRange.setFormulaArray(vDataArray)
+ Else
+ With .XCellRange
+ &apos; Store formula in top-left cell and paste it along the whole range
+ .getCellByPosition(0, 0).setFormula(Formula)
+ .fillSeries(com.sun.star.sheet.FillDirection.TO_BOTTOM, com.sun.star.sheet.FillMode.SIMPLE, 0, 0, 0)
+ .fillSeries(com.sun.star.sheet.FillDirection.TO_RIGHT, com.sun.star.sheet.FillMode.SIMPLE, 0, 0, 0)
+ End With
+ End If
+ sSet = .RangeName
+ End With
+
+Finally:
+ SetFormula = sSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.SetFormula
+
+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.Calc.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;CurrentSelection&quot;)
+ CurrentSelection = pvValue
+ 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_Calc.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function SetValue(Optional ByVal TargetRange As Variant _
+ , Optional ByRef Value As Variant _
+ ) As String
+&apos;&apos;&apos; Set the given value in the given range
+&apos;&apos;&apos; The full range is updated and the remainder of the sheet is left untouched
+&apos;&apos;&apos; If the size of Value &lt; the size of Range, then the other cells are emptied
+&apos;&apos;&apos; If the size of Value &gt; the size of Range, then Value is only partially copied
+&apos;&apos;&apos; Vectors are always expanded vertically, except if the range has a height of exactly 1 row
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; TargetRange : the range as a string that should receive a new value
+&apos;&apos;&apos; Value: a scalar, a vector or an array with the new values for each cell of the range.
+&apos;&apos;&apos; The new values should be strings, numeric values or dates. Other types empty the corresponding cell
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A string representing the updated range
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.SetValue(&quot;A1&quot;, 2)
+&apos;&apos;&apos; oDoc.SetValue(&quot;A1:F1&quot;, Array(1, 2, 3)) &apos; Horizontal vector, partially empty
+&apos;&apos;&apos; oDoc.SetValue(&quot;A1:D2&quot;, SF_Array.AppendRow(Array(1, 2, 3, 4), Array(5, 6, 7, 8)))
+
+Dim sSet As String &apos; Return value
+Dim oAddress As Object &apos; Alias of TargetRange
+Dim vDataArray As Variant &apos; DataArray compatible with .DataArray UNO property
+Const cstThisSub = &quot;SFDocuments.Calc.SetValue&quot;
+Const cstSubArgs = &quot;TargetRange, Value&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sSet = &quot;&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(TargetRange, &quot;TargetRange&quot;, V_STRING) Then GoTo Finally
+ If IsArray(Value) Then
+ If Not ScriptForge.SF_Utils._ValidateArray(Value, &quot;Value&quot;) Then GoTo Finally
+ Else
+ If Not ScriptForge.SF_Utils._Validate(Value, &quot;Value&quot;) Then GoTo Finally
+ End If
+ End If
+
+Try:
+ Set oAddress = _ParseAddress(TargetRange)
+ With oAddress
+ &apos; Convert to data array and limit its size to the size of the initial range
+ vDataArray = _ConvertToDataArray(Value, .Height - 1, .Width - 1)
+ If UBound(vDataArray) &lt; LBound(vDataArray) Then GoTo Finally
+ .XCellRange.setDataArray(vDataArray)
+ sSet = .RangeName
+ End With
+
+Finally:
+ SetValue = sSet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.SetValue
+
+REM -----------------------------------------------------------------------------
+Public Function SortRange(Optional ByVal Range As Variant _
+ , Optional ByVal SortKeys As Variant _
+ , Optional ByVal SortOrder As Variant _
+ , Optional ByVal DestinationCell As Variant _
+ , Optional ByVal ContainsHeader As Variant _
+ , Optional ByVal CaseSensitive As Variant _
+ , Optional ByVal SortColumns As Variant _
+ ) As Variant
+&apos;&apos;&apos; Sort the given range on maximum 3 columns/rows. The sorting order may vary by column/row
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range: the range to sort as a string
+&apos;&apos;&apos; SortKeys: a scalar (if 1 column/row) or an array of column/row numbers starting from 1
+&apos;&apos;&apos; SortOrder: a scalar or an array of strings: &quot;ASC&quot; or &quot;DESC&quot;
+&apos;&apos;&apos; Each item is paired with the corresponding item in SortKeys
+&apos;&apos;&apos; If the SortOrder array is shorter than SortKeys, the remaining keys are sorted
+&apos;&apos;&apos; in ascending order
+&apos;&apos;&apos; DestinationCell: the destination of the sorted range of cells, as a string
+&apos;&apos;&apos; If given as range, the destination will be reduced to its top-left cell
+&apos;&apos;&apos; By default, Range is overwritten with its sorted content
+&apos;&apos;&apos; ContainsHeader: when True, the first row/column is not sorted
+&apos;&apos;&apos; CaseSensitive: only for string comparisons, default = False
+&apos;&apos;&apos; SortColumns: when True, the columns are sorted from left to right
+&apos;&apos;&apos; Default = False: rows are sorted from top to bottom.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The modified range of cells as a string
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; oDoc.SortRange(&quot;A2:J200&quot;, Array(1, 3), , Array(&quot;ASC&quot;, &quot;DESC&quot;), CaseSensitive := True)
+&apos;&apos;&apos; &apos; Sort on columns A (ascending) and C (descending)
+
+Dim sSort As String &apos; Return value
+Dim oRangeAddress As _Address &apos; Parsed range
+Dim oRange As Object &apos; com.sun.star.table.XCellRange
+Dim oDestRange As Object &apos; Destination as a range
+Dim oDestAddress As Object &apos; com.sun.star.table.CellRangeAddress
+Dim oDestCell As Object &apos; com.sun.star.table.CellAddress
+Dim vSortDescriptor As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim vSortFields As Variant &apos; Array of com.sun.star.table.TableSortField
+Dim sOrder As String &apos; Item in SortOrder
+Dim i As Long
+Const cstThisSub = &quot;SFDocuments.Calc.SortRange&quot;
+Const cstSubArgs = &quot;Range, SortKeys, [TargetRange=&quot;&quot;&quot;&quot;], [SortOrder=&quot;&quot;ASC&quot;&quot;], [ContainsHeader=False], [CaseSensitive=False], [SortColumns=False]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sSort = &quot;&quot;
+
+Check:
+ If IsMissing(SortKeys) Or IsEmpty(SortKeys) Then
+ SortKeys = Array(1)
+ ElseIf Not IsArray(SortKeys) Then
+ SortKeys = Array(SortKeys)
+ End If
+ If IsMissing(DestinationCell) Or IsEmpty(DestinationCell) Then DestinationCell = &quot;&quot;
+ If IsMissing(SortOrder) Or IsEmpty(SortOrder) Then
+ SortOrder = Array(&quot;ASC&quot;)
+ ElseIf Not IsArray(SortOrder) Then
+ SortOrder = Array(SortOrder)
+ End If
+ If IsMissing(ContainsHeader) Or IsEmpty(ContainsHeader) Then ContainsHeader = False
+ If IsMissing(CaseSensitive) Or IsEmpty(CaseSensitive) Then CaseSensitive = False
+ If IsMissing(SortColumns) Or IsEmpty(SortColumns) Then SortColumns = False
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._ValidateArray(SortKeys, &quot;SortKeys&quot;, 1, V_NUMERIC, True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(DestinationCell, &quot;DestinationCell&quot;, V_STRING) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._ValidateArray(SortOrder, &quot;SortOrder&quot;, 1, V_STRING, True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(ContainsHeader, &quot;ContainsHeader&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(CaseSensitive, &quot;CaseSensitive&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SortColumns, &quot;SortColumns&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+ Set oRangeAddress = _ParseAddress(Range)
+ If Len(DestinationCell) &gt; 0 Then Set oDestRange = _ParseAddress(DestinationCell)
+
+Try:
+ &apos; Initialize the sort descriptor
+ Set oRange = oRangeAddress.XCellRange
+ vSortDescriptor = oRange.createSortDescriptor
+ ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;IsSortColumns&quot;, SortColumns)
+ ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;ContainsHeader&quot;, ContainsHeader)
+ ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;BindFormatsToContent&quot;, True)
+ If Len(DestinationCell) = 0 Then
+ ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;CopyOutputData&quot;, False)
+ Else
+ Set oDestAddress = oDestRange.XCellRange.RangeAddress
+ Set oDestCell = New com.sun.star.table.CellAddress
+ With oDestAddress
+ oDestCell.Sheet = .Sheet
+ oDestCell.Column = .StartColumn
+ oDestCell.Row = .StartRow
+ End With
+ ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;CopyOutputData&quot;, true)
+ ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;OutputPosition&quot;, oDestCell)
+ End If
+ ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;IsUserListEnabled&quot;, False)
+
+ &apos; Define the sorting keys
+ vSortFields = Array()
+ ReDim vSortFields(0 To UBound(SortKeys))
+ For i = 0 To UBound(SortKeys)
+ vSortFields(i) = New com.sun.star.table.TableSortField
+ If i &gt; UBound(SortOrder) Then sOrder = &quot;&quot; Else sOrder = SortOrder(i)
+ If Len(sOrder) = 0 Then sOrder = &quot;ASC&quot;
+ With vSortFields(i)
+ .Field = SortKeys(i) - 1
+ .IsAscending = ( UCase(sOrder) = &quot;ASC&quot; )
+ .IsCaseSensitive = CaseSensitive
+ End With
+ Next i
+
+ &apos; Associate the keys and the descriptor, and sort
+ ScriptForge.SF_Utils._SetPropertyValue(vSortDescriptor, &quot;SortFields&quot;, vSortFields)
+ oRange.sort(vSortDescriptor)
+
+ &apos; Compute the changed area
+ If Len(DestinationCell) = 0 Then
+ sSort = oRangeAddress.RangeName
+ Else
+ With oRangeAddress
+ sSort = _Offset(oDestRange, 0, 0, .Height, .Width).RangeName
+ End With
+ End If
+
+Finally:
+ SortRange = sSort
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc.SortRange
+
+REM ======================================================= SUPERCLASS PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get CustomProperties() As Variant
+ CustomProperties = [_Super].GetProperty(&quot;CustomProperties&quot;)
+End Property &apos; SFDocuments.SF_Calc.CustomProperties
+
+REM -----------------------------------------------------------------------------
+Property Let CustomProperties(Optional ByVal pvCustomProperties As Variant)
+ [_Super].CustomProperties = pvCustomProperties
+End Property &apos; SFDocuments.SF_Calc.CustomProperties
+
+REM -----------------------------------------------------------------------------
+Property Get Description() As Variant
+ Description = [_Super].GetProperty(&quot;Description&quot;)
+End Property &apos; SFDocuments.SF_Calc.Description
+
+REM -----------------------------------------------------------------------------
+Property Let Description(Optional ByVal pvDescription As Variant)
+ [_Super].Description = pvDescription
+End Property &apos; SFDocuments.SF_Calc.Description
+
+REM -----------------------------------------------------------------------------
+Property Get DocumentProperties() As Variant
+ DocumentProperties = [_Super].GetProperty(&quot;DocumentProperties&quot;)
+End Property &apos; SFDocuments.SF_Calc.DocumentProperties
+
+REM -----------------------------------------------------------------------------
+Property Get DocumentType() As String
+ DocumentType = [_Super].GetProperty(&quot;DocumentType&quot;)
+End Property &apos; SFDocuments.SF_Calc.DocumentType
+
+REM -----------------------------------------------------------------------------
+Property Get IsBase() As Boolean
+ IsBase = [_Super].GetProperty(&quot;IsBase&quot;)
+End Property &apos; SFDocuments.SF_Calc.IsBase
+
+REM -----------------------------------------------------------------------------
+Property Get IsCalc() As Boolean
+ IsCalc = [_Super].GetProperty(&quot;IsCalc&quot;)
+End Property &apos; SFDocuments.SF_Calc.IsCalc
+
+REM -----------------------------------------------------------------------------
+Property Get IsDraw() As Boolean
+ IsDraw = [_Super].GetProperty(&quot;IsDraw&quot;)
+End Property &apos; SFDocuments.SF_Calc.IsDraw
+
+REM -----------------------------------------------------------------------------
+Property Get IsImpress() As Boolean
+ IsImpress = [_Super].GetProperty(&quot;IsImpress&quot;)
+End Property &apos; SFDocuments.SF_Calc.IsImpress
+
+REM -----------------------------------------------------------------------------
+Property Get IsMath() As Boolean
+ IsMath = [_Super].GetProperty(&quot;IsMath&quot;)
+End Property &apos; SFDocuments.SF_Calc.IsMath
+
+REM -----------------------------------------------------------------------------
+Property Get IsWriter() As Boolean
+ IsWriter = [_Super].GetProperty(&quot;IsWriter&quot;)
+End Property &apos; SFDocuments.SF_Calc.IsWriter
+
+REM -----------------------------------------------------------------------------
+Property Get Keywords() As Variant
+ Keywords = [_Super].GetProperty(&quot;Keywords&quot;)
+End Property &apos; SFDocuments.SF_Calc.Keywords
+
+REM -----------------------------------------------------------------------------
+Property Let Keywords(Optional ByVal pvKeywords As Variant)
+ [_Super].Keywords = pvKeywords
+End Property &apos; SFDocuments.SF_Calc.Keywords
+
+REM -----------------------------------------------------------------------------
+Property Get Readonly() As Variant
+ Readonly = [_Super].GetProperty(&quot;Readonly&quot;)
+End Property &apos; SFDocuments.SF_Calc.Readonly
+
+REM -----------------------------------------------------------------------------
+Property Get Subject() As Variant
+ Subject = [_Super].GetProperty(&quot;Subject&quot;)
+End Property &apos; SFDocuments.SF_Calc.Subject
+
+REM -----------------------------------------------------------------------------
+Property Let Subject(Optional ByVal pvSubject As Variant)
+ [_Super].Subject = pvSubject
+End Property &apos; SFDocuments.SF_Calc.Subject
+
+REM -----------------------------------------------------------------------------
+Property Get Title() As Variant
+ Title = [_Super].GetProperty(&quot;Title&quot;)
+End Property &apos; SFDocuments.SF_Calc.Title
+
+REM -----------------------------------------------------------------------------
+Property Let Title(Optional ByVal pvTitle As Variant)
+ [_Super].Title = pvTitle
+End Property &apos; SFDocuments.SF_Calc.Title
+
+REM -----------------------------------------------------------------------------
+Property Get XComponent() As Variant
+ XComponent = [_Super].GetProperty(&quot;XComponent&quot;)
+End Property &apos; SFDocuments.SF_Calc.XComponent
+
+REM ========================================================== SUPERCLASS METHODS
+
+REM -----------------------------------------------------------------------------
+&apos;Public Function Activate() As Boolean
+&apos; Activate = [_Super].Activate()
+&apos;End Function &apos; SFDocuments.SF_Calc.Activate
+
+REM -----------------------------------------------------------------------------
+Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
+ CloseDocument = [_Super].CloseDocument(SaveAsk)
+End Function &apos; SFDocuments.SF_Calc.CloseDocument
+
+REM -----------------------------------------------------------------------------
+Public Sub RunCommand(Optional ByVal Command As Variant)
+ [_Super].RunCommand(Command)
+End Sub &apos; SFDocuments.SF_Calc.RunCommand
+
+REM -----------------------------------------------------------------------------
+Public Function Save() As Boolean
+ Save = [_Super].Save()
+End Function &apos; SFDocuments.SF_Calc.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_Calc.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_Calc.SaveCopyAs
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Function _ConvertFromDataArray(ByRef pvDataArray As Variant) As Variant
+&apos;&apos;&apos; Convert a data array to a scalar, a vector or a 2D array
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvDataArray: an array as returned by the XCellRange.getDatArray or .getFormulaArray methods
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A scalar, a zero-based 1D array or a zero-based 2D array of strings and/or doubles
+&apos;&apos;&apos; To convert doubles to dates, use the CDate builtin function
+
+Dim vArray As Variant &apos; Return value
+Dim lMax1 As Long &apos; UBound of pvDataArray
+Dim lMax2 As Long &apos; UBound of pvDataArray items
+Dim i As Long
+Dim j As Long
+
+ vArray = Empty
+
+Try:
+ &apos; Convert the data array to scalar, vector or array
+ lMax1 = UBound(pvDataArray)
+ If lMax1 &gt;= 0 Then
+ lMax2 = UBound(pvDataArray(0))
+ If lMax2 &gt;= 0 Then
+ If lMax1 + lMax2 &gt; 0 Then vArray = Array()
+ Select Case True
+ Case lMax1 = 0 And lMax2 = 0 &apos; Scalar
+ vArray = pvDataArray(0)(0)
+ Case lMax1 &gt; 0 And lMax2 = 0 &apos; Vertical vector
+ ReDim vArray(0 To lMax1)
+ For i = 0 To lMax1
+ vArray(i) = pvDataArray(i)(0)
+ Next i
+ Case lMax1 = 0 And lMax2 &gt; 0 &apos; Horizontal vector
+ ReDim vArray(0 To lMax2)
+ For j = 0 To lMax2
+ vArray(j) = pvDataArray(0)(j)
+ Next j
+ Case Else &apos; Array
+ ReDim vArray(0 To lMax1, 0 To lMax2)
+ For i = 0 To lMax1
+ For j = 0 To lMax2
+ vArray(i, j) = pvDataArray(i)(j)
+ Next j
+ Next i
+ End Select
+ End If
+ End If
+
+Finally:
+ _ConvertFromDataArray = vArray
+End Function &apos; SF_Documents.SF_Calc._ConvertFromDataArray
+
+REM -----------------------------------------------------------------------------
+Private Function _ConvertToCellValue(ByVal pvItem As Variant) As Variant
+&apos;&apos;&apos; Convert the argument to a valid Calc cell content
+
+Dim vCell As Variant &apos; Return value
+
+Try:
+ Select Case ScriptForge.SF_Utils._VarTypeExt(pvItem)
+ Case V_STRING : vCell = pvItem
+ Case V_DATE : vCell = CDbl(pvItem)
+ Case ScriptForge.V_NUMERIC : vCell = CDbl(pvItem)
+ Case ScriptForge.V_BOOLEAN : vCell = CDbl(Iif(pvItem, 1, 0))
+ Case Else : vCell = &quot;&quot;
+ End Select
+
+Finally:
+ _ConvertToCellValue = vCell
+ Exit Function
+End Function &apos; SF_Documents.SF_Calc._ConvertToCellValue
+
+REM -----------------------------------------------------------------------------
+Private Function _ConvertToDataArray(ByRef pvArray As Variant _
+ , Optional ByVal plRows As Long _
+ , Optional ByVal plColumns As Long _
+ ) As Variant
+&apos;&apos;&apos; Create a 2-dimensions nested array (compatible with the ranges .DataArray property)
+&apos;&apos;&apos; from a scalar, a 1D array or a 2D array
+&apos;&apos;&apos; Array items are converted to (possibly empty) strings or doubles
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvArray: the input scalar or array. If array, must be 1 or 2D otherwise it is ignored.
+&apos;&apos;&apos; plRows, plColumns: the upper bounds of the data array
+&apos;&apos;&apos; If bigger than input array, fill with zero-length strings
+&apos;&apos;&apos; If smaller than input array, truncate
+&apos;&apos;&apos; If plRows = 0 and the input array is a vector, the data array is aligned horizontally
+&apos;&apos;&apos; They are either both present or both absent
+&apos;&apos;&apos; When absent
+&apos;&apos;&apos; The size of the output is fully determined by the input array
+&apos;&apos;&apos; Vectors are aligned vertically
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A data array compatible with ranges .DataArray property
+&apos;&apos;&apos; The output is always an array of nested arrays
+
+Dim vDataArray() As Variant &apos; Return value
+Dim vVector() As Variant &apos; A temporary 1D array
+Dim vItem As Variant &apos; A single input item
+Dim iDims As Integer &apos; Number of dimensions of the input argument
+Dim lMin1 As Long &apos; Lower bound of input array
+Dim lMax1 As Long &apos; Upper bound
+Dim lMin2 As Long &apos; Lower bound
+Dim lMax2 As Long &apos; Upper bound
+Dim lRows As Long &apos; Upper bound of vDataArray
+Dim lCols As Long &apos; Upper bound of vVector
+Dim bHorizontal As Boolean &apos; Horizontal vector
+Dim i As Long
+Dim j As Long
+
+Const cstEmpty = &quot;&quot; &apos; Empty cell
+
+ If IsMissing(plRows) Or IsEmpty(plRows) Then plRows = -1
+ If IsMissing(plColumns) Or IsEmpty(plColumns) Then plColumns = -1
+
+ vDataArray = Array()
+
+Try:
+ &apos; Check the input argument and know its boundaries
+ iDims = ScriptForge.SF_Array.CountDims(pvArray)
+ If iDims = 0 Or iDims &gt; 2 Then Exit Function
+ lMin1 = 0 : lMax1 = 0 &apos; Default values
+ lMin2 = 0 : lMax2 = 0
+ Select Case iDims
+ Case -1 &apos; Scalar value
+ Case 1
+ bHorizontal = ( plRows = 0 And plColumns &gt; 0)
+ If Not bHorizontal Then
+ lMin1 = LBound(pvArray) : lMax1 = UBound(pvArray)
+ Else
+ lMin2 = LBound(pvArray) : lMax2 = UBound(pvArray)
+ End If
+ Case 2
+ lMin1 = LBound(pvArray, 1) : lMax1 = UBound(pvArray, 1)
+ lMin2 = LBound(pvArray, 2) : lMax2 = UBound(pvArray, 2)
+ End Select
+
+ &apos; Set the output dimensions accordingly
+ If plRows &gt;= 0 Then &apos; Dimensions of output are imposed
+ lRows = plRows
+ lCols = plColumns
+ Else &apos; Dimensions of output determined by input argument
+ lRows = 0 : lCols = 0 &apos; Default values
+ Select Case iDims
+ Case -1 &apos; Scalar value
+ Case 1 &apos; Vectors are aligned vertically
+ lRows = lMax1 - lMin1
+ Case 2
+ lRows = lMax1 - lMin1
+ lCols = lMax2 - lMin2
+ End Select
+ End If
+ ReDim vDataArray(0 To lRows)
+
+ &apos; Feed the output array row by row, each row being a vector
+ For i = 0 To lRows
+ ReDim vVector(0 To lCols)
+ For j = 0 To lCols
+ If i &gt; lMax1 - lMin1 Then
+ vVector(j) = cstEmpty
+ ElseIf j &gt; lMax2 - lMin2 Then
+ vVector(j) = cstEmpty
+ Else
+ Select Case iDims
+ Case -1 : vItem = _ConvertToCellValue(pvArray)
+ Case 1
+ If bHorizontal Then
+ vItem = _ConvertToCellValue(pvArray(j + lMin2))
+ Else
+ vItem = _ConvertToCellValue(pvArray(i + lMin1))
+ End If
+ Case 2
+ vItem = _ConvertToCellValue(pvArray(i + lMin1, j + lMin2))
+ End Select
+ vVector(j) = vItem
+ End If
+ vDataArray(i) = vVector
+ Next j
+ Next i
+
+Finally:
+ _ConvertToDataArray = vDataArray
+ Exit Function
+End Function &apos; SF_Documents.SF_Calc._ConvertToDataArray
+
+REM -----------------------------------------------------------------------------
+Private Function _DFunction(ByVal psFunction As String _
+ , Optional ByVal Range As Variant _
+ ) As Double
+&apos;&apos;&apos; Apply the given function on all the numeric values stored in the given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Range : the range as a string where to apply the function on
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The resulting value as a double
+
+Dim dblGet As Double &apos; Return value
+Dim oAddress As Object &apos; Alias of Range
+Dim vFunction As Variant &apos; com.sun.star.sheet.GeneralFunction.XXX
+Dim cstThisSub As String : cstThisSub = &quot;SFDocuments.Calc.&quot; &amp; psFunction
+Const cstSubArgs = &quot;Range&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ dblGet = 0
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Range, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Get the data
+ Set oAddress = _ParseAddress(Range)
+ Select Case psFunction
+ Case &quot;DAvg&quot; : vFunction = com.sun.star.sheet.GeneralFunction.AVERAGE
+ Case &quot;DCount&quot; : vFunction = com.sun.star.sheet.GeneralFunction.COUNTNUMS
+ Case &quot;DMax&quot; : vFunction = com.sun.star.sheet.GeneralFunction.MAX
+ Case &quot;DMin&quot; : vFunction = com.sun.star.sheet.GeneralFunction.MIN
+ Case &quot;DSum&quot; : vFunction = com.sun.star.sheet.GeneralFunction.SUM
+ Case Else : GoTo Finally
+ End Select
+ dblGet = oAddress.XCellRange.computeFunction(vFunction)
+
+Finally:
+ _DFunction = dblGet
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc._DFunction
+
+REM -----------------------------------------------------------------------------
+Function _GetColumnName(ByVal plColumnNumber As Long) As String
+&apos;&apos;&apos; Convert a column number (range 1, 2,..1024) into its letter counterpart (range &apos;A&apos;, &apos;B&apos;,..&apos;AMJ&apos;).
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; ColumnNumber: the column number, must be in the interval 1 ... 1024
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; a string representation of the column name, in range &apos;A&apos;..&apos;AMJ&apos;
+&apos;&apos;&apos; Adapted from a Python function by sundar nataraj
+&apos;&apos;&apos; http://stackoverflow.com/questions/23861680/convert-spreadsheet-number-to-column-letter
+
+Dim sCol As String &apos; Return value
+Dim lDiv As Long &apos; Intermediate result
+Dim lMod As Long &apos; Result of modulo 26 operation
+
+Try:
+ lDiv = plColumnNumber
+ Do While lDiv &gt; 0
+ lMod = (lDiv - 1) Mod 26
+ sCol = Chr(65 + lMod) + sCol
+ lDiv = Int((lDiv - lMod)/26)
+ Loop
+
+Finally:
+ _GetColumnName = sCol
+End Function &apos; SFDocuments.SF_Calc._GetColumnName
+
+REM -----------------------------------------------------------------------------
+Private Function _LastCell(ByRef poSheet As Object) As Variant
+&apos;&apos;&apos; Returns in an array the coordinates of the last used cell in the given sheet
+
+Dim oCursor As Object &apos; Cursor on the cell
+Dim oRange As Object &apos; The used range
+Dim vCoordinates(0 To 1) As Long &apos; Return value: (0) = Column, (1) = Row
+
+Try:
+ Set oCursor = poSheet.createCursorByRange(poSheet.getCellRangeByName(&quot;A1&quot;))
+ oCursor.gotoEndOfUsedArea(True)
+ Set oRange = poSheet.getCellRangeByName(oCursor.AbsoluteName)
+
+ vCoordinates(0) = oRange.RangeAddress.EndColumn + 1
+ vCoordinates(1) = oRange.RangeAddress.EndRow + 1
+
+Finally:
+ _LastCell = vCoordinates
+End Function &apos; SFDocuments.SF_Calc._LastCell
+
+REM -----------------------------------------------------------------------------
+Public Function _Offset(ByRef pvRange As Variant _
+ , ByVal plRows As Long _
+ , ByVal plColumns As Long _
+ , ByVal plHeight As Long _
+ , ByVal plWidth As Long _
+ ) As Object
+&apos;&apos;&apos; Returns a new range offset by a certain number of rows and columns from a given range
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvRange : the range, as a string or an object, from which the function searches for the new range
+&apos;&apos;&apos; plRows : the number of rows by which the reference was corrected up (negative value) or down.
+&apos;&apos;&apos; plColumns : the number of columns by which the reference was corrected to the left (negative value) or to the right.
+&apos;&apos;&apos; plHeight : the vertical height for an area that starts at the new reference position.
+&apos;&apos;&apos; plWidth : the horizontal width for an area that starts at the new reference position.
+&apos;&apos;&apos; Arguments Rows and Columns must not lead to zero or negative start row or column.
+&apos;&apos;&apos; Arguments Height and Width must not lead to zero or negative count of rows or columns.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A new range as object of type _Address
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; OFFSETADDRESSERROR The computed range of cells falls beyond the sheet boundaries
+
+Dim oOffset As Object &apos; Return value
+Dim oAddress As Object &apos; Alias of Range
+Dim oSheet As Object &apos; com.sun.star.sheet.XSpreadsheet
+Dim oRange As Object &apos; com.sun.star.table.XCellRange
+Dim oNewRange As Object &apos; com.sun.star.table.XCellRange
+Dim lLeft As Long &apos; New range coordinates
+Dim lTop As Long
+Dim lRight As Long
+Dim lBottom As Long
+
+ Set oOffset = Nothing
+
+Check:
+ If plHeight &lt; 0 Or plWidth &lt; 0 Then GoTo CatchAddress
+
+Try:
+ If VarType(pvRange) = V_STRING Then Set oAddress = _ParseAddress(pvRange) Else Set oAddress = pvRange
+ Set oSheet = oAddress.XSpreadSheet
+ Set oRange = oAddress.XCellRange.RangeAddress
+
+
+ &apos; Compute and validate new coordinates
+ With oRange
+ lLeft = .StartColumn + plColumns
+ lTop = .StartRow + plRows
+ lRight = lLeft + Iif(plWidth = 0, .EndColumn - .StartColumn, plWidth - 1)
+ lBottom = lTop + Iif(plHeight = 0, .EndRow - .StartRow, plHeight - 1)
+ If lLeft &lt; 0 Or lRight &lt; 0 Or lTop &lt; 0 Or lBottom &lt; 0 _
+ Or lLeft &gt; MAXCOLS Or lRight &gt; MAXCOLS _
+ Or lTop &gt; MAXROWS Or lBottom &gt; MAXROWS _
+ Then GoTo CatchAddress
+ Set oNewRange = oSheet.getCellRangeByPosition(lLeft, lTop, lRight, lBottom)
+ End With
+
+ &apos; Define the new range address
+ Set oOffset = New _Address
+ With oOffset
+ .ObjectType = CALCREFERENCE
+ .RawAddress = oNewRange.AbsoluteName
+ .Component = _Component
+ .XSpreadsheet = oNewRange.Spreadsheet
+ .SheetName = .XSpreadsheet.Name
+ .SheetIndex = .XSpreadsheet.RangeAddress.Sheet
+ .RangeName = .RawAddress
+ .XCellRange = oNewRange
+ .Height = oNewRange.RangeAddress.EndRow - oNewRange.RangeAddress.StartRow + 1
+ .Width = oNewRange.RangeAddress.EndColumn - oNewRange.RangeAddress.StartColumn + 1
+ End With
+
+Finally:
+ Set _Offset = oOffset
+ Exit Function
+Catch:
+ GoTo Finally
+CatchAddress:
+ ScriptForge.SF_Exception.RaiseFatal(OFFSETADDRESSERROR, &quot;Range&quot;, oAddress.RawAddress _
+ , &quot;Rows&quot;, plRows, &quot;Columns&quot;, plColumns, &quot;Height&quot;, plHeight, &quot;Width&quot;, plWidth _
+ , &quot;Document&quot;, [_Super]._FileIdent())
+ GoTo Finally
+End Function &apos; SF_Documents.SF_Calc._Offset
+
+REM -----------------------------------------------------------------------------
+Private Function _ParseAddress(ByVal psAddress As String) As Object
+&apos;&apos;&apos; Parse and validate a sheet or range reference
+&apos;&apos;&apos; Syntax to parse:
+&apos;&apos;&apos; [Sheet].[Range]
+&apos;&apos;&apos; Sheet =&gt; [&apos;][$]sheet[&apos;] or document named range or ~
+&apos;&apos;&apos; Range =&gt; A1:D10, A1, A:D, 10:10 ($ ignored), or sheet named range or ~
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An object of type _Address
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; CALCADDRESSERROR &apos; Adrress could not be parsed to a valid address
+
+Dim oAddress As _Address &apos; Return value
+Dim lStart As Long &apos; Position of found regex
+Dim sSheet As String &apos; Sheet component
+Dim sRange As String &apos; Range component
+Dim oSheets As Object &apos; com.sun.star.sheet.XSpreadsheets
+Dim oNamedRanges As Object &apos; com.sun.star.sheet.XNamedRanges
+Dim oRangeAddress As Object &apos; Alias for rangeaddress
+Dim vLastCell As Variant &apos; Result of _LastCell() method
+Dim oSelect As Object &apos; Current selection
+
+ With oAddress
+ sSheet = &quot;&quot; : sRange = &quot;&quot;
+ .SheetName = &quot;&quot; : .RangeName = &quot;&quot;
+
+ .ObjectType = CALCREFERENCE
+ .RawAddress = psAddress
+ Set .XSpreadSheet = Nothing : Set .XCellRange = Nothing
+
+ &apos; Split in sheet and range components - Check presence of surrounding single quotes or dot
+ If Left(psAddress, 1) = &quot;&apos;&quot; Then
+ lStart = 1
+ sSheet = ScriptForge.SF_String.FindRegex(psAddress, &quot;^&apos;[^\[\]*?:\/\\]+&apos;&quot;)
+ If lStart = 0 Then GoTo CatchAddress &apos; Invalid sheet name
+ If Len(psAddress) &gt; Len(sSheet) + 1 Then
+ If Mid(psAddress, Len(sSheet) + 1, 1) = &quot;.&quot; then sRange = Mid(psAddress, Len(sSheet) + 2)
+ End If
+ sSheet = Replace(Replace(sSheet, &quot;$&quot;, &quot;&quot;), &quot;&apos;&quot;, &quot;&quot;)
+ ElseIf InStr(psAddress, &quot;.&quot;) &gt; 0 Then
+ sSheet = Replace(Split(psAddress, &quot;.&quot;)(0), &quot;$&quot;, &quot;&quot;)
+ sRange = Replace(Split(psAddress, &quot;.&quot;)(1), &quot;$&quot;, &quot;&quot;)
+ Else
+ sSheet = psAddress
+ End If
+
+ &apos; Resolve sheet part: either a document named range, or the active sheet or a real sheet
+ Set oSheets = _Component.getSheets()
+ Set oNamedRanges = _Component.NamedRanges
+ If oSheets.hasByName(sSheet) Then
+ ElseIf sSheet = &quot;~&quot; And Len(sRange) &gt; 0 Then
+ sSheet = _Component.CurrentController.ActiveSheet.Name
+ ElseIf oNamedRanges.hasByName(sSheet) Then
+ .XCellRange = oNamedRanges.getByName(sSheet).ReferredCells
+ sSheet = oSheets.getByIndex(oNamedRanges.getByName(sSheet).ReferencePosition.Sheet).Name
+ Else
+ sRange = sSheet
+ sSheet = _Component.CurrentController.ActiveSheet.Name
+ End If
+ .SheetName = sSheet
+ .XSpreadSheet = oSheets.getByName(sSheet)
+ .SheetIndex = .XSpreadSheet.RangeAddress.Sheet
+
+ &apos; Resolve range part - either a sheet named range or the current selection or a real range or &quot;&quot;
+ If IsNull(.XCellRange) Then
+ Set oNamedRanges = .XSpreadSheet.NamedRanges
+ If sRange = &quot;~&quot; Then
+ Set oSelect = _Component.CurrentController.getSelection()
+ If oSelect.supportsService(&quot;com.sun.star.sheet.SheetCellRanges&quot;) Then &apos; Multiple selections
+ Set .XCellRange = oSelect.getByIndex(0)
+ Else
+ Set .XCellRange = oSelect
+ End If
+ ElseIf sRange = &quot;*&quot; Or sRange = &quot;&quot; Then
+ vLastCell = _LastCell(.XSpreadSheet)
+ sRange = &quot;A1:&quot; &amp; _GetColumnName(vLastCell(0)) &amp; CStr(vLastCell(1))
+ Set .XCellRange = .XSpreadSheet.getCellRangeByName(sRange)
+ ElseIf oNamedRanges.hasByName(sRange) Then
+ .XCellRange = oNamedRanges.getByName(sRange).ReferredCells
+ Else
+ On Local Error GoTo CatchError
+ Set .XCellRange = .XSpreadSheet.getCellRangeByName(sRange)
+ &apos; If range reaches the limits of the sheets, reduce it up to the used area
+ Set oRangeAddress = .XCellRange.RangeAddress
+ If oRangeAddress.StartColumn = 0 And oRangeAddress.EndColumn = MAXCOLS - 1 Then
+ vLastCell = _LastCell(.XSpreadSheet)
+ sRange = &quot;A&quot; &amp; CStr(oRangeAddress.StartRow + 1) &amp; &quot;:&quot; _
+ &amp; _GetColumnName(vLastCell(0)) &amp; CStr(oRangeAddress.EndRow + 1)
+ Set .XCellRange = .XSpreadSheet.getCellRangeByName(sRange)
+ ElseIf oRangeAddress.StartRow = 0 And oRangeAddress.EndRow = MAXROWS - 1 Then
+ vLastCell = _LastCell(.XSpreadSheet)
+ sRange = _GetColumnName(oRangeAddress.StartColumn + 1) &amp; &quot;1&quot; &amp; &quot;:&quot; _
+ &amp; _GetColumnName(oRangeAddress.EndColumn + 1) &amp; CStr(_LastCell(.XSpreadSheet)(1))
+ Set .XCellRange = .XSpreadSheet.getCellRangeByName(sRange)
+ End If
+ End If
+ End If
+ If IsNull(.XCellRange) Then GoTo CatchAddress
+
+ Set oRangeAddress = .XCellRange.RangeAddress
+ .RangeName = _RangeToString(oRangeAddress)
+ .Height = oRangeAddress.EndRow - oRangeAddress.StartRow + 1
+ .Width = oRangeAddress.EndColumn - oRangeAddress.StartColumn + 1
+
+ &apos; Remember the current component in case of use outside the current instance
+ Set .Component = _Component
+
+ End With
+
+Finally:
+ Set _ParseAddress = oAddress
+ Exit Function
+CatchError:
+ ScriptForge.SF_Exception.Clear()
+CatchAddress:
+ ScriptForge.SF_Exception.RaiseFatal(CALCADDRESSERROR, &quot;Range&quot;, psAddress _
+ , &quot;Document&quot;, [_Super]._FileIdent())
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc._ParseAddress
+
+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 oProperties As Object &apos; Document or Custom properties
+Dim vLastCell As Variant &apos; Coordinates of last used cell in a sheet
+Dim oSelect As Object &apos; Current selection
+Dim vRanges As Variant &apos; List of selected ranges
+Dim i As Long
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ _PropertyGet = False
+
+ cstThisSub = &quot;SFDocuments.SF_Calc.get&quot; &amp; psProperty
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not [_Super]._IsStillAlive() Then GoTo Finally
+
+ Select Case psProperty
+ Case &quot;CurrentSelection&quot;
+ Set oSelect = _Component.CurrentController.getSelection()
+ If IsNull(oSelect) Then
+ _PropertyGet = Array()
+ ElseIf oSelect.supportsService(&quot;com.sun.star.sheet.SheetCellRanges&quot;) Then &apos; Multiple selections
+ vRanges = Array()
+ For i = 0 To oSelect.Count - 1
+ vRanges = ScriptForge.SF_Array.Append(vRanges, oSelect.getByIndex(i).AbsoluteName)
+ Next i
+ _PropertyGet = vRanges
+ Else
+ _PropertyGet = oSelect.AbsoluteName
+ End If
+ Case &quot;Height&quot;
+ If IsMissing(pvArg) Or IsEmpty(pvArg) Then
+ _PropertyGet = 0
+ Else
+ If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ _PropertyGet = _ParseAddress(pvArg).Height
+ End If
+ Case &quot;LastCell&quot;, &quot;LastColumn&quot;, &quot;LastRow&quot;
+ If IsMissing(pvArg) Or IsEmpty(pvArg) Then &apos; Avoid errors when instance is watched in Basic IDE
+ _PropertyGet = -1
+ Else
+ If Not _ValidateSheet(pvArg, &quot;SheetName&quot;, , True) Then GoTo Finally
+ vLastCell = _LastCell(_Component.getSheets.getByName(pvArg))
+ If psProperty = &quot;LastRow&quot; Then
+ _PropertyGet = vLastCell(1)
+ ElseIf psProperty = &quot;LastColumn&quot; Then
+ _PropertyGet = vLastCell(0)
+ Else
+ _PropertyGet = GetColumnName(vLastCell(0)) &amp; CStr(vLastCell(1))
+ End If
+ End If
+ Case &quot;Range&quot;
+ If IsMissing(pvArg) Or IsEmpty(pvArg) Then
+ Set _PropertyGet = Nothing
+ Else
+ If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ Set _PropertyGet = _ParseAddress(pvArg)
+ End If
+ Case &quot;Sheet&quot;
+ If IsMissing(pvArg) Or IsEmpty(pvArg) Then
+ Set _PropertyGet = Nothing
+ Else
+ If Not _ValidateSheet(pvArg, &quot;SheetName&quot;, , True) Then GoTo Finally
+ Set _PropertyGet = _ParseAddress(pvArg)
+ End If
+ Case &quot;Sheets&quot;
+ _PropertyGet = _Component.getSheets.getElementNames()
+ Case &quot;Width&quot;
+ If IsMissing(pvArg) Or IsEmpty(pvArg) Then
+ _PropertyGet = 0
+ Else
+ If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ _PropertyGet = _ParseAddress(pvArg).Width
+ End If
+ Case &quot;XCellRange&quot;
+ If IsMissing(pvArg) Or IsEmpty(pvArg) Then
+ Set _PropertyGet = Nothing
+ Else
+ If Not ScriptForge.SF_Utils._Validate(pvArg, &quot;Range&quot;, V_STRING) Then GoTo Finally
+ Set _PropertyGet = _ParseAddress(pvArg).XCellRange
+ End If
+ Case &quot;XSpreadsheet&quot;
+ If IsMissing(pvArg) Or IsEmpty(pvArg) Then
+ Set _PropertyGet = Nothing
+ Else
+ If Not _ValidateSheet(pvArg, &quot;SheetName&quot;, , True) Then GoTo Finally
+ Set _PropertyGet = _Component.getSheets.getByName(pvArg)
+ End If
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFDocuments.SF_Calc._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _RangeToString(ByRef poAddress As Object) As String
+&apos;&apos;&apos; Converts a range address to its A1 notation)
+
+ With poAddress
+ _RangeToString = _GetColumnName(.StartColumn + 1) &amp; CStr(.StartRow + 1) &amp; &quot;:&quot; _
+ &amp; _GetColumnName(.EndColumn + 1) &amp; CStr(.EndRow + 1)
+ End With
+
+End Function &apos; SFDocuments.SF_Calc._RangeToString
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the SF_Calc 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;[Calc]: &quot; &amp; [_Super]._FileIdent()
+
+End Function &apos; SFDocuments.SF_Calc._Repr
+
+REM -----------------------------------------------------------------------------
+Private Sub _RestoreSelections(ByRef pvComponent As Variant _
+ , ByRef pvSelection As Variant _
+ )
+&apos;&apos;&apos; Set the selection to a single or a multiple range
+&apos;&apos;&apos; Does not work well when multiple selections and macro terminating in Basic IDE
+&apos;&apos;&apos; Called by the CopyToCell and CopyToRange methods
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvComponent: should work for foreign instances as well
+&apos;&apos;&apos; pvSelection: the stored selection done previously by Component.CurrentController.getSelection()
+
+Dim oCellRanges As Object &apos; com.sun.star.sheet.SheetCellRanges
+Dim vRangeAddresses As Variant &apos; Array of com.sun.star.table.CellRangeAddress
+Dim i As Long
+
+Try:
+ If IsArray(pvSelection) Then
+ Set oCellRanges = pvComponent.createInstance(&quot;com.sun.star.sheet.SheetCellRanges&quot;)
+ vRangeAddresses = Array()
+ ReDim vRangeAddresses(0 To UBound(pvSelection))
+ For i = 0 To UBound(pvSelection)
+ vRangeAddresses(i) = pvSelection.getByIndex(i).RangeAddress
+ Next i
+ oCellRanges.addRangeAddresses(vRangeAddresses, False)
+ pvComponent.CurrentController.select(oCellRanges)
+ Else
+ pvComponent.CurrentController.select(pvSelection)
+ End If
+
+Finally:
+ Exit Sub
+End Sub &apos; SFDocuments.SF_Calc._RestoreSelections
+
+REM -----------------------------------------------------------------------------
+Private Function _ValidateSheet(Optional ByRef pvSheetName As Variant _
+ , Optional ByVal psArgName As String _
+ , Optional ByVal pvNew As Variant _
+ , Optional ByVal pvActive As Variant _
+ , Optional ByVal pvOptional as Variant _
+ , Optional ByVal pvNumeric As Variant _
+ , Optional ByVal pvReference As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Sheet designation validation function similar to the SF_Utils._ValidateXXX functions
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvSheetName: string or numeric position
+&apos;&apos;&apos; pvNew: if True, sheet must not exist (default = False)
+&apos;&apos;&apos; pvActive: if True, the shortcut &quot;~&quot; is accepted (default = False)
+&apos;&apos;&apos; pvOptional: if True, a zero-length string is accepted (default = False)
+&apos;&apos;&apos; pvNumeric: if True, the sheet position is accepted (default = False)
+&apos;&apos;&apos; pvReference: if True, a sheet reference is acceptable (default = False)
+&apos;&apos;&apos; pvNumeric and pvReference must not both be = True
+&apos;&apos;&apos; Returns
+&apos;&apos;&apos; True if valid. SheetName is reset to current value if = &quot;~&quot;
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; DUPLICATESHEETERROR A sheet with the given name exists already
+
+Dim vSheets As Variant &apos; List of sheets
+Dim vTypes As Variant &apos; Array of accepted variable types
+Dim bValid As Boolean &apos; Return value
+
+Check:
+ If IsMissing(pvNew) Or IsEmpty(pvNew) Then pvNew = False
+ If IsMissing(pvActive) Or IsEmpty(pvActive) Then pvActive = False
+ If IsMissing(pvOptional) Or IsEmpty(pvOptional) Then pvOptional = False
+ If IsMissing(pvNumeric) Or IsEmpty(pvNumeric) Then pvNumeric = False
+ If IsMissing(pvReference) Or IsEmpty(pvReference) Then pvReference = False
+
+ &apos; Define the acceptable variable types
+ If pvNumeric Then
+ vTypes = Array(V_STRING, V_NUMERIC)
+ ElseIf pvReference Then
+ vTypes = Array(V_STRING, ScriptForge.V_OBJECT)
+ Else
+ vTypes = V_STRING
+ End If
+ If Not ScriptForge.SF_Utils._Validate(pvSheetName, psArgName, vTypes, , , Iif(pvReference, CALCREFERENCE, &quot;&quot;)) Then GoTo Finally
+ bValid = False
+
+Try:
+ If VarType(pvSheetName) = V_STRING Then
+ If pvOptional And Len(pvSheetName) = 0 Then
+ ElseIf pvActive And pvSheetName = &quot;~&quot; Then
+ pvSheetName = _Component.CurrentController.ActiveSheet.Name
+ Else
+ vSheets = _Component.getSheets.getElementNames()
+ If pvNew Then
+ If ScriptForge.SF_Array.Contains(vSheets, pvSheetName) Then GoTo CatchDuplicate
+ Else
+ If Not ScriptForge.SF_Utils._Validate(pvSheetName, psArgName, V_STRING, vSheets) Then GoTo Finally
+ End If
+ End If
+ End If
+ bValid = True
+
+Finally:
+ _ValidateSheet = bValid
+ Exit Function
+CatchDuplicate:
+ ScriptForge.SF_Exception.RaiseFatal(DUPLICATESHEETERROR, psArgName, pvSheetName, &quot;Document&quot;, [_Super]._FileIdent())
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Calc._ValidateSheet
+
+REM ============================================ END OF SFDOCUMENTS.SF_CALC
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdocuments/SF_Document.xba b/wizards/source/sfdocuments/SF_Document.xba
new file mode 100644
index 000000000000..151ecd3e03d5
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Document.xba
@@ -0,0 +1,1010 @@
+<?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_Document" 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_Document
+&apos;&apos;&apos; ===========
+&apos;&apos;&apos;
+&apos;&apos;&apos; The SFDocuments library gathers a number of methods and properties making easy
+&apos;&apos;&apos; the management and several manipulations of LibreOffice documents
+&apos;&apos;&apos;
+&apos;&apos;&apos; Some methods are generic for all types of documents: they are combined in the
+&apos;&apos;&apos; current SF_Document module
+&apos;&apos;&apos; - saving, closing documents
+&apos;&apos;&apos; - accessing their standard or custom properties
+&apos;&apos;&apos; Specific properties and methods are implemented in the concerned subclass(es) SF_Calc, SF_Writer, ...
+&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 implemented below
+&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 current module is closely related to the &quot;UI&quot; and &quot;FileSystem&quot; services
+&apos;&apos;&apos; 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.GetDocument(&quot;Untitled 1&quot;)
+&apos;&apos;&apos; &apos; or Set oDoc = ui.CreateDocument(&quot;Calc&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.Document&quot;, &quot;Untitled 1&quot;) &apos; Default = ActiveWindow
+&apos;&apos;&apos; &apos; The substring &quot;SFDocuments.&quot; in the service name is optional
+&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 DOCUMENTDEADERROR = &quot;DOCUMENTDEADERROR&quot;
+Private Const DOCUMENTSAVEERROR = &quot;DOCUMENTSAVEERROR&quot;
+Private Const DOCUMENTSAVEASERROR = &quot;DOCUMENTSAVEASERROR&quot;
+Private Const DOCUMENTREADONLYERROR = &quot;DOCUMENTREADONLYERROR&quot;
+
+REM ============================================================= PRIVATE MEMBERS
+
+Private [Me] As Object
+Private [_Parent] As Object
+Private ObjectType As String &apos; Must be DOCUMENT
+Private ServiceName As String
+
+&apos; Window description
+Private _Component As Object &apos; com.sun.star.lang.XComponent
+Private _Frame As Object &apos; com.sun.star.comp.framework.Frame
+Private _WindowName As String &apos; Object Name
+Private _WindowTitle As String &apos; Only mean to identify new documents
+Private _WindowFileName As String &apos; URL of file name
+Private _DocumentType As String &apos; Writer, Calc, ...
+
+&apos; Properties (work variables - real properties could have been set manually by user)
+Private _DocumentProperties As Object &apos; Dictionary of document properties
+Private _CustomProperties As Object &apos; Dictionary of custom properties
+
+REM ============================================================ MODULE CONSTANTS
+
+REM ===================================================== CONSTRUCTOR/DESCTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Initialize()
+ Set [Me] = Nothing
+ Set [_Parent] = Nothing
+ ObjectType = &quot;DOCUMENT&quot;
+ ServiceName = &quot;SFDocuments.Document&quot;
+ Set _Component = Nothing
+ Set _Frame = Nothing
+ _WindowName = &quot;&quot;
+ _WindowTitle = &quot;&quot;
+ _WindowFileName = &quot;&quot;
+ _DocumentType = &quot;&quot;
+ Set _DocumentProperties = Nothing
+ Set _CustomProperties = Nothing
+End Sub &apos; SFDocuments.SF_Document Constructor
+
+REM -----------------------------------------------------------------------------
+Private Sub Class_Terminate()
+ Call Class_Initialize()
+End Sub &apos; SFDocuments.SF_Document Destructor
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Call Class_Terminate()
+ Set Dispose = Nothing
+End Function &apos; SFDocuments.SF_Document Explicit Destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get CustomProperties() As Variant
+&apos;&apos;&apos; Returns a dictionary of all custom properties of the document
+ CustomProperties = _PropertyGet(&quot;CustomProperties&quot;)
+End Property &apos; SFDocuments.SF_Document.CustomProperties
+
+REM -----------------------------------------------------------------------------
+Property Let CustomProperties(Optional ByVal pvCustomProperties As Variant)
+&apos;&apos;&apos; Sets the updatable custom properties
+&apos;&apos;&apos; The argument is a dictionary
+
+Dim vPropertyValues As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim vCustomProperties As Variant &apos; Alias of argument
+Dim oUserdefinedProperties As Object &apos; Custom properties object
+Dim vOldPropertyValues As Variant &apos; Array of (to remove) existing user defined properties
+Dim oProperty As Object &apos; Single com.sun.star.beans.PropertyValues
+Dim sProperty As String &apos; Property name
+Dim vKeys As Variant &apos; Array of dictionary keys
+Dim vItems As Variant &apos; Array of dictionary items
+Dim vValue As Variant &apos; Value to store in property
+Dim iAttribute As Integer &apos; com.sun.star.beans.PropertyAttribute.REMOVEABLE
+Dim i As Long
+Const cstThisSub = &quot;SFDocuments.Document.setCustomProperties&quot;
+Const cstSubArgs = &quot;CustomProperties&quot;
+
+ 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(pvCustomProperties, &quot;CustomProperties&quot;, ScriptForge.V_OBJECT, , , &quot;DICTIONARY&quot;) Then GoTo Finally
+ End If
+
+Try:
+ Set oUserDefinedProperties = _Component.getDocumentProperties().UserDefinedProperties
+
+ Set vCustomProperties = pvCustomProperties &apos; To avoid &quot;Object variable not set&quot; error
+ With vCustomProperties
+
+ &apos; All existing custom properties must first be removed to avoid type conflicts
+ vOldPropertyValues = oUserDefinedProperties.getPropertyValues
+ For Each oProperty In vOldPropertyValues
+ sProperty = oProperty.Name
+ oUserDefinedProperties.removeProperty(sProperty)
+ Next oProperty
+
+ &apos; Insert new properties one by one after type adjustment (dates, arrays, numbers)
+ vKeys = .Keys
+ vItems = .Items
+ iAttribute = com.sun.star.beans.PropertyAttribute.REMOVEABLE
+ For i = 0 To UBound(vKeys)
+ If VarType(vItems(i)) = V_DATE Then
+ vValue = ScriptForge.SF_Utils._CDateToUnoDate(vItems(i))
+ ElseIf IsArray(vItems(i)) Then
+ vValue = Null
+ ElseIf ScriptForge.SF_Utils._VarTypeExt(vItems(i)) = ScriptForge.V_NUMERIC Then
+ vValue = CreateUnoValue(&quot;double&quot;, vItems(i))
+ Else
+ vValue = vItems(i)
+ End If
+ oUserDefinedProperties.addProperty(vKeys(i), iAttribute, vValue)
+ Next i
+
+ &apos; Declare the document as changed
+ _Component.setModified(True)
+ End With
+
+ &apos; Reload custom properties in current object instance
+ _PropertyGet(&quot;CustomProperties&quot;)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Property
+Catch:
+ GoTo Finally
+End Property &apos; SFDocuments.SF_Document.CustomProperties
+
+REM -----------------------------------------------------------------------------
+Property Get Description() As Variant
+&apos;&apos;&apos; Returns the updatable document property Description
+ Description = _PropertyGet(&quot;Description&quot;)
+End Property &apos; SFDocuments.SF_Document.Description
+
+REM -----------------------------------------------------------------------------
+Property Let Description(Optional ByVal pvDescription As Variant)
+&apos;&apos;&apos; Sets the updatable document property Description
+&apos;&apos;&apos; If multilined, separate lines by &quot;\n&quot; escape sequence or by hard breaks
+
+Dim sDescription As String &apos; Alias of pvDescription
+Const cstThisSub = &quot;SFDocuments.Document.setDescription&quot;
+Const cstSubArgs = &quot;Description&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(pvDescription, &quot;Description&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Update in UNO component object and in current instance
+ sDescription = Replace(pvDescription, &quot;\n&quot;, ScriptForge.SF_String.sfNEWLINE)
+ _Component.DocumentProperties.Description = sDescription
+ If Not IsNull(_DocumentProperties) Then _DocumentProperties.ReplaceItem(&quot;Description&quot;, sdescription)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Property
+End Property &apos; SFDocuments.SF_Document.Description
+
+REM -----------------------------------------------------------------------------
+Property Get DocumentProperties() As Variant
+&apos;&apos;&apos; Returns a dictionary of all standard document properties, custom properties are excluded
+ DocumentProperties = _PropertyGet(&quot;DocumentProperties&quot;)
+End Property &apos; SFDocuments.SF_Document.DocumentProperties
+
+REM -----------------------------------------------------------------------------
+Property Get DocumentType() As String
+&apos;&apos;&apos; Returns &quot;Base&quot;, &quot;Calc&quot;, &quot;Draw&quot;, ... or &quot;Writer&quot;
+ DocumentType = _PropertyGet(&quot;DocumentType&quot;)
+End Property &apos; SFDocuments.SF_Document.DocumentType
+
+REM -----------------------------------------------------------------------------
+Property Get IsBase() As Boolean
+ IsBase = _PropertyGet(&quot;IsBase&quot;)
+End Property &apos; SFDocuments.SF_Document.IsBase
+
+REM -----------------------------------------------------------------------------
+Property Get IsCalc() As Boolean
+ IsCalc = _PropertyGet(&quot;IsCalc&quot;)
+End Property &apos; SFDocuments.SF_Document.IsCalc
+
+REM -----------------------------------------------------------------------------
+Property Get IsDraw() As Boolean
+ IsDraw = _PropertyGet(&quot;IsDraw&quot;)
+End Property &apos; SFDocuments.SF_Document.IsDraw
+
+REM -----------------------------------------------------------------------------
+Property Get IsImpress() As Boolean
+ IsImpress = _PropertyGet(&quot;IsImpress&quot;)
+End Property &apos; SFDocuments.SF_Document.IsImpress
+
+REM -----------------------------------------------------------------------------
+Property Get IsMath() As Boolean
+ IsMath = _PropertyGet(&quot;IsMath&quot;)
+End Property &apos; SFDocuments.SF_Document.IsMath
+
+REM -----------------------------------------------------------------------------
+Property Get IsWriter() As Boolean
+ IsWriter = _PropertyGet(&quot;IsWriter&quot;)
+End Property &apos; SFDocuments.SF_Document.IsWriter
+
+REM -----------------------------------------------------------------------------
+Property Get Keywords() As Variant
+&apos;&apos;&apos; Returns the updatable document property Keywords
+ Keywords = _PropertyGet(&quot;Keywords&quot;)
+End Property &apos; SFDocuments.SF_Document.Keywords
+
+REM -----------------------------------------------------------------------------
+Property Let Keywords(Optional ByVal pvKeywords As Variant)
+&apos;&apos;&apos; Sets the updatable document property Keywords
+
+Dim vKeywords As Variant &apos; Alias of pvKeywords
+Const cstThisSub = &quot;SFDocuments.Document.setKeywords&quot;
+Const cstSubArgs = &quot;Keywords&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(pvKeywords, &quot;Keywords&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Update in UNO component object and in current instance
+ vKeywords = ScriptForge.SF_Array.TrimArray(Split(pvKeywords, &quot;,&quot;))
+ _Component.DocumentProperties.Keywords = vKeywords
+ If Not IsNull(_DocumentProperties) Then _DocumentProperties.ReplaceItem(&quot;Keywords&quot;, Join(vKeywords, &quot;, &quot;))
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Property
+End Property &apos; SFDocuments.SF_Document.Keywords
+
+REM -----------------------------------------------------------------------------
+Property Get Readonly() As Boolean
+&apos;&apos;&apos; Returns True if the document must not be modified
+ Readonly = _PropertyGet(&quot;Readonly&quot;)
+End Property &apos; SFDocuments.SF_Document.Readonly
+
+REM -----------------------------------------------------------------------------
+Property Get Subject() As Variant
+&apos;&apos;&apos; Returns the updatable document property Subject
+ Subject = _PropertyGet(&quot;Subject&quot;)
+End Property &apos; SFDocuments.SF_Document.Subject
+
+REM -----------------------------------------------------------------------------
+Property Let Subject(Optional ByVal pvSubject As Variant)
+&apos;&apos;&apos; Sets the updatable document property Subject
+
+Const cstThisSub = &quot;SFDocuments.Document.setSubject&quot;
+Const cstSubArgs = &quot;Subject&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(pvSubject, &quot;Subject&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Update in UNO component object and in current instance
+ _Component.DocumentProperties.Subject = pvSubject
+ If Not IsNull(_DocumentProperties) Then _DocumentProperties.ReplaceItem(&quot;Subject&quot;, pvSubject)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Property
+End Property &apos; SFDocuments.SF_Document.Subject
+
+REM -----------------------------------------------------------------------------
+Property Get Title() As Variant
+&apos;&apos;&apos; Returns the updatable document property Title
+ Title = _PropertyGet(&quot;Title&quot;)
+End Property &apos; SFDocuments.SF_Document.Title
+
+REM -----------------------------------------------------------------------------
+Property Let Title(Optional ByVal pvTitle As Variant)
+&apos;&apos;&apos; Sets the updatable document property Title
+
+Const cstThisSub = &quot;SFDocuments.Document.setTitle&quot;
+Const cstSubArgs = &quot;Title&quot;
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive(True) Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(pvTitle, &quot;Title&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Update in UNO component object and in current instance
+ _Component.DocumentProperties.Title = pvTitle
+ If Not IsNull(_DocumentProperties) Then _DocumentProperties.ReplaceItem(&quot;Title&quot;, pvTitle)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Property
+End Property &apos; SFDocuments.SF_Document.Title
+
+REM -----------------------------------------------------------------------------
+Property Get XComponent() As Variant
+&apos;&apos;&apos; Returns the com.sun.star.lang.XComponent UNO object representing the document
+ XComponent = _PropertyGet(&quot;XComponent&quot;)
+End Property &apos; SFDocuments.SF_Document.XComponent
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function Activate() As Boolean
+&apos;&apos;&apos; Make the current document active
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if the document could be activated
+&apos;&apos;&apos; Otherwise, there is no change in the actual user interface
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.Activate()
+
+Dim bActivate As Boolean &apos; Return value
+Dim oContainer As Object &apos; com.sun.star.awt.XWindow
+Const cstThisSub = &quot;SFDocuments.Document.Activate&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bActivate = False
+
+Check:
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _IsStillAlive() Then GoTo Finally
+
+Try:
+ Set oContainer = _Frame.ContainerWindow
+ With oContainer
+ If .isVisible() = False Then .setVisible(True)
+ .IsMinimized = False
+ .setFocus()
+ .toFront() &apos; Force window change in Linux
+ Wait 1 &apos; Bypass desynchro issue in Linux
+ End With
+ bActivate = True
+
+Finally:
+ Activate = bActivate
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.Activate
+
+REM -----------------------------------------------------------------------------
+Public Function CloseDocument(Optional ByVal SaveAsk As Variant) As Boolean
+&apos;&apos;&apos; Close the document. Does nothing if the document is already closed
+&apos;&apos;&apos; regardless of how the document was closed, manually or by program
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; SaveAsk: If True (default), the user is invited to confirm or not the writing of the changes on disk
+&apos;&apos;&apos; No effect if the document was not modified
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False if the user declined to close
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; If oDoc.CloseDocument() Then
+&apos;&apos;&apos; &apos; ...
+
+Dim bClosed As Boolean &apos; return value
+Dim oDispatch &apos; com.sun.star.frame.DispatchHelper
+Const cstThisSub = &quot;SFDocuments.Document.CloseDocument&quot;
+Const cstSubArgs = &quot;[SaveAsk=True]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bClosed = False
+
+Check:
+ If IsMissing(SaveAsk) Or IsEmpty(SaveAsk) Then SaveAsk = True
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(SaveAsk, &quot;SaveAsk&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ If SaveAsk And _Component.IsModified Then &apos; Execute closure with the File/Close menu command
+ Activate()
+ RunCommand(&quot;CloseDoc&quot;)
+ bClosed = _IsStillAlive(, False) &apos; Do not raise error
+ Else
+ _Frame.close(True)
+ _Frame.dispose()
+ bClosed = True
+ End If
+
+Finally:
+ If bClosed Then Dispose()
+ CloseDocument = bClosed
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.CloseDocument
+
+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; If the property does not exist, returns Null
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; see the exceptions of the individual properties
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; myModel.GetProperty(&quot;MyProperty&quot;)
+
+Const cstThisSub = &quot;SFDocuments.Document.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:
+ GetProperty = _PropertyGet(PropertyName)
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list of public methods of the Model service as an array
+
+ Methods = Array( _
+ &quot;Activate&quot; _
+ , &quot;CloseDocument&quot; _
+ , &quot;RunCommand&quot; _
+ , &quot;Save&quot; _
+ , &quot;SaveAs&quot; _
+ , &quot;SaveCopyAs&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Document.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the Timer class as an array
+
+ Properties = Array( _
+ &quot;CustomProperties&quot; _
+ , &quot;Description&quot; _
+ , &quot;DocumentProperties&quot; _
+ , &quot;DocumentType&quot; _
+ , &quot;IsBase&quot; _
+ , &quot;IsCalc&quot; _
+ , &quot;IsDraw &quot; _
+ , &quot;IsImpress&quot; _
+ , &quot;IsMath&quot; _
+ , &quot;IsWriter&quot; _
+ , &quot;Keywords&quot; _
+ , &quot;Readonly&quot; _
+ , &quot;Subject&quot; _
+ , &quot;Title&quot; _
+ , &quot;XComponent&quot; _
+ )
+
+End Function &apos; SFDocuments.SF_Document.Properties
+
+REM -----------------------------------------------------------------------------
+Public Sub RunCommand(Optional ByVal Command As Variant)
+&apos;&apos;&apos; Run on the document the given menu command. The command is executed without arguments
+&apos;&apos;&apos; A few typical commands:
+&apos;&apos;&apos; Save, SaveAs, ExportToPDF, SetDocumentProperties, Undo, Copy, Paste, ...
+&apos;&apos;&apos; Dozens can be found in the directory $install/share/config/soffice.cfg/modules
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Command: Case-sensitive. The command itself is not checked.
+&apos;&apos;&apos; If nothing happens, then the command is probably wrong
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.RunCommand(&quot;About&quot;)
+
+Dim oDispatch &apos; com.sun.star.frame.DispatchHelper
+Const cstThisSub = &quot;SFDocuments.Document.RunCommand&quot;
+Const cstSubArgs = &quot;Command&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not ScriptForge.SF_Utils._Validate(Command, &quot;Command&quot;, V_STRING) Then GoTo Finally
+ End If
+
+Try:
+ Set oDispatch = ScriptForge.SF_Utils._GetUNOService(&quot;DispatchHelper&quot;)
+ oDispatch.executeDispatch(_Frame, &quot;.uno:&quot; &amp; Command, &quot;&quot;, 0, Array())
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Sub
+Catch:
+ GoTo Finally
+End Sub &apos; SFDocuments.SF_Document.RunCommand
+
+REM -----------------------------------------------------------------------------
+Public Function Save() As Boolean
+&apos;&apos;&apos; Store the document to the file location from which it was loaded
+&apos;&apos;&apos; Ignored if the document was not modified
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False if the document could not be saved
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DOCUMENTSAVEERROR The file has been opened readonly or was opened as new and was not yet saved
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; If Not oDoc.Save() Then
+&apos;&apos;&apos; &apos; ...
+
+Dim bSaved As Boolean &apos; return value
+Const cstThisSub = &quot;SFDocuments.Document.Save&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bSaved = False
+
+Check:
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _IsStillAlive() Then GoTo Finally
+ bSaved = False
+
+Try:
+ With _Component
+ If .isReadonly() Or Not .hasLocation() Then GoTo CatchReadonly
+ If .IsModified() Then
+ .store()
+ bSaved = True
+ End If
+ End With
+
+Finally:
+ Save = bSaved
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchReadonly:
+ ScriptForge.SF_Exception.RaiseFatal(DOCUMENTSAVEERROR, &quot;FileName&quot;, _FileIdent())
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.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
+&apos;&apos;&apos; Store the document to the given file location
+&apos;&apos;&apos; The new location becomes the new file name on which simple Save method calls will be applied
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file where to save. It must follow the SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; Overwrite: True if the destination file may be overwritten (default = False)
+&apos;&apos;&apos; Password: Use to protect the document
+&apos;&apos;&apos; FilterName: the name of a filter that should be used for saving the document
+&apos;&apos;&apos; If present, the filter must exist
+&apos;&apos;&apos; FilterOptions: an optional string of options associated with the filter
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False if the document could not be saved
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DOCUMENTSAVEASERROR The destination has its readonly attribute set or overwriting rejected
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.SaveAs(&quot;C:\Me\Copy2.odt&quot;, Overwrite := True)
+
+Dim bSaved As Boolean &apos; return value
+Dim oFilterFactory As Object &apos; com.sun.star.document.FilterFactory
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim sFile As String &apos; Alias of FileName
+Dim vProperties As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim FSO As Object &apos; SF_FileSystem
+Const cstThisSub = &quot;SFDocuments.Document.SaveAs&quot;
+Const cstSubArgs = &quot;FileName, [Overwrite=False], [Password=&quot;&quot;&quot;&quot;], [FilterName=&quot;&quot;&quot;&quot;], [FilterOptions=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo CatchError
+ bSaved = False
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
+ If IsMissing(Password) Or IsEmpty(Password) Then Password = &quot;&quot;
+ If IsMissing(FilterName) Or IsEmpty(FilterName) Then FilterName = &quot;&quot;
+ If IsMissing(FilterOptions) Or IsEmpty(FilterOptions) Then FilterOptions = &quot;&quot;
+
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Password, &quot;Password&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(FilterName, &quot;FilterName&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(FilterOptions, &quot;FilterOptions&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ &apos; Check that the filter exists
+ If Len(FilterName) &gt; 0 Then
+ Set oFilterFactory = ScriptForge.SF_Utils._GetUNOService(&quot;FilterFactory&quot;)
+ If Not oFilterFactory.hasByName(FilterName) Then GoTo CatchError
+ End If
+
+ &apos; Check destination file overwriting
+ Set FSO = CreateScriptService(&quot;FileSystem&quot;)
+ sFile = FSO._ConvertToUrl(FileName)
+ If FSO.FileExists(FileName) Then
+ If Overwrite = False Then GoTo CatchError
+ Set oSfa = ScriptForge.SF_Utils._GetUNOService(&quot;FileAccess&quot;)
+ If oSfa.isReadonly(sFile) Then GoTo CatchError
+ End If
+
+Try:
+ &apos; Setup arguments
+ If Len(Password) + Len(FilterName) = 0 Then
+ vProperties = Array()
+ Else
+ vProperties = Array( _
+ ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterName&quot;, FilterName) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterOptions&quot;, FilterOptions) _
+ )
+ If Len(Password) &gt; 0 Then &apos; Password is to add only if &lt;&gt; &quot;&quot; !?
+ vProperties = ScriptForge.SF_Array.Append(vproperties _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;Password&quot;, Password))
+ End If
+ End If
+
+ _Component.StoreAsURL(sFile, vProperties)
+
+ &apos; Remind the new file name
+ _WindowFileName = sFile
+ _WindowName = FSO.GetName(FileName)
+ bSaved = True
+
+Finally:
+ SaveAs = bSaved
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchError:
+ ScriptForge.SF_Exception.RaiseFatal(DOCUMENTSAVEASERROR, &quot;FileName&quot;, FileName, &quot;Overwrite&quot;, Overwrite _
+ , &quot;FilterName&quot;, FilterName)
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.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
+&apos;&apos;&apos; Store a copy or export the document to the given file location
+&apos;&apos;&apos; The actual location is unchanged
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file where to save. It must follow the SF_FileSystem.FileNaming notation
+&apos;&apos;&apos; Overwrite: True if the destination file may be overwritten (default = False)
+&apos;&apos;&apos; Password: Use to protect the document
+&apos;&apos;&apos; FilterName: the name of a filter that should be used for saving the document
+&apos;&apos;&apos; If present, the filter must exist
+&apos;&apos;&apos; FilterOptions: an optional string of options associated with the filter
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; False if the document could not be saved
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; DOCUMENTSAVEASERROR The destination has its readonly attribute set or overwriting rejected
+&apos;&apos;&apos; Examples:
+&apos;&apos;&apos; oDoc.SaveCopyAs(&quot;C:\Me\Copy2.odt&quot;, Overwrite := True)
+
+Dim bSaved As Boolean &apos; return value
+Dim oFilterFactory As Object &apos; com.sun.star.document.FilterFactory
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim sFile As String &apos; Alias of FileName
+Dim vProperties As Variant &apos; Array of com.sun.star.beans.PropertyValue
+Dim FSO As Object &apos; SF_FileSystem
+Const cstThisSub = &quot;SFDocuments.Document.SaveCopyAs&quot;
+Const cstSubArgs = &quot;FileName, [Overwrite=False], [Password=&quot;&quot;&quot;&quot;], [FilterName=&quot;&quot;&quot;&quot;], [FilterOptions=&quot;&quot;&quot;&quot;]&quot;
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo CatchError
+ bSaved = False
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = False
+ If IsMissing(Password) Or IsEmpty(Password) Then Password = &quot;&quot;
+ If IsMissing(FilterName) Or IsEmpty(FilterName) Then FilterName = &quot;&quot;
+ If IsMissing(FilterOptions) Or IsEmpty(FilterOptions) Then FilterOptions = &quot;&quot;
+
+ If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not _IsStillAlive() Then GoTo Finally
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Password, &quot;Password&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(FilterName, &quot;FilterName&quot;, V_STRING) Then GoTo Finally
+ If Not SF_Utils._Validate(FilterOptions, &quot;FilterOptions&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ &apos; Check that the filter exists
+ If Len(FilterName) &gt; 0 Then
+ Set oFilterFactory = ScriptForge.SF_Utils._GetUNOService(&quot;FilterFactory&quot;)
+ If Not oFilterFactory.hasByName(FilterName) Then GoTo CatchError
+ End If
+
+ &apos; Check destination file overwriting
+ Set FSO = CreateScriptService(&quot;FileSystem&quot;)
+ sFile = FSO._ConvertToUrl(FileName)
+ If FSO.FileExists(FileName) Then
+ If Overwrite = False Then GoTo CatchError
+ Set oSfa = ScriptForge.SF_Utils._GetUNOService(&quot;FileAccess&quot;)
+ If oSfa.isReadonly(sFile) Then GoTo CatchError
+ End If
+
+Try:
+ &apos; Setup arguments
+ If Len(Password) + Len(FilterName) = 0 Then
+ vProperties = Array()
+ Else
+ vProperties = Array( _
+ ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterName&quot;, FilterName) _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;FilterOptions&quot;, FilterOptions) _
+ )
+ If Len(Password) &gt; 0 Then &apos; Password is to add only if &lt;&gt; &quot;&quot; !?
+ vProperties = ScriptForge.SF_Array.Append(vproperties _
+ , ScriptForge.SF_Utils._MakePropertyValue(&quot;Password&quot;, Password))
+ End If
+ End If
+
+ _Component.StoreToURL(sFile, vProperties)
+ bSaved = True
+
+Finally:
+ SaveCopyAs = bSaved
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchError:
+ ScriptForge.SF_Exception.RaiseFatal(DOCUMENTSAVEASERROR, &quot;FileName&quot;, FileName, &quot;Overwrite&quot;, Overwrite _
+ , &quot;FilterName&quot;, FilterName)
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document.SaveCopyAs
+
+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.Document.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_Document.SetProperty
+
+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 = Iif(Len(_WindowFileName) &gt; 0, SF_FileSystem._ConvertFromUrl(_WindowFileName), _WindowTitle)
+
+End Function &apos; SFDocuments.SF_Document._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
+Dim sFileName As String &apos; File identification used to display error message
+
+ On Local Error GoTo Catch &apos; Anticipate DisposedException errors or alike
+ If IsMissing(pbForUpdate) Then pbForUpdate = False
+ If IsMissing(pbError) Then pbError = True
+
+Try:
+ &apos; Check existence of document
+ bAlive = Not IsNull(_Frame)
+ If bAlive Then bAlive = Not IsNull(_Component)
+ If bAlive Then bAlive = Not IsNull(_Component.CurrentController)
+
+ &apos; Check document is not read only
+ If bAlive And pbForUpdate Then
+ If _Component.isreadonly() Then GoTo CatchReadonly
+ End If
+
+Finally:
+ _IsStillAlive = bAlive
+ Exit Function
+Catch:
+ bAlive = False
+ On Error GoTo 0
+ sFileName = _FileIdent()
+ Dispose()
+ If pbError Then ScriptForge.SF_Exception.RaiseFatal(DOCUMENTDEADERROR, sFileName)
+ GoTo Finally
+CatchReadonly:
+ bAlive = False
+ If pbError Then ScriptForge.SF_Exception.RaiseFatal(DOCUMENTREADONLYERROR, &quot;Document&quot;, _FileIdent())
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Document._IsStillAlive
+
+REM -----------------------------------------------------------------------------
+Private Sub _LoadDocumentProperties()
+&apos;&apos;&apos; Create dictionary with document properties as entries/ Custom properties are excluded
+&apos;&apos;&apos; Document is presumed still alive
+&apos;&apos;&apos; Special values:
+&apos;&apos;&apos; Only valid dates are taken
+&apos;&apos;&apos; Statistics are exploded in subitems. Subitems are specific to document type
+&apos;&apos;&apos; Keywords are joined
+&apos;&apos;&apos; Language is aligned on L10N convention la-CO
+
+Dim oProperties As Object &apos; Document properties
+Dim vNamedValue As Variant &apos; com.sun.star.beans.NamedValue
+
+ If IsNull(_DocumentProperties) Then
+ Set oProperties = _Component.getDocumentProperties
+ Set _DocumentProperties = CreateScriptService(&quot;Dictionary&quot;)
+ With _DocumentProperties
+ .Add(&quot;Author&quot;, oProperties.Author)
+ .Add(&quot;AutoloadSecs&quot;, oProperties.AutoloadSecs)
+ .Add(&quot;AutoloadURL&quot;, oProperties.AutoloadURL)
+ If oProperties.CreationDate.Year &gt; 0 Then .Add(&quot;CreationDate&quot;, CDateFromUnoDateTime(oProperties.CreationDate))
+ .Add(&quot;DefaultTarget&quot;, oProperties.DefaultTarget)
+ .Add(&quot;Description&quot;, oProperties.Description) &apos; The description can be multiline
+ &apos; DocumentStatistics : number and names of statistics depend on document type
+ For Each vNamedValue In oProperties.DocumentStatistics
+ .Add(vNamedValue.Name, vNamedValue.Value)
+ Next vNamedValue
+ .Add(&quot;EditingDuration&quot;, oProperties.EditingDuration)
+ .Add(&quot;Generator&quot;, oProperties.Generator)
+ .Add(&quot;Keywords&quot;, Join(oProperties.Keywords, &quot;, &quot;))
+ .Add(&quot;Language&quot;, oProperties.Language.Language &amp; Iif(Len(oProperties.Language.Country) &gt; 0, &quot;-&quot; &amp; oProperties.Language.Country, &quot;&quot;))
+ If oProperties.ModificationDate.Year &gt; 0 Then .Add(&quot;ModificationDate&quot;, CDateFromUnoDateTime(oProperties.ModificationDate))
+ If oProperties.PrintDate.Year &gt; 0 Then .Add(&quot;PrintDate&quot;, CDateFromUnoDateTime(oProperties.PrintDate))
+ .Add(&quot;PrintedBy&quot;, oProperties.PrintedBy)
+ .Add(&quot;Subject&quot;, oProperties.Subject)
+ If oProperties.TemplateDate.Year &gt; 0 Then .Add(&quot;TemplateDate&quot;, CDateFromUnoDateTime(oProperties.TemplateDate))
+ .Add(&quot;TemplateName&quot;, oProperties.TemplateName)
+ .Add(&quot;TemplateURL&quot;, oProperties.TemplateURL)
+ .Add(&quot;Title&quot;, oProperties.Title)
+ End With
+ End If
+
+End Sub &apos; SFDocuments.SF_Document._LoadDocumentProperties
+
+REM -----------------------------------------------------------------------------
+Private Function _PropertyGet(Optional ByVal psProperty As String) 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 oProperties As Object &apos; Document or Custom properties
+Dim cstThisSub As String
+Const cstSubArgs = &quot;&quot;
+
+ _PropertyGet = False
+
+ Select Case _DocumentType
+ Case &quot;Calc&quot; : cstThisSub = &quot;SFDocuments.SF_&quot; &amp; _DocumentType &amp; &quot;.get&quot; &amp; psProperty
+ Case Else : cstThisSub = &quot;SFDocuments.SF_Document.get&quot; &amp; psProperty
+ End Select
+ ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+ If Not _IsStillAlive() Then GoTo Finally
+
+ Select Case psProperty
+ Case &quot;CustomProperties&quot;
+ _CustomProperties = CreateScriptService(&quot;Dictionary&quot;) &apos; Always reload as updates could have been done manually by user
+ _CustomProperties.ImportFromPropertyValues(_Component.getDocumentProperties().UserDefinedProperties.getPropertyValues)
+ _PropertyGet = _CustomProperties
+ Case &quot;Description&quot;
+ _PropertyGet = _Component.DocumentProperties.Description
+ Case &quot;DocumentProperties&quot;
+ _LoadDocumentProperties() &apos; Always reload as updates could have been done manually by user
+ Set _PropertyGet = _DocumentProperties
+ Case &quot;DocumentType&quot;
+ _PropertyGet = _DocumentType
+ Case &quot;IsBase&quot;, &quot;IsCalc&quot;, &quot;IsDraw&quot;, &quot;IsImpress&quot;, &quot;IsMath&quot;, &quot;IsWriter&quot;
+ _PropertyGet = ( Mid(psProperty, 3) = _DocumentType )
+ Case &quot;Keywords&quot;
+ _PropertyGet = Join(_Component.DocumentProperties.Keywords, &quot;, &quot;)
+ Case &quot;Readonly&quot;
+ _PropertyGet = _Component.isReadonly()
+ Case &quot;Subject&quot;
+ _PropertyGet = _Component.DocumentProperties.Subject
+ Case &quot;Title&quot;
+ _PropertyGet = _Component.DocumentProperties.Title
+ Case &quot;XComponent&quot;
+ Set _PropertyGet = _Component
+ Case Else
+ _PropertyGet = Null
+ End Select
+
+Finally:
+ ScriptForge.SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+End Function &apos; SFDocuments.SF_Document._PropertyGet
+
+REM -----------------------------------------------------------------------------
+Private Function _Repr() As String
+&apos;&apos;&apos; Convert the SF_Document 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;[Document]: &quot; &amp; _DocumentType &amp; &quot; - &quot; &amp; _FileIdent()
+
+End Function &apos; SFDocuments.SF_Document._Repr
+
+REM ============================================ END OF SFDOCUMENTS.SF_DOCUMENT
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdocuments/SF_Register.xba b/wizards/source/sfdocuments/SF_Register.xba
new file mode 100644
index 000000000000..40f327bb0d41
--- /dev/null
+++ b/wizards/source/sfdocuments/SF_Register.xba
@@ -0,0 +1,198 @@
+<?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_Register" 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 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_Register
+&apos;&apos;&apos; ===========
+&apos;&apos;&apos; The ScriptForge framework includes
+&apos;&apos;&apos; the master ScriptForge library
+&apos;&apos;&apos; a number of &quot;associated&quot; libraries SF*
+&apos;&apos;&apos; any user/contributor extension wanting to fit into the framework
+&apos;&apos;&apos;
+&apos;&apos;&apos; The main methods in this module allow the current library to cling to ScriptForge
+&apos;&apos;&apos; - RegisterScriptServices
+&apos;&apos;&apos; Register the list of services implemented by the current library
+&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
+
+REM ============================================================== PUBLIC METHODS
+
+REM -----------------------------------------------------------------------------
+Public Sub RegisterScriptServices() As Variant
+&apos;&apos;&apos; Register into ScriptForge the list of the services implemented by the current library
+&apos;&apos;&apos; Each library pertaining to the framework must implement its own version of this method
+&apos;&apos;&apos;
+&apos;&apos;&apos; It consists in successive calls to the RegisterService() and RegisterEventManager() methods
+&apos;&apos;&apos; with 2 arguments:
+&apos;&apos;&apos; ServiceName: the name of the service as a case-insensitive string
+&apos;&apos;&apos; ServiceReference: the reference as an object
+&apos;&apos;&apos; If the reference refers to a module, then return the module as an object:
+&apos;&apos;&apos; GlobalScope.Library.Module
+&apos;&apos;&apos; If the reference is a class instance, then return a string referring to the method
+&apos;&apos;&apos; containing the New statement creating the instance
+&apos;&apos;&apos; &quot;libraryname.modulename.function&quot;
+
+ With GlobalScope.ScriptForge.SF_Services
+ .RegisterService(&quot;Document&quot;, &quot;SFDocuments.SF_Register._NewDocument&quot;) &apos; Reference to the function initializing the service
+ .RegisterService(&quot;Calc&quot;, &quot;SFDocuments.SF_Register._NewDocument&quot;) &apos; Same references, distinction is made inside the function
+ .RegisterService(&quot;Base&quot;, &quot;SFDocuments.SF_Register._NewDocument&quot;) &apos; Same references, distinction is made inside the function
+ .RegisterEventManager(&quot;DocumentEvent&quot;, &quot;SFDocuments.SF_Register._EventManager&quot;) &apos; Reference to the events manager
+ &apos;TODO
+ End With
+
+End Sub &apos; SFDocuments.SF_Register.RegisterScriptServices
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Public Function _EventManager(Optional ByRef pvArgs As Variant) As Object
+&apos;&apos;&apos; Returns a Document or Calc object corresponding with the active component
+&apos;&apos;&apos; which triggered the event in argument
+&apos;&apos;&apos; This method should be triggered only thru the invocation of CreateScriptService
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; pvEvent: com.sun.star.document.DocumentEvent
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; the output of a Document, Calc, ... service or Nothing
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Sub TriggeredByEvent(ByRef poEvent As Object)
+&apos;&apos;&apos; Dim oDoc As Object
+&apos;&apos;&apos; Set oDoc = CreateScriptService(&quot;SFDocuments.DocumentEvent&quot;, poEvent)
+&apos;&apos;&apos; If Not IsNull(oDoc) Then
+&apos;&apos;&apos; &apos; ... (a valid document has been identified)
+&apos;&apos;&apos; End Sub
+
+Dim oSource As Object &apos; Return value
+Dim vEvent As Variant &apos; Alias of pvArgs(0)
+
+ &apos; Never abort while an event is processed
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Finally
+ Set oSource = Nothing
+
+Check:
+ If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
+ If UBound(pvArgs) &gt;= 0 Then vEvent = pvArgs(0) Else Set vEvent = Empty
+ If VarType(vEvent) &lt;&gt; ScriptForge.V_OBJECT Then GoTo Finally
+
+Try:
+ If ScriptForge.SF_Session.UnoObjectType(vEvent) = &quot;com.sun.star.document.DocumentEvent&quot; Then
+ If ScriptForge.SF_Session.UnoObjectType(vEvent.Source) = &quot;SwXTextDocument&quot; Then
+ Set oSource = SF_Register._NewDocument(vEvent.Source)
+ End If
+ End If
+
+Finally:
+ Set _EventManager = oSource
+ Exit Function
+End Function &apos; SFDocuments.SF_Documents._EventManager
+
+REM -----------------------------------------------------------------------------
+Public Function _NewDocument(Optional ByVal pvArgs As Variant) As Object
+&apos;&apos;&apos; Create a new instance of the (super) SF_Document class or of one of its subclasses (SF_Calc, ...)
+&apos; Args:
+&apos;&apos;&apos; WindowName: see the definition of WindowName in the description of the UI service
+&apos;&apos;&apos; If absent, the document is presumed to be in the active window
+&apos;&apos;&apos; If WindowName is an object, it must be a component
+&apos;&apos;&apos; (com.sun.star.lang.XComponent or com.sun.star.comp.dba.ODatabaseDocument)
+&apos;&apos;&apos; Returns: the instance or Nothing
+
+Dim oDocument As Object &apos; Return value
+Dim oSuperDocument As Object &apos; Companion superclass document
+Dim vWindowName As Variant &apos; Alias of pvArgs(0)
+Dim oEnum As Object &apos; com.sun.star.container.XEnumeration
+Dim oComp As Object &apos; com.sun.star.lang.XComponent
+Dim vWindow As Window &apos; A single component
+Dim oUi As Object &apos; &quot;UI&quot; service
+Dim bFound As Boolean &apos; True if the document is found on the desktop
+
+ If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+
+Check:
+ If IsMissing(pvArgs) Or IsEmpty(pvArgs) Then pvArgs = Array()
+ If Not IsArray(pvArgs) Then pvArgs = Array(pvArgs) &apos; Needed when _NewDocument called from _EventManager
+ If UBound(pvArgs) &gt;= 0 Then vWindowName = pvArgs(0) Else vWindowName = &quot;&quot;
+ If Not ScriptForge.SF_Utils._Validate(vWindowName, &quot;WindowName&quot;, Array(V_STRING, ScriptForge.V_OBJECT)) Then GoTo Finally
+ Set oDocument = Nothing
+
+Try:
+ Set oUi = ScriptForge.SF_Register.CreateScriptService(&quot;UI&quot;)
+ Select Case VarType(vWindowName)
+ Case V_STRING
+ If Len(vWindowName) &gt; 0 Then
+ bFound = False
+ Set oEnum = StarDesktop.Components().createEnumeration
+ Do While oEnum.hasMoreElements
+ Set oComp = oEnum.nextElement
+ vWindow = oUi._IdentifyWindow(oComp)
+ With vWindow
+ &apos; Does the current window match the argument ?
+ If (Len(.WindowFileName) &gt; 0 And .WindowFileName = ScriptForge.SF_FileSystem._ConvertToUrl(vWindowName)) _
+ Or (Len(.WindowName) &gt; 0 And .WindowName = vWindowName) _
+ Or (Len(.WindowTitle) &gt; 0 And .WindowTitle = vWindowName) Then
+ bFound = True
+ Exit Do
+ End If
+ End With
+ Loop
+ Else
+ bFound = True
+ vWindow = oUi._IdentifyWindow(StarDesktop.CurrentComponent)
+ End If
+ Case ScriptForge.V_OBJECT &apos; com.sun.star.lang.XComponent
+ bFound = True
+ vWindow = oUi._IdentifyWindow(vWindowName)
+ End Select
+
+ If bFound And Not IsNull(vWindow.Frame) And Len(vWindow.DocumentType) &gt; 0 Then
+ &apos; Create the right subclass and associate to it a new instance of the superclass
+ Select Case vWindow.DocumentType
+ Case &quot;Base&quot;
+ Set oDocument = New SF_Base
+ Set oSuperDocument = New SF_Document
+ Set oDocument.[_Super] = oSuperDocument &apos; Now both super and subclass are twinned
+ Case &quot;Calc&quot;
+ Set oDocument = New SF_Calc
+ Set oSuperDocument = New SF_Document
+ Set oDocument.[_Super] = oSuperDocument &apos; Now both super and subclass are twinned
+ Case Else &apos; Only superclass
+ Set oDocument = New SF_Document
+ Set oSuperDocument = oDocument
+ End Select
+ With oDocument &apos; Initialize attributes of subclass
+ Set .[Me] = oDocument
+ Set ._Component = vWindow.Component
+ &apos; Initialize specific attributes
+ Select Case vWindow.DocumentType
+ Case &quot;Base&quot;
+ Set ._DataSource = ._Component.DataSource
+ Case Else
+ End Select
+ End With
+ With oSuperDocument &apos; Initialize attributes of superclass
+ Set .[Me] = oSuperDocument
+ Set ._Component = vWindow.Component
+ Set ._Frame = vWindow.Frame
+ ._WindowName = vWindow.WindowName
+ ._WindowTitle = vWindow.WindowTitle
+ ._WindowFileName = vWindow.WindowFileName
+ ._DocumentType = vWindow.DocumentType
+ End With
+ End If
+
+Finally:
+ Set _NewDocument = oDocument
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; SFDocuments.SF_Register._NewDocument
+
+REM ============================================== END OF SFDOCUMENTS.SF_REGISTER
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdocuments/__License.xba b/wizards/source/sfdocuments/__License.xba
new file mode 100644
index 000000000000..eddcd8214951
--- /dev/null
+++ b/wizards/source/sfdocuments/__License.xba
@@ -0,0 +1,26 @@
+<?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="__License" script:language="StarBasic" script:moduleType="normal">
+&apos;&apos;&apos; Copyright 2019-2020 Jean-Pierre LEDURE, Jean-François NIFENECKER, Alain ROMEDENNE
+
+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 =======================================================================================================================
+
+&apos;&apos;&apos; ScriptForge is distributed in the hope that it will be useful,
+&apos;&apos;&apos; but WITHOUT ANY WARRANTY; without even the implied warranty of
+&apos;&apos;&apos; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+&apos;&apos;&apos; ScriptForge is free software; you can redistribute it and/or modify it under the terms of either (at your option):
+
+&apos;&apos;&apos; 1) The Mozilla Public License, v. 2.0. If a copy of the MPL was not
+&apos;&apos;&apos; distributed with this file, you can obtain one at http://mozilla.org/MPL/2.0/ .
+
+&apos;&apos;&apos; 2) The GNU Lesser General Public License as published by
+&apos;&apos;&apos; the Free Software Foundation, either version 3 of the License, or
+&apos;&apos;&apos; (at your option) any later version. If a copy of the LGPL was not
+&apos;&apos;&apos; distributed with this file, see http://www.gnu.org/licenses/ .
+
+</script:module> \ No newline at end of file
diff --git a/wizards/source/sfdocuments/dialog.xlb b/wizards/source/sfdocuments/dialog.xlb
new file mode 100644
index 000000000000..62e84ea5c08d
--- /dev/null
+++ b/wizards/source/sfdocuments/dialog.xlb
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
+<library:library xmlns:library="http://openoffice.org/2000/library" library:name="SFDocuments" library:readonly="false" library:passwordprotected="false"/> \ No newline at end of file
diff --git a/wizards/source/sfdocuments/script.xlb b/wizards/source/sfdocuments/script.xlb
new file mode 100644
index 000000000000..82a939306752
--- /dev/null
+++ b/wizards/source/sfdocuments/script.xlb
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE library:library PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "library.dtd">
+<library:library xmlns:library="http://openoffice.org/2000/library" library:name="SFDocuments" library:readonly="false" library:passwordprotected="false">
+ <library:element library:name="__License"/>
+ <library:element library:name="SF_Document"/>
+ <library:element library:name="SF_Calc"/>
+ <library:element library:name="SF_Register"/>
+ <library:element library:name="SF_Base"/>
+</library:library> \ No newline at end of file